mainsequence 6.0.45__tar.gz → 6.0.46__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mainsequence-6.0.45/mainsequence.egg-info → mainsequence-6.0.46}/PKG-INFO +1 -1
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md +48 -5
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/api.py +4 -4
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/cli.py +12 -9
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/agent_runtime_models.py +255 -8
- {mainsequence-6.0.45 → mainsequence-6.0.46/mainsequence.egg-info}/PKG-INFO +1 -1
- {mainsequence-6.0.45 → mainsequence-6.0.46}/pyproject.toml +1 -1
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_cli.py +1 -1
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_filter_normalization.py +181 -3
- {mainsequence-6.0.45 → mainsequence-6.0.46}/LICENSE +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/README.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/maintenance/project-maintenance/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/sdk_project_execution/SKILL.md +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/__main__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/bootstrap.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/config.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/migrations.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/cli/ui.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/base.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/client.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/metatables/core.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/models_user.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/client/utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/defaults.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/logconf.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/alembic.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/env.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/provider.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/registry.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/project_context.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/project_skills.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence/scaffold_skills.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/setup.cfg +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_auth_precedence.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_canonical_api_route_contract.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_cli_migrations.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_client.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_dependency_extras.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_environment_resource_context.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_environment_response_contracts.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_instrumentation.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_local_ops.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_logconf.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_meta_table_migrations.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_meta_tables_client_models.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_notification_uid_contract.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_project_branch_contract.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_project_runtime_context.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_project_skills.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_run_configuration.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_scaffold_skills.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_scheduler_client_model.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_schema_names.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_secret_client_model.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_ssh_utils.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_update_statistics.py +0 -0
- {mainsequence-6.0.45 → mainsequence-6.0.46}/tests/test_update_uid_guards.py +0 -0
{mainsequence-6.0.45 → mainsequence-6.0.46}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md
RENAMED
|
@@ -30,6 +30,9 @@ internally and sends a standard A2A message.
|
|
|
30
30
|
- Do not expose runtime credentials in prompts, logs, or user-facing answers.
|
|
31
31
|
- Do not use commands that require both target agent UID and target session UID for chat.
|
|
32
32
|
- Use `--strict-dictionary` when the target answer must be machine-parseable JSON.
|
|
33
|
+
- Read `a2a_profile` from discovery, default to `message`, and never infer Task
|
|
34
|
+
support.
|
|
35
|
+
- Use `--response-kind task` only when the selected Agent advertises `task`.
|
|
33
36
|
- Do not send or request reasoning/thinking traces; standard A2A responses expose only message parts.
|
|
34
37
|
|
|
35
38
|
## Discovery Flow
|
|
@@ -53,6 +56,7 @@ Agent's environment.
|
|
|
53
56
|
5. Prefer the highest `combined_score` when present.
|
|
54
57
|
6. If the user asked only which agents are available, summarize the candidates and stop.
|
|
55
58
|
Include agent name, agent UID, and a short capability summary.
|
|
59
|
+
7. Preserve the selected Agent's `a2a_profile` for request validation.
|
|
56
60
|
|
|
57
61
|
## Target Session
|
|
58
62
|
|
|
@@ -106,6 +110,15 @@ mainsequence agent session a2a send \
|
|
|
106
110
|
--message "Summarize the current portfolio drift."
|
|
107
111
|
```
|
|
108
112
|
|
|
113
|
+
For advertised asynchronous work, explicitly request a Task:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
mainsequence agent session a2a send \
|
|
117
|
+
<target_agent_session_uid> \
|
|
118
|
+
--message "Run the full analysis asynchronously." \
|
|
119
|
+
--response-kind task
|
|
120
|
+
```
|
|
121
|
+
|
|
109
122
|
For a second message to the same target session, send another chat command
|
|
110
123
|
with the same target `AgentSession` UID:
|
|
111
124
|
|
|
@@ -189,7 +202,11 @@ handle_unique_id -> AgentSession.uid -> A2A message.contextId
|
|
|
189
202
|
Direct SDK flow:
|
|
190
203
|
|
|
191
204
|
```python
|
|
192
|
-
from mainsequence.client.agent_runtime_models import
|
|
205
|
+
from mainsequence.client.agent_runtime_models import (
|
|
206
|
+
A2AResponseKind,
|
|
207
|
+
Agent,
|
|
208
|
+
AgentSession,
|
|
209
|
+
)
|
|
193
210
|
|
|
194
211
|
|
|
195
212
|
agent = Agent.get_by_uid(target_agent_uid)
|
|
@@ -202,7 +219,24 @@ response = AgentSession.send_a2a_message(
|
|
|
202
219
|
session.uid,
|
|
203
220
|
message="Return a JSON object with keys: summary, risk_level, next_action.",
|
|
204
221
|
strict_dictionary=True,
|
|
222
|
+
response_kind=A2AResponseKind.MESSAGE,
|
|
223
|
+
a2a_profile=agent.a2a_profile,
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Use asynchronous Task mode only when discovery advertises it:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
if A2AResponseKind.TASK not in agent.a2a_profile.supported_response_kinds:
|
|
231
|
+
raise ValueError("The selected agent does not advertise A2A Task responses")
|
|
232
|
+
|
|
233
|
+
result = AgentSession.send_a2a_message(
|
|
234
|
+
session,
|
|
235
|
+
message="Run the full analysis asynchronously.",
|
|
236
|
+
response_kind=A2AResponseKind.TASK,
|
|
237
|
+
a2a_profile=agent.a2a_profile,
|
|
205
238
|
)
|
|
239
|
+
task = AgentSession.wait_for_a2a_task(session, task_id=result.task.id)
|
|
206
240
|
```
|
|
207
241
|
|
|
208
242
|
For another message in the same conversation, reuse the same `session.uid`:
|
|
@@ -267,12 +301,19 @@ handle for a different task or conversation.
|
|
|
267
301
|
## Response Handling
|
|
268
302
|
|
|
269
303
|
- Parse the CLI output as the standard A2A JSON response.
|
|
270
|
-
-
|
|
304
|
+
- The default `message` result is direct execution and does not create an A2A
|
|
305
|
+
Task. Consume only its documented `message.parts`.
|
|
306
|
+
- A `task` result is valid only after explicitly selecting `--response-kind
|
|
307
|
+
task` for an Agent whose discovery profile advertises it. Preserve its ID and
|
|
308
|
+
follow it with the SDK task get/wait/cancel helpers.
|
|
309
|
+
- Treat a result kind different from the requested kind as a protocol error.
|
|
271
310
|
- Do not depend on reasoning, tool traces, runtime paths, or transport metadata.
|
|
272
311
|
- If a send times out or disconnects and must be retried, reuse the same
|
|
273
|
-
`--message-id` value
|
|
312
|
+
`--message-id` value to preserve request identity. Direct `message` sends do
|
|
313
|
+
not have durable replay protection, so do not retry automatically: the first
|
|
314
|
+
turn may already have executed. Use `task` when durable recovery is required.
|
|
274
315
|
- If the CLI generated the message id and the send failed, reuse the
|
|
275
|
-
`A2A message id for
|
|
316
|
+
`A2A message id for request retry` value printed with the error.
|
|
276
317
|
|
|
277
318
|
## Deterministic Execution Path
|
|
278
319
|
|
|
@@ -282,7 +323,9 @@ handle for a different task or conversation.
|
|
|
282
323
|
4. Create or resolve the target session with `mainsequence agent session get_or_create`.
|
|
283
324
|
5. Use the returned session `uid`.
|
|
284
325
|
6. Run `mainsequence agent session a2a send <target_agent_session_uid> ...`.
|
|
285
|
-
7.
|
|
326
|
+
7. Inspect the selected Agent's `a2a_profile` and default to `message`.
|
|
327
|
+
8. Parse `message.parts`, or follow the returned Task only when Task mode was
|
|
328
|
+
explicitly selected and advertised.
|
|
286
329
|
|
|
287
330
|
## Role-Specific Behavior
|
|
288
331
|
|
|
@@ -1417,7 +1417,7 @@ def send_agent_session_a2a_message(
|
|
|
1417
1417
|
message_id: str | None = None,
|
|
1418
1418
|
strict_dictionary: bool = False,
|
|
1419
1419
|
json_repair_attempts: int = 3,
|
|
1420
|
-
|
|
1420
|
+
response_kind: str = "message",
|
|
1421
1421
|
timeout: int | None = None,
|
|
1422
1422
|
) -> dict[str, Any]:
|
|
1423
1423
|
"""
|
|
@@ -1437,7 +1437,7 @@ def send_agent_session_a2a_message(
|
|
|
1437
1437
|
cached_runtime_access=cached_runtime_access,
|
|
1438
1438
|
strict_dictionary=strict_dictionary,
|
|
1439
1439
|
json_repair_attempts=json_repair_attempts,
|
|
1440
|
-
|
|
1440
|
+
response_kind=response_kind,
|
|
1441
1441
|
timeout=timeout,
|
|
1442
1442
|
),
|
|
1443
1443
|
)
|
|
@@ -1463,7 +1463,7 @@ def _send_agent_session_a2a_message_with_cache(
|
|
|
1463
1463
|
cached_runtime_access: dict[str, Any] | None,
|
|
1464
1464
|
strict_dictionary: bool,
|
|
1465
1465
|
json_repair_attempts: int,
|
|
1466
|
-
|
|
1466
|
+
response_kind: str,
|
|
1467
1467
|
timeout: int | None,
|
|
1468
1468
|
):
|
|
1469
1469
|
if cached_runtime_access is not None:
|
|
@@ -1476,7 +1476,7 @@ def _send_agent_session_a2a_message_with_cache(
|
|
|
1476
1476
|
message_id=message_id,
|
|
1477
1477
|
strict_dictionary=strict_dictionary,
|
|
1478
1478
|
json_repair_attempts=json_repair_attempts,
|
|
1479
|
-
|
|
1479
|
+
response_kind=response_kind,
|
|
1480
1480
|
timeout=timeout,
|
|
1481
1481
|
)
|
|
1482
1482
|
|
|
@@ -3788,7 +3788,7 @@ def _agent_session_a2a_send_impl(
|
|
|
3788
3788
|
strict_dictionary: bool,
|
|
3789
3789
|
json_repair_attempts: int,
|
|
3790
3790
|
message_id: str | None,
|
|
3791
|
-
|
|
3791
|
+
response_kind: str,
|
|
3792
3792
|
timeout: int | None,
|
|
3793
3793
|
) -> None:
|
|
3794
3794
|
try:
|
|
@@ -3806,6 +3806,9 @@ def _agent_session_a2a_send_impl(
|
|
|
3806
3806
|
if json_repair_attempts < 1:
|
|
3807
3807
|
error("--json-repair-attempts must be greater than 0.")
|
|
3808
3808
|
raise typer.Exit(1)
|
|
3809
|
+
if response_kind not in {"message", "task"}:
|
|
3810
|
+
error("--response-kind must be 'message' or 'task'.")
|
|
3811
|
+
raise typer.Exit(1)
|
|
3809
3812
|
attachment_paths = list(files or [])
|
|
3810
3813
|
attachment_media_types = list(media_types or [])
|
|
3811
3814
|
if attachment_media_types and len(attachment_media_types) != len(attachment_paths):
|
|
@@ -3841,12 +3844,12 @@ def _agent_session_a2a_send_impl(
|
|
|
3841
3844
|
message_id=effective_message_id,
|
|
3842
3845
|
strict_dictionary=strict_dictionary,
|
|
3843
3846
|
json_repair_attempts=json_repair_attempts,
|
|
3844
|
-
|
|
3847
|
+
response_kind=response_kind,
|
|
3845
3848
|
timeout=timeout,
|
|
3846
3849
|
)
|
|
3847
3850
|
except ApiError as e:
|
|
3848
3851
|
error(str(e))
|
|
3849
|
-
error(f"A2A message id for
|
|
3852
|
+
error(f"A2A message id for request retry: {effective_message_id}")
|
|
3850
3853
|
raise typer.Exit(1) from e
|
|
3851
3854
|
|
|
3852
3855
|
typer.echo(json.dumps(response_payload, indent=2))
|
|
@@ -4991,12 +4994,12 @@ def agent_session_a2a_send_cmd(
|
|
|
4991
4994
|
message_id: str | None = typer.Option(
|
|
4992
4995
|
None,
|
|
4993
4996
|
"--message-id",
|
|
4994
|
-
help="Stable A2A message.messageId to
|
|
4997
|
+
help="Stable A2A message.messageId to preserve request identity across a retry.",
|
|
4995
4998
|
),
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
"--
|
|
4999
|
-
help="
|
|
4999
|
+
response_kind: str = typer.Option(
|
|
5000
|
+
"message",
|
|
5001
|
+
"--response-kind",
|
|
5002
|
+
help="Select the A2A result contract: message or task.",
|
|
5000
5003
|
),
|
|
5001
5004
|
timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
|
|
5002
5005
|
):
|
|
@@ -5015,7 +5018,7 @@ def agent_session_a2a_send_cmd(
|
|
|
5015
5018
|
strict_dictionary=strict_dictionary,
|
|
5016
5019
|
json_repair_attempts=json_repair_attempts,
|
|
5017
5020
|
message_id=message_id,
|
|
5018
|
-
|
|
5021
|
+
response_kind=response_kind,
|
|
5019
5022
|
timeout=timeout,
|
|
5020
5023
|
)
|
|
5021
5024
|
|
|
@@ -20,7 +20,11 @@ DEFAULT_AGENT_SESSION_LONG_REQUEST_TIMEOUT = (5.0, 900.0)
|
|
|
20
20
|
DEFAULT_AGENT_RUNTIME_ACCESS_CACHE_TTL_SECONDS = 60.0
|
|
21
21
|
DEFAULT_AGENT_RUNTIME_ACCESS_CACHE_EXPIRY_SKEW_SECONDS = 30.0
|
|
22
22
|
STANDARD_A2A_MESSAGE_SEND_PATH = "/api/a2a/v1/message:send"
|
|
23
|
+
STANDARD_A2A_TASKS_PATH = "/api/a2a/v1/tasks"
|
|
23
24
|
STANDARD_A2A_CONTENT_TYPE = "application/a2a+json"
|
|
25
|
+
STANDARD_A2A_RESPONSE_KIND_EXTENSION_URI = (
|
|
26
|
+
"https://mainsequence.ai/a2a/extensions/response-kind/v1"
|
|
27
|
+
)
|
|
24
28
|
STANDARD_A2A_OUTPUT_CONTRACT_METADATA_KEY = (
|
|
25
29
|
"https://mainsequence.ai/a2a/extensions/output-contract/v1"
|
|
26
30
|
)
|
|
@@ -35,6 +39,67 @@ class AgentSessionStatus(str, Enum):
|
|
|
35
39
|
CANCELED = "canceled"
|
|
36
40
|
|
|
37
41
|
|
|
42
|
+
class A2AResponseKind(str, Enum):
|
|
43
|
+
MESSAGE = "message"
|
|
44
|
+
TASK = "task"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class AgentA2AProfile(BasePydanticModel):
|
|
48
|
+
response_kind_extension_uri: str = STANDARD_A2A_RESPONSE_KIND_EXTENSION_URI
|
|
49
|
+
supported_response_kinds: list[A2AResponseKind] = Field(
|
|
50
|
+
default_factory=lambda: [A2AResponseKind.MESSAGE]
|
|
51
|
+
)
|
|
52
|
+
default_response_kind: A2AResponseKind = A2AResponseKind.MESSAGE
|
|
53
|
+
|
|
54
|
+
@model_validator(mode="after")
|
|
55
|
+
def _validate_default(self) -> AgentA2AProfile:
|
|
56
|
+
if self.response_kind_extension_uri != STANDARD_A2A_RESPONSE_KIND_EXTENSION_URI:
|
|
57
|
+
raise ValueError("response_kind_extension_uri is not supported")
|
|
58
|
+
self.supported_response_kinds = list(dict.fromkeys(self.supported_response_kinds))
|
|
59
|
+
if not self.supported_response_kinds:
|
|
60
|
+
raise ValueError("supported_response_kinds must not be empty")
|
|
61
|
+
if A2AResponseKind.MESSAGE not in self.supported_response_kinds:
|
|
62
|
+
raise ValueError("supported_response_kinds must include 'message'")
|
|
63
|
+
if self.default_response_kind is not A2AResponseKind.MESSAGE:
|
|
64
|
+
raise ValueError("default_response_kind must be 'message'")
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class A2ATaskStatus(BasePydanticModel):
|
|
69
|
+
model_config = ConfigDict(extra="allow")
|
|
70
|
+
|
|
71
|
+
state: str
|
|
72
|
+
timestamp: str | None = None
|
|
73
|
+
message: Any | None = None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class A2ATask(BasePydanticModel):
|
|
77
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True, serialize_by_alias=True)
|
|
78
|
+
|
|
79
|
+
kind: Literal["task"] = "task"
|
|
80
|
+
id: str
|
|
81
|
+
context_id: str = Field(alias="contextId")
|
|
82
|
+
status: A2ATaskStatus
|
|
83
|
+
artifacts: list[dict[str, Any]] = Field(default_factory=list)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class A2AMessageSendResult(BasePydanticModel):
|
|
87
|
+
model_config = ConfigDict(serialize_by_alias=True)
|
|
88
|
+
|
|
89
|
+
message: dict[str, Any] | None = None
|
|
90
|
+
task: A2ATask | None = None
|
|
91
|
+
|
|
92
|
+
@model_validator(mode="after")
|
|
93
|
+
def _require_exact_result(self) -> A2AMessageSendResult:
|
|
94
|
+
if (self.message is None) == (self.task is None):
|
|
95
|
+
raise ValueError("A2A message-send result must contain exactly one of message or task")
|
|
96
|
+
return self
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def response_kind(self) -> A2AResponseKind:
|
|
100
|
+
return A2AResponseKind.TASK if self.task is not None else A2AResponseKind.MESSAGE
|
|
101
|
+
|
|
102
|
+
|
|
38
103
|
class AgentHarnessKind(str, Enum):
|
|
39
104
|
PI = "pi"
|
|
40
105
|
TAU = "tau"
|
|
@@ -56,6 +121,7 @@ class AgentSemanticSearchResult(BasePydanticModel):
|
|
|
56
121
|
"",
|
|
57
122
|
description="Short description returned by semantic search for the matched agent.",
|
|
58
123
|
)
|
|
124
|
+
a2a_profile: AgentA2AProfile = Field(default_factory=AgentA2AProfile)
|
|
59
125
|
project_branch_uid: str = Field(
|
|
60
126
|
...,
|
|
61
127
|
description="Public UID of the ProjectBranch that owns the matched Project Coding Agent.",
|
|
@@ -278,6 +344,7 @@ class Agent(ShareableObjectMixin, BaseObjectOrm, BasePydanticModel):
|
|
|
278
344
|
None,
|
|
279
345
|
description="Optional structured agent card payload.",
|
|
280
346
|
)
|
|
347
|
+
a2a_profile: AgentA2AProfile = Field(default_factory=AgentA2AProfile)
|
|
281
348
|
|
|
282
349
|
llm_thinking: str
|
|
283
350
|
llm_provider: str = Field(
|
|
@@ -958,7 +1025,7 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
958
1025
|
message_id: str | None = None,
|
|
959
1026
|
strict_dictionary: bool = False,
|
|
960
1027
|
json_repair_attempts: int = 3,
|
|
961
|
-
|
|
1028
|
+
response_kind: A2AResponseKind = A2AResponseKind.MESSAGE,
|
|
962
1029
|
) -> dict[str, Any]:
|
|
963
1030
|
normalized_message = str(message)
|
|
964
1031
|
if not normalized_message.strip():
|
|
@@ -970,6 +1037,10 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
970
1037
|
normalized_message_id = f"msg-{uuid.uuid4()}"
|
|
971
1038
|
|
|
972
1039
|
accepted_output_modes = ["application/json"] if strict_dictionary else ["text/plain"]
|
|
1040
|
+
try:
|
|
1041
|
+
normalized_response_kind = A2AResponseKind(response_kind)
|
|
1042
|
+
except ValueError as exc:
|
|
1043
|
+
raise ValueError("response_kind must be 'message' or 'task'") from exc
|
|
973
1044
|
parts: list[dict[str, Any]] = [{"text": normalized_message}]
|
|
974
1045
|
for file_spec in files or []:
|
|
975
1046
|
parts.append(AgentSession._build_standard_a2a_raw_file_part(file_spec))
|
|
@@ -983,7 +1054,7 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
983
1054
|
},
|
|
984
1055
|
"configuration": {
|
|
985
1056
|
"acceptedOutputModes": accepted_output_modes,
|
|
986
|
-
"
|
|
1057
|
+
"responseKind": normalized_response_kind.value,
|
|
987
1058
|
},
|
|
988
1059
|
}
|
|
989
1060
|
if strict_dictionary:
|
|
@@ -1060,6 +1131,7 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1060
1131
|
"Authorization": f"Bearer {access.token.strip()}",
|
|
1061
1132
|
"Content-Type": STANDARD_A2A_CONTENT_TYPE,
|
|
1062
1133
|
"Accept": STANDARD_A2A_CONTENT_TYPE,
|
|
1134
|
+
"A2A-Extensions": STANDARD_A2A_RESPONSE_KIND_EXTENSION_URI,
|
|
1063
1135
|
}
|
|
1064
1136
|
return requests.post(
|
|
1065
1137
|
url,
|
|
@@ -1069,8 +1141,10 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1069
1141
|
)
|
|
1070
1142
|
|
|
1071
1143
|
@staticmethod
|
|
1072
|
-
def extract_a2a_message_text(
|
|
1073
|
-
|
|
1144
|
+
def extract_a2a_message_text(
|
|
1145
|
+
payload: dict[str, Any] | A2AMessageSendResult,
|
|
1146
|
+
) -> str:
|
|
1147
|
+
message = payload.message if isinstance(payload, A2AMessageSendResult) else payload.get("message")
|
|
1074
1148
|
if not isinstance(message, dict):
|
|
1075
1149
|
return ""
|
|
1076
1150
|
parts = message.get("parts")
|
|
@@ -1092,13 +1166,38 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1092
1166
|
message_id: str | None = None,
|
|
1093
1167
|
strict_dictionary: bool = False,
|
|
1094
1168
|
json_repair_attempts: int = 3,
|
|
1095
|
-
|
|
1169
|
+
response_kind: A2AResponseKind = A2AResponseKind.MESSAGE,
|
|
1170
|
+
a2a_profile: AgentA2AProfile | dict[str, Any] | None = None,
|
|
1096
1171
|
timeout=None,
|
|
1097
|
-
) ->
|
|
1172
|
+
) -> A2AMessageSendResult:
|
|
1098
1173
|
"""
|
|
1099
1174
|
Send one standard A2A message to the runtime for this agent session.
|
|
1100
1175
|
"""
|
|
1101
1176
|
session_uid = cls._resolve_agent_session_uid(agent_session)
|
|
1177
|
+
normalized_response_kind = A2AResponseKind(response_kind)
|
|
1178
|
+
resolved_profile: AgentA2AProfile | None = None
|
|
1179
|
+
if a2a_profile is not None:
|
|
1180
|
+
resolved_profile = (
|
|
1181
|
+
a2a_profile
|
|
1182
|
+
if isinstance(a2a_profile, AgentA2AProfile)
|
|
1183
|
+
else AgentA2AProfile.model_validate(a2a_profile)
|
|
1184
|
+
)
|
|
1185
|
+
elif normalized_response_kind is A2AResponseKind.TASK:
|
|
1186
|
+
session = (
|
|
1187
|
+
agent_session
|
|
1188
|
+
if isinstance(agent_session, AgentSession)
|
|
1189
|
+
else cls.get(pk=session_uid, timeout=timeout)
|
|
1190
|
+
)
|
|
1191
|
+
if not session.agent_uid:
|
|
1192
|
+
raise ValueError("Task response_kind requires a session with an agent_uid")
|
|
1193
|
+
resolved_profile = Agent.get(pk=session.agent_uid, timeout=timeout).a2a_profile
|
|
1194
|
+
if (
|
|
1195
|
+
resolved_profile is not None
|
|
1196
|
+
and normalized_response_kind not in resolved_profile.supported_response_kinds
|
|
1197
|
+
):
|
|
1198
|
+
raise ValueError(
|
|
1199
|
+
f"response_kind {normalized_response_kind.value!r} is not advertised by the agent"
|
|
1200
|
+
)
|
|
1102
1201
|
body = cls._build_standard_a2a_message_send_body(
|
|
1103
1202
|
agent_session_uid=session_uid,
|
|
1104
1203
|
message=message,
|
|
@@ -1106,7 +1205,7 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1106
1205
|
message_id=message_id,
|
|
1107
1206
|
strict_dictionary=strict_dictionary,
|
|
1108
1207
|
json_repair_attempts=json_repair_attempts,
|
|
1109
|
-
|
|
1208
|
+
response_kind=normalized_response_kind,
|
|
1110
1209
|
)
|
|
1111
1210
|
access = cls._resolve_runtime_access_for_message_send(session_uid, timeout=timeout)
|
|
1112
1211
|
response = cls._post_standard_a2a_message(
|
|
@@ -1140,7 +1239,150 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1140
1239
|
) from exc
|
|
1141
1240
|
if not isinstance(payload, dict):
|
|
1142
1241
|
raise TypeError("Standard A2A response must be a JSON object")
|
|
1143
|
-
|
|
1242
|
+
try:
|
|
1243
|
+
result = A2AMessageSendResult.model_validate(payload)
|
|
1244
|
+
except ValueError as exc:
|
|
1245
|
+
raise ApiError(
|
|
1246
|
+
"Standard A2A response must contain exactly one valid message or task result.",
|
|
1247
|
+
response=response,
|
|
1248
|
+
payload=body,
|
|
1249
|
+
) from exc
|
|
1250
|
+
if result.response_kind is not normalized_response_kind:
|
|
1251
|
+
raise ApiError(
|
|
1252
|
+
"Standard A2A response kind does not match the requested response_kind.",
|
|
1253
|
+
response=response,
|
|
1254
|
+
payload=body,
|
|
1255
|
+
)
|
|
1256
|
+
return result
|
|
1257
|
+
|
|
1258
|
+
@classmethod
|
|
1259
|
+
def _request_a2a_task(
|
|
1260
|
+
cls,
|
|
1261
|
+
agent_session: str | AgentSession,
|
|
1262
|
+
*,
|
|
1263
|
+
task_id: str,
|
|
1264
|
+
cancel: bool,
|
|
1265
|
+
timeout=None,
|
|
1266
|
+
) -> A2ATask:
|
|
1267
|
+
session_uid = cls._resolve_agent_session_uid(agent_session)
|
|
1268
|
+
normalized_task_id = str(task_id or "").strip()
|
|
1269
|
+
if not normalized_task_id or "/" in normalized_task_id:
|
|
1270
|
+
raise ValueError("task_id must be a non-empty A2A task identifier")
|
|
1271
|
+
|
|
1272
|
+
def request(access: AgentSessionRuntimeAccess) -> requests.Response:
|
|
1273
|
+
if access.mode != "token":
|
|
1274
|
+
raise ApiError("Coding-agent runtime access is unavailable.")
|
|
1275
|
+
if not isinstance(access.token, str) or not access.token.strip():
|
|
1276
|
+
raise ApiError("Runtime access response is missing token.")
|
|
1277
|
+
path = f"{STANDARD_A2A_TASKS_PATH}/{normalized_task_id}"
|
|
1278
|
+
method = "GET"
|
|
1279
|
+
if cancel:
|
|
1280
|
+
path = f"{path}:cancel"
|
|
1281
|
+
method = "POST"
|
|
1282
|
+
request_timeout = (
|
|
1283
|
+
DEFAULT_AGENT_SESSION_LONG_REQUEST_TIMEOUT if timeout is None else timeout
|
|
1284
|
+
)
|
|
1285
|
+
return requests.request(
|
|
1286
|
+
method,
|
|
1287
|
+
_join_runtime_url(access.rpc_url, path),
|
|
1288
|
+
headers={
|
|
1289
|
+
"Authorization": f"Bearer {access.token.strip()}",
|
|
1290
|
+
"Accept": STANDARD_A2A_CONTENT_TYPE,
|
|
1291
|
+
},
|
|
1292
|
+
timeout=request_timeout,
|
|
1293
|
+
)
|
|
1294
|
+
|
|
1295
|
+
access = cls._resolve_runtime_access_for_message_send(session_uid, timeout=timeout)
|
|
1296
|
+
response = request(access)
|
|
1297
|
+
if response.status_code in (401, 403):
|
|
1298
|
+
cls.clear_cached_runtime_access(session_uid)
|
|
1299
|
+
access = cls.resolve_runtime_access(session_uid, cache=True, timeout=timeout)
|
|
1300
|
+
response = request(access)
|
|
1301
|
+
if response.status_code in (401, 403):
|
|
1302
|
+
cls.clear_cached_runtime_access(session_uid)
|
|
1303
|
+
if not (200 <= response.status_code < 300):
|
|
1304
|
+
raise_for_response(response)
|
|
1305
|
+
try:
|
|
1306
|
+
payload = response.json()
|
|
1307
|
+
except Exception as exc:
|
|
1308
|
+
raise ApiError(
|
|
1309
|
+
"Standard A2A task response must be a JSON object.",
|
|
1310
|
+
response=response,
|
|
1311
|
+
) from exc
|
|
1312
|
+
task_payload = payload.get("task") if isinstance(payload, dict) else None
|
|
1313
|
+
if not isinstance(task_payload, dict):
|
|
1314
|
+
raise ApiError(
|
|
1315
|
+
"Standard A2A task response must contain a task object.",
|
|
1316
|
+
response=response,
|
|
1317
|
+
)
|
|
1318
|
+
return A2ATask.model_validate(task_payload)
|
|
1319
|
+
|
|
1320
|
+
@classmethod
|
|
1321
|
+
def get_a2a_task(
|
|
1322
|
+
cls,
|
|
1323
|
+
agent_session: str | AgentSession,
|
|
1324
|
+
*,
|
|
1325
|
+
task_id: str,
|
|
1326
|
+
timeout=None,
|
|
1327
|
+
) -> A2ATask:
|
|
1328
|
+
return cls._request_a2a_task(
|
|
1329
|
+
agent_session,
|
|
1330
|
+
task_id=task_id,
|
|
1331
|
+
cancel=False,
|
|
1332
|
+
timeout=timeout,
|
|
1333
|
+
)
|
|
1334
|
+
|
|
1335
|
+
@classmethod
|
|
1336
|
+
def cancel_a2a_task(
|
|
1337
|
+
cls,
|
|
1338
|
+
agent_session: str | AgentSession,
|
|
1339
|
+
*,
|
|
1340
|
+
task_id: str,
|
|
1341
|
+
timeout=None,
|
|
1342
|
+
) -> A2ATask:
|
|
1343
|
+
return cls._request_a2a_task(
|
|
1344
|
+
agent_session,
|
|
1345
|
+
task_id=task_id,
|
|
1346
|
+
cancel=True,
|
|
1347
|
+
timeout=timeout,
|
|
1348
|
+
)
|
|
1349
|
+
|
|
1350
|
+
@classmethod
|
|
1351
|
+
def wait_for_a2a_task(
|
|
1352
|
+
cls,
|
|
1353
|
+
agent_session: str | AgentSession,
|
|
1354
|
+
*,
|
|
1355
|
+
task_id: str,
|
|
1356
|
+
poll_interval_seconds: float = 1.0,
|
|
1357
|
+
wait_timeout_seconds: float = 900.0,
|
|
1358
|
+
timeout=None,
|
|
1359
|
+
) -> A2ATask:
|
|
1360
|
+
if poll_interval_seconds <= 0:
|
|
1361
|
+
raise ValueError("poll_interval_seconds must be greater than 0")
|
|
1362
|
+
if wait_timeout_seconds <= 0:
|
|
1363
|
+
raise ValueError("wait_timeout_seconds must be greater than 0")
|
|
1364
|
+
deadline = time.monotonic() + wait_timeout_seconds
|
|
1365
|
+
terminal_states = {
|
|
1366
|
+
"completed",
|
|
1367
|
+
"failed",
|
|
1368
|
+
"canceled",
|
|
1369
|
+
"rejected",
|
|
1370
|
+
"TASK_STATE_COMPLETED",
|
|
1371
|
+
"TASK_STATE_FAILED",
|
|
1372
|
+
"TASK_STATE_CANCELED",
|
|
1373
|
+
"TASK_STATE_REJECTED",
|
|
1374
|
+
}
|
|
1375
|
+
while True:
|
|
1376
|
+
task = cls.get_a2a_task(
|
|
1377
|
+
agent_session,
|
|
1378
|
+
task_id=task_id,
|
|
1379
|
+
timeout=timeout,
|
|
1380
|
+
)
|
|
1381
|
+
if task.status.state in terminal_states:
|
|
1382
|
+
return task
|
|
1383
|
+
if time.monotonic() >= deadline:
|
|
1384
|
+
raise TimeoutError(f"Timed out waiting for A2A task {task_id}")
|
|
1385
|
+
time.sleep(poll_interval_seconds)
|
|
1144
1386
|
|
|
1145
1387
|
@classmethod
|
|
1146
1388
|
def resolve_runtime_access(
|
|
@@ -1415,7 +1657,12 @@ class AgentSession(BaseObjectOrm, BasePydanticModel):
|
|
|
1415
1657
|
|
|
1416
1658
|
|
|
1417
1659
|
__all__ = [
|
|
1660
|
+
"A2AMessageSendResult",
|
|
1661
|
+
"A2AResponseKind",
|
|
1662
|
+
"A2ATask",
|
|
1663
|
+
"A2ATaskStatus",
|
|
1418
1664
|
"Agent",
|
|
1665
|
+
"AgentA2AProfile",
|
|
1419
1666
|
"AgentRuntimeImageDrift",
|
|
1420
1667
|
"AgentRuntimeImageDriftCheck",
|
|
1421
1668
|
"AgentHarnessKind",
|
|
@@ -6867,7 +6867,7 @@ def test_agent_session_a2a_send_always_returns_json(cli_mod, runner, monkeypatch
|
|
|
6867
6867
|
assert captured["kwargs"]["message_id"] == "msg-client-1"
|
|
6868
6868
|
assert captured["kwargs"]["strict_dictionary"] is True
|
|
6869
6869
|
assert captured["kwargs"]["json_repair_attempts"] == 3
|
|
6870
|
-
assert captured["kwargs"]["
|
|
6870
|
+
assert captured["kwargs"]["response_kind"] == "message"
|
|
6871
6871
|
assert "omit_reasoning" not in captured["kwargs"]
|
|
6872
6872
|
|
|
6873
6873
|
|