capability-runtime 0.1.3.post1__tar.gz → 0.1.5__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.
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/PKG-INFO +82 -7
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/README.md +80 -5
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/pyproject.toml +2 -2
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/__init__.py +36 -4
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/adapters/agent_adapter.py +182 -8
- capability_runtime-0.1.5/src/capability_runtime/adapters/agently_backend.py +1142 -0
- capability_runtime-0.1.5/src/capability_runtime/adapters/agently_compat.py +95 -0
- capability_runtime-0.1.5/src/capability_runtime/adapters/agently_workspace.py +19 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/adapters/triggerflow_workflow_engine.py +228 -22
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/config.py +83 -14
- capability_runtime-0.1.5/src/capability_runtime/context_pack.py +290 -0
- capability_runtime-0.1.5/src/capability_runtime/dynamic_workflow.py +365 -0
- capability_runtime-0.1.5/src/capability_runtime/errors.py +67 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/__init__.py +3 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/chat_backend.py +5 -8
- capability_runtime-0.1.5/src/capability_runtime/protocol/dynamic_workflow.py +37 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/reporting/node_report.py +192 -1
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/runtime.py +543 -4
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/sdk_lifecycle.py +134 -42
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/types.py +2 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/projector.py +208 -8
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/v1.py +3 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/utils/usage.py +7 -2
- capability_runtime-0.1.5/src/capability_runtime/workflow_runtime.py +373 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime.egg-info/PKG-INFO +82 -7
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime.egg-info/SOURCES.txt +14 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime.egg-info/requires.txt +1 -1
- capability_runtime-0.1.5/tests/test_agently_action_artifact_evidence.py +328 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_agently_backend.py +134 -3
- capability_runtime-0.1.5/tests/test_agently_backend_authorization_header_contract.py +45 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_agently_backend_replay.py +38 -0
- capability_runtime-0.1.5/tests/test_agently_bridge_diagnostics.py +120 -0
- capability_runtime-0.1.5/tests/test_agently_workspace_recall_preview.py +190 -0
- capability_runtime-0.1.5/tests/test_backend_mode.py +310 -0
- capability_runtime-0.1.5/tests/test_config_glue.py +85 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_dependency_pins.py +16 -0
- capability_runtime-0.1.5/tests/test_dynamic_workflow_plan_contract.py +117 -0
- capability_runtime-0.1.5/tests/test_dynamic_workflow_runtime.py +279 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_smoke.py +47 -1
- capability_runtime-0.1.5/tests/test_integration_agently_requester_smoke.py +82 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_node_report_builder.py +64 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_node_report_contract_v1.py +8 -1
- capability_runtime-0.1.5/tests/test_openai_responses_compatible_bridge.py +1277 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_per_capability_llm_config_model_routing.py +220 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_public_api_exports.py +43 -1
- capability_runtime-0.1.5/tests/test_publish_real_provider_gate.py +112 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_release_tag_version_guardrail.py +2 -2
- capability_runtime-0.1.5/tests/test_review_followups_module_contracts.py +298 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_run_stream_semantics_v1.py +137 -2
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_structured_stream.py +107 -1
- capability_runtime-0.1.5/tests/test_triggerflow_lifecycle_mapping.py +265 -0
- capability_runtime-0.1.5/tests/test_workflow_host_runtime_surface.py +384 -0
- capability_runtime-0.1.3.post1/src/capability_runtime/adapters/agently_backend.py +0 -439
- capability_runtime-0.1.3.post1/src/capability_runtime/errors.py +0 -20
- capability_runtime-0.1.3.post1/src/capability_runtime/workflow_runtime.py +0 -218
- capability_runtime-0.1.3.post1/tests/test_backend_mode.py +0 -106
- capability_runtime-0.1.3.post1/tests/test_config_glue.py +0 -41
- capability_runtime-0.1.3.post1/tests/test_integration_agently_requester_smoke.py +0 -47
- capability_runtime-0.1.3.post1/tests/test_review_followups_module_contracts.py +0 -57
- capability_runtime-0.1.3.post1/tests/test_workflow_host_runtime_surface.py +0 -200
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/setup.cfg +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/adapters/__init__.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/adapters/workflow_engine.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/guards.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_protocol.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/__init__.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/approvals_profiles.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/evidence_hooks.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/history.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/invoke_capability.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/resume.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/system_prompt.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/host_toolkit/turn_delta.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/logging_utils.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/manifest.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/output_validator.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/agent.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/capability.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/context.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/protocol/workflow.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/registry.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/reporting/__init__.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/runtime_ui_events_mixin.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/service_facade.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/services.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/structured_output.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/structured_stream.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/__init__.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/session.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/store.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/ui_events/transport.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/upstream_compat.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/utils/__init__.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime.egg-info/dependency_links.txt +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime.egg-info/top_level.txt +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_bilingual_docs_surface.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_bridge_artifacts_passthrough.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_bridge_register_tool_public_api.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_coding_agent_examples_atomic.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_coding_agent_examples_recipes.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_docs_pinned_dependency_versions.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_docs_scheme2_no_skilladapter_residue.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_error_observability.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_alignment_fixes_l1.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_no_agent_sdk_imports.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_real_evidence_strict_integration.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_real_integration.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_ui_events_showcase_offline.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_ui_events_showcase_real_fallback.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_ui_events_showcase_real_integration.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_ui_events_showcase_ui_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_examples_workflow_skills_first_smoke.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_guards.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_approvals_profiles.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_history_assembler.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_invoke_capability.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_invoke_capability_shared_runtime.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_resume_helper.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_system_prompt_evidence.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_host_toolkit_turn_delta.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_integration_approval_event_shape.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_integration_sources_redis_pgsql_smoke.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_loop.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_node_report_engine_identity_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_offline_backend_injection_evidence.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_preflight_gate.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_project_identity_naming_matrix.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_public_repo_hygiene.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_qa_agent.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_registry.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_replay_tool_calls_alignment.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_repo_hygiene_no_tracked_env_or_pyc.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_repo_no_deep_imports_in_user_facing_docs.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_bridge_fake_backend.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_concurrency.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_engine.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_hitl_host_protocol.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_hooks_and_schema_gate.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_initial_history_and_meta.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_manifest.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_result_prompt_hardening.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_service_facade_rpc_mapping.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_service_session_bridge.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_status_mapping.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_runtime_structured_output_bridge.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_sandbox_permissions_passthrough_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_services_call_callback.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_services_map_node_status.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_skills_conformance_smoke.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_adapter_tool_registration.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_chat_backend_protocol_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_chat_sse_usage_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_compat_spaces_schema.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_prompt_profile_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_runtime_client_server_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_sandbox_profile_precedence_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_skills_bundles_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_tool_descriptor_compat.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_upstream_verification.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_versioning_strategy_guard.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_wal_backend_injection_contract.py +0 -0
- {capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/tests/test_wal_locator_resolution_contract.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: capability-runtime
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Bridge/glue layer that composes Agently (LLM/TriggerFlow) with skills-runtime-sdk (skills/tools/WAL/events).
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: PyYAML>=6
|
|
9
9
|
Requires-Dist: pydantic<3,>=2
|
|
10
|
-
Requires-Dist: agently==4.
|
|
10
|
+
Requires-Dist: agently==4.1.3.1
|
|
11
11
|
Requires-Dist: skills-runtime-sdk==0.1.12
|
|
12
12
|
Provides-Extra: dev
|
|
13
13
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
@@ -40,7 +40,10 @@ The public contract of this repository is intentionally narrow:
|
|
|
40
40
|
- Public capability registration and manifest descriptors
|
|
41
41
|
- Workflow orchestration on top of the runtime without exposing TriggerFlow as a public API
|
|
42
42
|
- Evidence-first results through `NodeReport`, tool-call reports, approval summaries, and WAL locators
|
|
43
|
-
- Host-facing helpers for
|
|
43
|
+
- Host-facing helpers for waiting summaries, approval tickets, resume-intent preview, continuity, and service streaming
|
|
44
|
+
- Runtime capability previews behind the same runtime contract:
|
|
45
|
+
Responses requester opt-in, Dynamic DAG preview, workflow lifecycle summaries,
|
|
46
|
+
Workspace/Recall context packs, and Action artifact evidence summaries
|
|
44
47
|
|
|
45
48
|
## Architecture At A Glance
|
|
46
49
|
|
|
@@ -48,7 +51,7 @@ The public contract of this repository is intentionally narrow:
|
|
|
48
51
|
+-----------------------------+
|
|
49
52
|
| Host Application |
|
|
50
53
|
| - register capabilities |
|
|
51
|
-
| - run / stream /
|
|
54
|
+
| - run / stream / summarize |
|
|
52
55
|
+--------------+--------------+
|
|
53
56
|
|
|
|
54
57
|
v
|
|
@@ -131,7 +134,27 @@ python examples/01_quickstart/run_bridge.py
|
|
|
131
134
|
```
|
|
132
135
|
|
|
133
136
|
Bridge mode reuses Agently's OpenAI-compatible transport but still delegates the
|
|
134
|
-
actual skills/tools/WAL semantics to `skills-runtime-sdk`.
|
|
137
|
+
actual skills/tools/WAL semantics to `skills-runtime-sdk`. The default requester
|
|
138
|
+
strategy is `chat_completions`. Responses mode is an explicit opt-in with
|
|
139
|
+
`RuntimeConfig.requester_strategy="responses"`; it is not the default.
|
|
140
|
+
|
|
141
|
+
Real provider wiring order:
|
|
142
|
+
|
|
143
|
+
1. Verify the provider model name with the gateway or `/models` surface.
|
|
144
|
+
2. Build a provider requester factory from neutral transport settings with
|
|
145
|
+
`build_openai_provider_requester_factory(...)`.
|
|
146
|
+
3. Keep chat/completions on the default `requester_strategy="chat_completions"`.
|
|
147
|
+
4. Opt in to the responses lane only if the provider supports `/responses`.
|
|
148
|
+
5. Run the runtime chat path with
|
|
149
|
+
`RuntimeConfig(mode="bridge", requester_strategy="chat_completions")`.
|
|
150
|
+
6. Run the runtime responses path with
|
|
151
|
+
`RuntimeConfig(mode="bridge", requester_strategy="responses")`.
|
|
152
|
+
|
|
153
|
+
Model routing has a separate priority chain: `AgentSpec.llm_config["model"]`
|
|
154
|
+
overrides the SDK `ChatRequest.model`, and that request model is the runtime
|
|
155
|
+
bridge source of truth when the provider usage payload omits `model`. Agently
|
|
156
|
+
settings configure transport details such as base URL, auth, and requester
|
|
157
|
+
plugin settings; they do not replace `AgentSpec.llm_config.model`.
|
|
135
158
|
|
|
136
159
|
### 3. Workflow orchestration
|
|
137
160
|
|
|
@@ -139,6 +162,19 @@ actual skills/tools/WAL semantics to `skills-runtime-sdk`.
|
|
|
139
162
|
python examples/02_workflow/run.py
|
|
140
163
|
```
|
|
141
164
|
|
|
165
|
+
### 4. Runtime capability previews
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
python examples/05_dynamic_dag_preview/run.py
|
|
169
|
+
python examples/06_responses_bridge/run.py
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
These previews keep the public surface inside `capability_runtime`: use
|
|
173
|
+
`DynamicWorkflowPlan` / runtime methods for Dynamic DAGs and
|
|
174
|
+
`RuntimeConfig.requester_strategy` for Responses. Do not build downstream code on
|
|
175
|
+
upstream-native `TaskDAG`, `DynamicTask`, `Workspace`, `Action`, or requester
|
|
176
|
+
objects.
|
|
177
|
+
|
|
142
178
|
For a higher-level index, start with [examples/README.md](examples/README.md).
|
|
143
179
|
|
|
144
180
|
## Public API At A Glance
|
|
@@ -150,6 +186,10 @@ from capability_runtime import (
|
|
|
150
186
|
Runtime,
|
|
151
187
|
RuntimeConfig,
|
|
152
188
|
CustomTool,
|
|
189
|
+
ProviderRequester,
|
|
190
|
+
ProviderRequesterFactory,
|
|
191
|
+
ProviderRequesterStrategy,
|
|
192
|
+
build_openai_provider_requester_factory,
|
|
153
193
|
AgentSpec,
|
|
154
194
|
AgentIOSchema,
|
|
155
195
|
WorkflowSpec,
|
|
@@ -162,10 +202,19 @@ from capability_runtime import (
|
|
|
162
202
|
CapabilityKind,
|
|
163
203
|
CapabilityResult,
|
|
164
204
|
CapabilityStatus,
|
|
205
|
+
DynamicWorkflowNode,
|
|
206
|
+
DynamicWorkflowPlan,
|
|
165
207
|
NodeReport,
|
|
208
|
+
StructuredStreamEvent,
|
|
166
209
|
HostRunSnapshot,
|
|
210
|
+
HostRunStatus,
|
|
167
211
|
ApprovalTicket,
|
|
168
212
|
ResumeIntent,
|
|
213
|
+
RuntimeContextRecordRef,
|
|
214
|
+
RuntimeRecallBackend,
|
|
215
|
+
RuntimeRecallContextPack,
|
|
216
|
+
build_recall_context_pack,
|
|
217
|
+
write_node_report_summary,
|
|
169
218
|
RuntimeServiceFacade,
|
|
170
219
|
RuntimeServiceRequest,
|
|
171
220
|
RuntimeServiceHandle,
|
|
@@ -176,8 +225,26 @@ from capability_runtime import (
|
|
|
176
225
|
The runtime currently supports three execution modes through `RuntimeConfig.mode`:
|
|
177
226
|
|
|
178
227
|
- `mock`: deterministic local testing without a real LLM backend
|
|
179
|
-
- `bridge`:
|
|
180
|
-
- `sdk_native`: native `skills-runtime-sdk` backend without
|
|
228
|
+
- `bridge`: provider transport adapter + `skills-runtime-sdk` execution semantics
|
|
229
|
+
- `sdk_native`: native `skills-runtime-sdk` backend without the provider transport adapter
|
|
230
|
+
|
|
231
|
+
Provider bridge strategy is separate from `mode`:
|
|
232
|
+
|
|
233
|
+
- `RuntimeConfig.requester_strategy="chat_completions"`: backward-compatible
|
|
234
|
+
default bridge path.
|
|
235
|
+
- `RuntimeConfig.requester_strategy="responses"`: opt-in Responses bridge path.
|
|
236
|
+
- `sdk_backend` injection takes precedence over both strategies for offline
|
|
237
|
+
regression and fake-backend tests.
|
|
238
|
+
|
|
239
|
+
Dynamic DAG preview is separate from `WorkflowSpec.steps`: compile a TaskDAG-like
|
|
240
|
+
mapping into the runtime-owned `DynamicWorkflowPlan`, keep `max_dynamic_nodes`
|
|
241
|
+
bounded, and execute nodes only through registered capabilities.
|
|
242
|
+
|
|
243
|
+
Provider audit evidence is expected in `NodeReport.usage`: preserve
|
|
244
|
+
`model`, `request_id`, `provider`, and token counts when the provider returns
|
|
245
|
+
them. If the provider omits `model`, the request model from `ChatRequest.model`
|
|
246
|
+
is the fallback; never treat an SDK placeholder such as `gpt-4` as real provider
|
|
247
|
+
evidence when a more specific request/provider model is available.
|
|
181
248
|
|
|
182
249
|
## Repository Layout
|
|
183
250
|
|
|
@@ -226,7 +293,15 @@ configure the corresponding Trusted Publisher entry on `pypi.org`.
|
|
|
226
293
|
|
|
227
294
|
- `skills-runtime-sdk` remains the source of truth for skills, approvals, tools,
|
|
228
295
|
WAL, and event evidence.
|
|
296
|
+
- Agently `SkillsExecutor` is not a `capability-runtime` skills driver. Its
|
|
297
|
+
authoring patterns may inform `SKILL.md` bundle design, but skill injection,
|
|
298
|
+
tool execution, approvals, WAL, events, and `NodeReport` aggregation remain
|
|
299
|
+
owned by `skills-runtime-sdk`.
|
|
229
300
|
- `Agently` remains the transport/orchestration substrate where this repository
|
|
230
301
|
chooses to bridge instead of forking or reimplementing.
|
|
231
302
|
- `capability-runtime` is the contract-convergence layer: it narrows those
|
|
232
303
|
upstream capabilities into a smaller host-facing runtime surface.
|
|
304
|
+
- Default bridge mode is non-breaking: if you do not configure Responses, Dynamic DAG,
|
|
305
|
+
Workspace/Recall, or Action artifact evidence previews, existing
|
|
306
|
+
`Runtime.run()` / `Runtime.run_stream()` / `WorkflowSpec` consumers can keep
|
|
307
|
+
reading the existing `NodeReport` and UI event fields.
|
|
@@ -24,7 +24,10 @@ The public contract of this repository is intentionally narrow:
|
|
|
24
24
|
- Public capability registration and manifest descriptors
|
|
25
25
|
- Workflow orchestration on top of the runtime without exposing TriggerFlow as a public API
|
|
26
26
|
- Evidence-first results through `NodeReport`, tool-call reports, approval summaries, and WAL locators
|
|
27
|
-
- Host-facing helpers for
|
|
27
|
+
- Host-facing helpers for waiting summaries, approval tickets, resume-intent preview, continuity, and service streaming
|
|
28
|
+
- Runtime capability previews behind the same runtime contract:
|
|
29
|
+
Responses requester opt-in, Dynamic DAG preview, workflow lifecycle summaries,
|
|
30
|
+
Workspace/Recall context packs, and Action artifact evidence summaries
|
|
28
31
|
|
|
29
32
|
## Architecture At A Glance
|
|
30
33
|
|
|
@@ -32,7 +35,7 @@ The public contract of this repository is intentionally narrow:
|
|
|
32
35
|
+-----------------------------+
|
|
33
36
|
| Host Application |
|
|
34
37
|
| - register capabilities |
|
|
35
|
-
| - run / stream /
|
|
38
|
+
| - run / stream / summarize |
|
|
36
39
|
+--------------+--------------+
|
|
37
40
|
|
|
|
38
41
|
v
|
|
@@ -115,7 +118,27 @@ python examples/01_quickstart/run_bridge.py
|
|
|
115
118
|
```
|
|
116
119
|
|
|
117
120
|
Bridge mode reuses Agently's OpenAI-compatible transport but still delegates the
|
|
118
|
-
actual skills/tools/WAL semantics to `skills-runtime-sdk`.
|
|
121
|
+
actual skills/tools/WAL semantics to `skills-runtime-sdk`. The default requester
|
|
122
|
+
strategy is `chat_completions`. Responses mode is an explicit opt-in with
|
|
123
|
+
`RuntimeConfig.requester_strategy="responses"`; it is not the default.
|
|
124
|
+
|
|
125
|
+
Real provider wiring order:
|
|
126
|
+
|
|
127
|
+
1. Verify the provider model name with the gateway or `/models` surface.
|
|
128
|
+
2. Build a provider requester factory from neutral transport settings with
|
|
129
|
+
`build_openai_provider_requester_factory(...)`.
|
|
130
|
+
3. Keep chat/completions on the default `requester_strategy="chat_completions"`.
|
|
131
|
+
4. Opt in to the responses lane only if the provider supports `/responses`.
|
|
132
|
+
5. Run the runtime chat path with
|
|
133
|
+
`RuntimeConfig(mode="bridge", requester_strategy="chat_completions")`.
|
|
134
|
+
6. Run the runtime responses path with
|
|
135
|
+
`RuntimeConfig(mode="bridge", requester_strategy="responses")`.
|
|
136
|
+
|
|
137
|
+
Model routing has a separate priority chain: `AgentSpec.llm_config["model"]`
|
|
138
|
+
overrides the SDK `ChatRequest.model`, and that request model is the runtime
|
|
139
|
+
bridge source of truth when the provider usage payload omits `model`. Agently
|
|
140
|
+
settings configure transport details such as base URL, auth, and requester
|
|
141
|
+
plugin settings; they do not replace `AgentSpec.llm_config.model`.
|
|
119
142
|
|
|
120
143
|
### 3. Workflow orchestration
|
|
121
144
|
|
|
@@ -123,6 +146,19 @@ actual skills/tools/WAL semantics to `skills-runtime-sdk`.
|
|
|
123
146
|
python examples/02_workflow/run.py
|
|
124
147
|
```
|
|
125
148
|
|
|
149
|
+
### 4. Runtime capability previews
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python examples/05_dynamic_dag_preview/run.py
|
|
153
|
+
python examples/06_responses_bridge/run.py
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
These previews keep the public surface inside `capability_runtime`: use
|
|
157
|
+
`DynamicWorkflowPlan` / runtime methods for Dynamic DAGs and
|
|
158
|
+
`RuntimeConfig.requester_strategy` for Responses. Do not build downstream code on
|
|
159
|
+
upstream-native `TaskDAG`, `DynamicTask`, `Workspace`, `Action`, or requester
|
|
160
|
+
objects.
|
|
161
|
+
|
|
126
162
|
For a higher-level index, start with [examples/README.md](examples/README.md).
|
|
127
163
|
|
|
128
164
|
## Public API At A Glance
|
|
@@ -134,6 +170,10 @@ from capability_runtime import (
|
|
|
134
170
|
Runtime,
|
|
135
171
|
RuntimeConfig,
|
|
136
172
|
CustomTool,
|
|
173
|
+
ProviderRequester,
|
|
174
|
+
ProviderRequesterFactory,
|
|
175
|
+
ProviderRequesterStrategy,
|
|
176
|
+
build_openai_provider_requester_factory,
|
|
137
177
|
AgentSpec,
|
|
138
178
|
AgentIOSchema,
|
|
139
179
|
WorkflowSpec,
|
|
@@ -146,10 +186,19 @@ from capability_runtime import (
|
|
|
146
186
|
CapabilityKind,
|
|
147
187
|
CapabilityResult,
|
|
148
188
|
CapabilityStatus,
|
|
189
|
+
DynamicWorkflowNode,
|
|
190
|
+
DynamicWorkflowPlan,
|
|
149
191
|
NodeReport,
|
|
192
|
+
StructuredStreamEvent,
|
|
150
193
|
HostRunSnapshot,
|
|
194
|
+
HostRunStatus,
|
|
151
195
|
ApprovalTicket,
|
|
152
196
|
ResumeIntent,
|
|
197
|
+
RuntimeContextRecordRef,
|
|
198
|
+
RuntimeRecallBackend,
|
|
199
|
+
RuntimeRecallContextPack,
|
|
200
|
+
build_recall_context_pack,
|
|
201
|
+
write_node_report_summary,
|
|
153
202
|
RuntimeServiceFacade,
|
|
154
203
|
RuntimeServiceRequest,
|
|
155
204
|
RuntimeServiceHandle,
|
|
@@ -160,8 +209,26 @@ from capability_runtime import (
|
|
|
160
209
|
The runtime currently supports three execution modes through `RuntimeConfig.mode`:
|
|
161
210
|
|
|
162
211
|
- `mock`: deterministic local testing without a real LLM backend
|
|
163
|
-
- `bridge`:
|
|
164
|
-
- `sdk_native`: native `skills-runtime-sdk` backend without
|
|
212
|
+
- `bridge`: provider transport adapter + `skills-runtime-sdk` execution semantics
|
|
213
|
+
- `sdk_native`: native `skills-runtime-sdk` backend without the provider transport adapter
|
|
214
|
+
|
|
215
|
+
Provider bridge strategy is separate from `mode`:
|
|
216
|
+
|
|
217
|
+
- `RuntimeConfig.requester_strategy="chat_completions"`: backward-compatible
|
|
218
|
+
default bridge path.
|
|
219
|
+
- `RuntimeConfig.requester_strategy="responses"`: opt-in Responses bridge path.
|
|
220
|
+
- `sdk_backend` injection takes precedence over both strategies for offline
|
|
221
|
+
regression and fake-backend tests.
|
|
222
|
+
|
|
223
|
+
Dynamic DAG preview is separate from `WorkflowSpec.steps`: compile a TaskDAG-like
|
|
224
|
+
mapping into the runtime-owned `DynamicWorkflowPlan`, keep `max_dynamic_nodes`
|
|
225
|
+
bounded, and execute nodes only through registered capabilities.
|
|
226
|
+
|
|
227
|
+
Provider audit evidence is expected in `NodeReport.usage`: preserve
|
|
228
|
+
`model`, `request_id`, `provider`, and token counts when the provider returns
|
|
229
|
+
them. If the provider omits `model`, the request model from `ChatRequest.model`
|
|
230
|
+
is the fallback; never treat an SDK placeholder such as `gpt-4` as real provider
|
|
231
|
+
evidence when a more specific request/provider model is available.
|
|
165
232
|
|
|
166
233
|
## Repository Layout
|
|
167
234
|
|
|
@@ -210,7 +277,15 @@ configure the corresponding Trusted Publisher entry on `pypi.org`.
|
|
|
210
277
|
|
|
211
278
|
- `skills-runtime-sdk` remains the source of truth for skills, approvals, tools,
|
|
212
279
|
WAL, and event evidence.
|
|
280
|
+
- Agently `SkillsExecutor` is not a `capability-runtime` skills driver. Its
|
|
281
|
+
authoring patterns may inform `SKILL.md` bundle design, but skill injection,
|
|
282
|
+
tool execution, approvals, WAL, events, and `NodeReport` aggregation remain
|
|
283
|
+
owned by `skills-runtime-sdk`.
|
|
213
284
|
- `Agently` remains the transport/orchestration substrate where this repository
|
|
214
285
|
chooses to bridge instead of forking or reimplementing.
|
|
215
286
|
- `capability-runtime` is the contract-convergence layer: it narrows those
|
|
216
287
|
upstream capabilities into a smaller host-facing runtime surface.
|
|
288
|
+
- Default bridge mode is non-breaking: if you do not configure Responses, Dynamic DAG,
|
|
289
|
+
Workspace/Recall, or Action artifact evidence previews, existing
|
|
290
|
+
`Runtime.run()` / `Runtime.run_stream()` / `WorkflowSpec` consumers can keep
|
|
291
|
+
reading the existing `NodeReport` and UI event fields.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "capability-runtime"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.5"
|
|
4
4
|
description = "Bridge/glue layer that composes Agently (LLM/TriggerFlow) with skills-runtime-sdk (skills/tools/WAL/events)."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -8,7 +8,7 @@ license = "MIT"
|
|
|
8
8
|
dependencies = [
|
|
9
9
|
"PyYAML>=6",
|
|
10
10
|
"pydantic>=2,<3",
|
|
11
|
-
"agently==4.
|
|
11
|
+
"agently==4.1.3.1",
|
|
12
12
|
"skills-runtime-sdk==0.1.12",
|
|
13
13
|
]
|
|
14
14
|
|
{capability_runtime-0.1.3.post1 → capability_runtime-0.1.5}/src/capability_runtime/__init__.py
RENAMED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
"""capability-runtime:统一 Runtime 入口(能力协议 + 执行 + 报告)。"""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
__version__ = "0.1.
|
|
4
|
+
__version__ = "0.1.5"
|
|
5
5
|
|
|
6
6
|
# === 统一入口 ===
|
|
7
|
-
from .config import
|
|
7
|
+
from .config import (
|
|
8
|
+
AgentlyRequesterStrategy,
|
|
9
|
+
CustomTool,
|
|
10
|
+
ProviderRequester,
|
|
11
|
+
ProviderRequesterFactory,
|
|
12
|
+
ProviderRequesterStrategy,
|
|
13
|
+
RuntimeConfig,
|
|
14
|
+
ToolChoiceAfterToolResult,
|
|
15
|
+
)
|
|
16
|
+
from .context_pack import (
|
|
17
|
+
RuntimeContextRecordRef,
|
|
18
|
+
RuntimeRecallBackend,
|
|
19
|
+
RuntimeRecallContextPack,
|
|
20
|
+
build_recall_context_pack,
|
|
21
|
+
write_node_report_summary,
|
|
22
|
+
)
|
|
8
23
|
from .runtime import Runtime
|
|
9
24
|
from .service_facade import RuntimeServiceFacade, RuntimeServiceHandle, RuntimeServiceRequest, RuntimeSession
|
|
10
25
|
from .structured_stream import StructuredStreamEvent
|
|
26
|
+
from .adapters.agently_backend import build_openai_provider_requester_factory
|
|
11
27
|
|
|
12
28
|
# === 报告类型 ===
|
|
13
29
|
from .types import NodeReport, NodeResult
|
|
@@ -27,6 +43,7 @@ from .protocol.capability import (
|
|
|
27
43
|
CapabilityStatus,
|
|
28
44
|
)
|
|
29
45
|
from .protocol.context import ExecutionContext
|
|
46
|
+
from .protocol.dynamic_workflow import DynamicWorkflowNode, DynamicWorkflowPlan
|
|
30
47
|
from .protocol.workflow import (
|
|
31
48
|
ConditionalStep,
|
|
32
49
|
InputMapping,
|
|
@@ -35,7 +52,6 @@ from .protocol.workflow import (
|
|
|
35
52
|
Step,
|
|
36
53
|
WorkflowSpec,
|
|
37
54
|
)
|
|
38
|
-
from .services import RuntimeServices
|
|
39
55
|
from .workflow_runtime import WorkflowReplayRequest, WorkflowRunSnapshot, WorkflowRunStatus, WorkflowStepSnapshot
|
|
40
56
|
|
|
41
57
|
# === 错误导出 ===
|
|
@@ -45,8 +61,19 @@ __all__ = [
|
|
|
45
61
|
# Runtime
|
|
46
62
|
"Runtime",
|
|
47
63
|
"RuntimeConfig",
|
|
64
|
+
"ProviderRequesterStrategy",
|
|
65
|
+
"AgentlyRequesterStrategy",
|
|
66
|
+
"ToolChoiceAfterToolResult",
|
|
67
|
+
"ProviderRequester",
|
|
68
|
+
"ProviderRequesterFactory",
|
|
48
69
|
"CustomTool",
|
|
49
70
|
"StructuredStreamEvent",
|
|
71
|
+
"RuntimeContextRecordRef",
|
|
72
|
+
"RuntimeRecallBackend",
|
|
73
|
+
"RuntimeRecallContextPack",
|
|
74
|
+
"build_recall_context_pack",
|
|
75
|
+
"write_node_report_summary",
|
|
76
|
+
"build_openai_provider_requester_factory",
|
|
50
77
|
# Reports
|
|
51
78
|
"NodeReport",
|
|
52
79
|
"NodeResult",
|
|
@@ -77,6 +104,8 @@ __all__ = [
|
|
|
77
104
|
"AgentSpec",
|
|
78
105
|
"AgentIOSchema",
|
|
79
106
|
"PromptRenderMode",
|
|
107
|
+
"DynamicWorkflowNode",
|
|
108
|
+
"DynamicWorkflowPlan",
|
|
80
109
|
"WorkflowSpec",
|
|
81
110
|
"Step",
|
|
82
111
|
"LoopStep",
|
|
@@ -84,8 +113,11 @@ __all__ = [
|
|
|
84
113
|
"ConditionalStep",
|
|
85
114
|
"InputMapping",
|
|
86
115
|
"ExecutionContext",
|
|
87
|
-
"RuntimeServices",
|
|
88
116
|
# Errors
|
|
89
117
|
"RuntimeFrameworkError",
|
|
90
118
|
"CapabilityNotFoundError",
|
|
91
119
|
]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def __getattr__(name: str):
|
|
123
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -20,12 +20,14 @@ from typing import Any, AsyncIterator, Dict, List, Optional, Union
|
|
|
20
20
|
from skills_runtime.core.contracts import AgentEvent
|
|
21
21
|
from skills_runtime.core.errors import FrameworkIssue
|
|
22
22
|
|
|
23
|
+
from ..errors import ProviderStreamTerminalError
|
|
23
24
|
from ..logging_utils import log_suppressed_exception
|
|
24
25
|
from ..protocol.agent import AgentSpec
|
|
25
26
|
from ..protocol.capability import CapabilityResult, CapabilityStatus
|
|
26
27
|
from ..protocol.context import ExecutionContext
|
|
27
|
-
from ..reporting.node_report import NodeReportBuilder
|
|
28
|
+
from ..reporting.node_report import NodeReportBuilder, attach_agently_bridge_diagnostics
|
|
28
29
|
from ..services import RuntimeServices, map_node_status
|
|
30
|
+
from ..types import NodeUsageReport
|
|
29
31
|
|
|
30
32
|
# _build_task 使用的 prompt section 常量
|
|
31
33
|
_SECTION_SYSTEM = "## 系统指令"
|
|
@@ -37,6 +39,7 @@ _RUNTIME_PROMPT_KEY = "_runtime_prompt"
|
|
|
37
39
|
_PROMPT_HASH_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
|
|
38
40
|
_ALLOWED_PROMPT_ROLES = {"system", "developer", "user", "assistant", "tool"}
|
|
39
41
|
_ALLOWED_PROMPT_PROFILES = {"default_agent", "generation_direct", "structured_transform"}
|
|
42
|
+
_ALLOWED_IMAGE_DETAILS = {"auto", "low", "high"}
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
class _InvalidPromptMessages(ValueError):
|
|
@@ -366,6 +369,67 @@ class AgentAdapter:
|
|
|
366
369
|
node_report=report,
|
|
367
370
|
)
|
|
368
371
|
return
|
|
372
|
+
except ProviderStreamTerminalError as exc:
|
|
373
|
+
provider_terminal = exc.to_control_payload()
|
|
374
|
+
if any(ev.type == "provider_stream_terminal" for ev in events):
|
|
375
|
+
events.append(
|
|
376
|
+
AgentEvent(
|
|
377
|
+
type="run_failed",
|
|
378
|
+
timestamp="",
|
|
379
|
+
run_id=context.run_id,
|
|
380
|
+
turn_id=None,
|
|
381
|
+
payload={"error_kind": exc.reason, "message": exc.message},
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
report = NodeReportBuilder().build(events=events)
|
|
385
|
+
attach_agently_bridge_diagnostics(
|
|
386
|
+
report,
|
|
387
|
+
mode=getattr(self._services.config, "mode", ""),
|
|
388
|
+
requester_strategy=getattr(self._services.config, "effective_requester_strategy", "chat_completions"),
|
|
389
|
+
)
|
|
390
|
+
report.meta["capability_id"] = spec.base.id
|
|
391
|
+
report.meta["source"] = "provider_stream"
|
|
392
|
+
else:
|
|
393
|
+
report = self._services.build_fail_closed_report(
|
|
394
|
+
run_id=context.run_id,
|
|
395
|
+
status=exc.status,
|
|
396
|
+
reason=exc.reason,
|
|
397
|
+
completion_reason=exc.completion_reason,
|
|
398
|
+
meta={
|
|
399
|
+
"capability_id": spec.base.id,
|
|
400
|
+
"source": "provider_stream",
|
|
401
|
+
"provider_terminal": provider_terminal,
|
|
402
|
+
**prompt_plan.evidence,
|
|
403
|
+
},
|
|
404
|
+
)
|
|
405
|
+
if (
|
|
406
|
+
exc.model is not None
|
|
407
|
+
or exc.request_id is not None
|
|
408
|
+
or exc.provider is not None
|
|
409
|
+
or exc.provider_transport is not None
|
|
410
|
+
):
|
|
411
|
+
report.usage = NodeUsageReport(
|
|
412
|
+
model=exc.model,
|
|
413
|
+
request_id=exc.request_id,
|
|
414
|
+
provider=exc.provider,
|
|
415
|
+
provider_transport=exc.provider_transport,
|
|
416
|
+
)
|
|
417
|
+
self._apply_prompt_evidence(report=report, evidence=prompt_plan.evidence)
|
|
418
|
+
_apply_on_event_error_evidence(report)
|
|
419
|
+
status = map_node_status(report)
|
|
420
|
+
error_code = (
|
|
421
|
+
str(provider_terminal.get("error_code"))
|
|
422
|
+
if isinstance(provider_terminal.get("error_code"), str)
|
|
423
|
+
else None
|
|
424
|
+
)
|
|
425
|
+
yield CapabilityResult(
|
|
426
|
+
status=status,
|
|
427
|
+
error=exc.message if status == CapabilityStatus.FAILED else None,
|
|
428
|
+
error_code=error_code,
|
|
429
|
+
report=report,
|
|
430
|
+
node_report=report,
|
|
431
|
+
)
|
|
432
|
+
return
|
|
369
433
|
except Exception as exc:
|
|
370
434
|
report = self._services.build_fail_closed_report(
|
|
371
435
|
run_id=context.run_id,
|
|
@@ -385,6 +449,11 @@ class AgentAdapter:
|
|
|
385
449
|
return
|
|
386
450
|
|
|
387
451
|
report = NodeReportBuilder().build(events=events)
|
|
452
|
+
attach_agently_bridge_diagnostics(
|
|
453
|
+
report,
|
|
454
|
+
mode=getattr(self._services.config, "mode", ""),
|
|
455
|
+
requester_strategy=getattr(self._services.config, "effective_requester_strategy", "chat_completions"),
|
|
456
|
+
)
|
|
388
457
|
self._apply_prompt_evidence(report=report, evidence=prompt_plan.evidence)
|
|
389
458
|
_apply_on_event_error_evidence(report)
|
|
390
459
|
if issues and getattr(self._services.config, "preflight_mode", "error") == "warn":
|
|
@@ -417,10 +486,20 @@ class AgentAdapter:
|
|
|
417
486
|
)
|
|
418
487
|
|
|
419
488
|
status = map_node_status(report)
|
|
489
|
+
provider_terminal = report.meta.get("provider_terminal") if isinstance(report.meta, dict) else None
|
|
490
|
+
terminal_error_code = None
|
|
491
|
+
if isinstance(provider_terminal, dict) and isinstance(provider_terminal.get("error_code"), str):
|
|
492
|
+
terminal_error_code = provider_terminal["error_code"]
|
|
493
|
+
terminal_error = None
|
|
494
|
+
if isinstance(provider_terminal, dict) and isinstance(provider_terminal.get("message"), str):
|
|
495
|
+
terminal_error = provider_terminal["message"]
|
|
496
|
+
if final_output.startswith("CAPRT_PROVIDER_STREAM_TERMINAL "):
|
|
497
|
+
final_output = terminal_error if status == CapabilityStatus.FAILED else ""
|
|
420
498
|
yield CapabilityResult(
|
|
421
499
|
status=status,
|
|
422
500
|
output=final_output,
|
|
423
|
-
error=report.reason if status == CapabilityStatus.FAILED else None,
|
|
501
|
+
error=terminal_error if terminal_error is not None and status == CapabilityStatus.FAILED else (report.reason if status == CapabilityStatus.FAILED else None),
|
|
502
|
+
error_code=terminal_error_code,
|
|
424
503
|
report=report,
|
|
425
504
|
node_report=report,
|
|
426
505
|
artifacts=list(report.artifacts),
|
|
@@ -578,6 +657,10 @@ class AgentAdapter:
|
|
|
578
657
|
if messages is not None:
|
|
579
658
|
evidence["prompt_messages_count"] = len(messages)
|
|
580
659
|
evidence["prompt_message_roles"] = [str(item["role"]) for item in messages]
|
|
660
|
+
modalities, content_part_counts, media_count = _summarize_precomposed_message_content(messages)
|
|
661
|
+
evidence["prompt_modalities"] = modalities
|
|
662
|
+
evidence["prompt_content_part_counts"] = content_part_counts
|
|
663
|
+
evidence["prompt_media_count"] = media_count
|
|
581
664
|
return evidence
|
|
582
665
|
|
|
583
666
|
def _strip_runtime_prompt(self, input: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -736,18 +819,27 @@ def _hash_text(text: str) -> str:
|
|
|
736
819
|
def _hash_messages(messages: List[Dict[str, Any]]) -> str:
|
|
737
820
|
"""对 provider messages 做稳定 JSON canonicalization 后生成摘要。"""
|
|
738
821
|
|
|
739
|
-
canonical =
|
|
822
|
+
canonical = _canonicalize_messages(messages)
|
|
740
823
|
return _hash_text(canonical)
|
|
741
824
|
|
|
742
825
|
|
|
826
|
+
def _canonicalize_messages(messages: List[Dict[str, Any]]) -> str:
|
|
827
|
+
"""对 provider messages 做稳定 JSON canonicalization。"""
|
|
828
|
+
|
|
829
|
+
try:
|
|
830
|
+
return json.dumps(messages, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False)
|
|
831
|
+
except (TypeError, ValueError) as exc:
|
|
832
|
+
raise _InvalidPromptMessages("_runtime_prompt.messages must be JSON canonicalizable") from exc
|
|
833
|
+
|
|
834
|
+
|
|
743
835
|
def _validate_precomposed_messages(raw: Any) -> List[Dict[str, Any]]:
|
|
744
836
|
"""
|
|
745
837
|
校验 host 提供的最终 provider messages。
|
|
746
838
|
|
|
747
839
|
约束:
|
|
748
840
|
- 只接受非空 list[dict];
|
|
749
|
-
- 每条消息必须有合法 role
|
|
750
|
-
-
|
|
841
|
+
- 每条消息必须有合法 role 与字符串或稳定 content parts;
|
|
842
|
+
- 返回深拷贝,避免后续执行链路修改调用方输入。
|
|
751
843
|
"""
|
|
752
844
|
|
|
753
845
|
if not isinstance(raw, list):
|
|
@@ -763,10 +855,92 @@ def _validate_precomposed_messages(raw: Any) -> List[Dict[str, Any]]:
|
|
|
763
855
|
content = item.get("content")
|
|
764
856
|
if not isinstance(role, str) or role not in _ALLOWED_PROMPT_ROLES:
|
|
765
857
|
raise _InvalidPromptMessages(f"_runtime_prompt.messages[{idx}].role is invalid")
|
|
766
|
-
if not isinstance(content, str):
|
|
767
|
-
raise _InvalidPromptMessages(f"_runtime_prompt.messages[{idx}].content must be a string")
|
|
768
858
|
copied = dict(item)
|
|
769
859
|
copied["role"] = role
|
|
770
|
-
copied["content"] = content
|
|
860
|
+
copied["content"] = _validate_precomposed_message_content(content, message_index=idx)
|
|
771
861
|
out.append(copied)
|
|
862
|
+
return json.loads(_canonicalize_messages(out))
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
def _validate_precomposed_message_content(content: Any, *, message_index: int) -> Union[str, List[Dict[str, Any]]]:
|
|
866
|
+
"""校验单条 precomposed message 的 content 字段。"""
|
|
867
|
+
|
|
868
|
+
if isinstance(content, str):
|
|
869
|
+
return content
|
|
870
|
+
if not isinstance(content, list):
|
|
871
|
+
raise _InvalidPromptMessages(
|
|
872
|
+
f"_runtime_prompt.messages[{message_index}].content must be a string or content part list"
|
|
873
|
+
)
|
|
874
|
+
if not content:
|
|
875
|
+
raise _InvalidPromptMessages(f"_runtime_prompt.messages[{message_index}].content must not be an empty list")
|
|
876
|
+
|
|
877
|
+
out: List[Dict[str, Any]] = []
|
|
878
|
+
for part_index, part in enumerate(content):
|
|
879
|
+
out.append(_validate_precomposed_content_part(part, message_index=message_index, part_index=part_index))
|
|
772
880
|
return out
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def _validate_precomposed_content_part(part: Any, *, message_index: int, part_index: int) -> Dict[str, Any]:
|
|
884
|
+
"""校验 v1 稳定支持的 OpenAI-compatible content part。"""
|
|
885
|
+
|
|
886
|
+
path = f"_runtime_prompt.messages[{message_index}].content[{part_index}]"
|
|
887
|
+
if not isinstance(part, dict):
|
|
888
|
+
raise _InvalidPromptMessages(f"{path} must be a dict")
|
|
889
|
+
part_type = part.get("type")
|
|
890
|
+
if not isinstance(part_type, str) or not part_type:
|
|
891
|
+
raise _InvalidPromptMessages(f"{path}.type is required")
|
|
892
|
+
if part_type == "text":
|
|
893
|
+
if set(part.keys()) != {"type", "text"}:
|
|
894
|
+
raise _InvalidPromptMessages(f"{path} has unsupported text part fields")
|
|
895
|
+
text = part.get("text")
|
|
896
|
+
if not isinstance(text, str):
|
|
897
|
+
raise _InvalidPromptMessages(f"{path}.text must be a string")
|
|
898
|
+
return {"type": "text", "text": text}
|
|
899
|
+
if part_type == "image_url":
|
|
900
|
+
if set(part.keys()) != {"type", "image_url"}:
|
|
901
|
+
raise _InvalidPromptMessages(f"{path} has unsupported image_url part fields")
|
|
902
|
+
image_url = part.get("image_url")
|
|
903
|
+
if not isinstance(image_url, dict):
|
|
904
|
+
raise _InvalidPromptMessages(f"{path}.image_url must be a dict")
|
|
905
|
+
allowed_image_keys = {"url", "detail"}
|
|
906
|
+
if not set(image_url.keys()).issubset(allowed_image_keys):
|
|
907
|
+
raise _InvalidPromptMessages(f"{path}.image_url has unsupported fields")
|
|
908
|
+
url = image_url.get("url")
|
|
909
|
+
if not isinstance(url, str) or not url.strip():
|
|
910
|
+
raise _InvalidPromptMessages(f"{path}.image_url.url must be a non-empty string")
|
|
911
|
+
copied_image_url: Dict[str, Any] = {"url": url}
|
|
912
|
+
if "detail" in image_url:
|
|
913
|
+
detail = image_url.get("detail")
|
|
914
|
+
if detail not in _ALLOWED_IMAGE_DETAILS:
|
|
915
|
+
raise _InvalidPromptMessages(f"{path}.image_url.detail is invalid")
|
|
916
|
+
copied_image_url["detail"] = detail
|
|
917
|
+
return {"type": "image_url", "image_url": copied_image_url}
|
|
918
|
+
raise _InvalidPromptMessages(f"{path}.type is unsupported")
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
def _summarize_precomposed_message_content(
|
|
922
|
+
messages: List[Dict[str, Any]],
|
|
923
|
+
) -> tuple[List[str], List[int], int]:
|
|
924
|
+
"""生成 precomposed messages 的最小披露多模态摘要。"""
|
|
925
|
+
|
|
926
|
+
modalities: set[str] = set()
|
|
927
|
+
content_part_counts: List[int] = []
|
|
928
|
+
media_count = 0
|
|
929
|
+
for message in messages:
|
|
930
|
+
content = message.get("content")
|
|
931
|
+
if isinstance(content, str):
|
|
932
|
+
modalities.add("text")
|
|
933
|
+
content_part_counts.append(0)
|
|
934
|
+
continue
|
|
935
|
+
if isinstance(content, list):
|
|
936
|
+
content_part_counts.append(len(content))
|
|
937
|
+
for part in content:
|
|
938
|
+
part_type = part.get("type") if isinstance(part, dict) else None
|
|
939
|
+
if part_type == "text":
|
|
940
|
+
modalities.add("text")
|
|
941
|
+
elif part_type == "image_url":
|
|
942
|
+
modalities.add("image")
|
|
943
|
+
media_count += 1
|
|
944
|
+
continue
|
|
945
|
+
content_part_counts.append(0)
|
|
946
|
+
return sorted(modalities), content_part_counts, media_count
|