aisolate-agent 0.3.2__tar.gz → 0.3.4__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.
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/PKG-INFO +2 -2
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/README.md +1 -1
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/pyproject.toml +1 -1
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/agent.py +57 -17
- aisolate_agent-0.3.4/src/aisolate/agent/config/__init__.py +15 -0
- aisolate_agent-0.3.4/src/aisolate/agent/config/state_llm.py +92 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/context.py +16 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/events.py +2 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/protocols.py +8 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/task.py +3 -3
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/llm/base.py +44 -6
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/llm/harmony.py +4 -4
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/llm/oai.py +52 -13
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/llm/qwen.py +22 -4
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/conftest.py +3 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_event_agent_name_stamping.py +3 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_run_streaming_cancel.py +3 -0
- aisolate_agent-0.3.4/src/aisolate/agent/tests/test_core/test_state_llm_overrides.py +421 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_turn_started_events.py +3 -0
- aisolate_agent-0.3.4/src/aisolate/agent/tests/test_integration/test_prompt_template_contract.py +120 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_llm_generate_span.py +8 -1
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_subagent_failure_contract.py +9 -1
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/subagent.py +15 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/PKG-INFO +2 -2
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/SOURCES.txt +3 -0
- aisolate_agent-0.3.2/src/aisolate/agent/config/__init__.py +0 -5
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/setup.cfg +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/config/agent_settings.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/config/prompts/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/artifacts.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/budget.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/conversation_log.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/exceptions.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/graph.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/initial_state.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/llm_response.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/policy.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/snapshot.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/spine_compaction.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/tests/test_context_snapshots.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/tests/test_snapshot.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/views.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/core/workspace.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/graphs.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/logging/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/logging/config.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/logging/factory.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/logging/unified_logger.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/main.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/memory/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/memory/models.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/base.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/clarification.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/compaction.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/critic.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/executing.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/expert_synthesis.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/finished.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/hitl_pause.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/outputs.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/states/planning.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/status.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/llm/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/memory/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/memory/in_memory.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/memory/tests/test_in_memory.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/strategies/memory/vector.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/substrate.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/decorators.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/factory.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/interface.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/noop.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/openinference.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/opentelemetry_impl.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/telemetry/utils.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/fakes.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_architecture_assumptions.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_artifact_rows.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_change_bridge_echo.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_conversation_log.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_delegated_lineage_restore.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_execute_turn_review_pending.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_firewall_property.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_graph.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_initial_state.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_legacy_snapshot.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_live_capture.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_locale_prelude.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_policy.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_restore_review_posture.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_resume_semantics.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_spine_compaction.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_state_transitions.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_status_summarizer.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_subagent_graph.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_substrate.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_token_accumulation.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_turn_usage_isolation.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_uniform_state.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_views.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_workspace_bridge_attribution.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_workspace_capture.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_core/test_workspace_changed_event.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/conftest.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_delegation_file_paths.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_delegation_recovery.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_locale_helpers.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_size_compaction.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_stall_clone_96919cf1.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_truncation_wedge_5b90b101.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_e2e/test_workspace_lifecycle.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/helpers.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/test_flagship_loop.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/test_followup_roundtrips.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/test_full_workflow.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/test_restore_roundtrips.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_integration/test_stalled_and_acceptance.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_compact_for_llm.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_critic_enforcer.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_critic_review_cap.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_emission_map.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_executing_metadata.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_executing_prefix_stability.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_executing_review_routing.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_planning_artifact.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_planning_metadata.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_progress_ledger.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_selection.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_size_compaction_wiring.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_states/test_stall_recovery.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_identity_block.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_llm_providers.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_llm_watchdog.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_prepare_history_contract.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_qwen_retry.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_qwen_strategy.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_qwen_truncation.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_qwen_workspace_envelope.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_scripted_llm_contract.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_telemetry_attributes.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_strategies/test_turn_budget_block.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_bundle_and_restore.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_delegation_identity.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_edit_blocks.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_fake_executor.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_handover_sidecars.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_load_handover_resolution.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_output_refs.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_sandbox_import_surface.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_send_actions_error.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_shell_executing_loop.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_shell_tools.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_subagent_handover.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_three_tier_tools.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_workspace_actions.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tests/test_tools/test_workspace_tools.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/base.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/final_answer.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/load_handover.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/visit_page_action.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/web_search_action.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/wikipedia_search_action.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/actions/workspace.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/base.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/execution.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/functions/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/functions/base.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/functions/hitl.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/models.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/base.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/edit_blocks.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/files_ops.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/python_executor.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/shell.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/web_search.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/platform/workspace_tools.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/tools/routing.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/trace.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/agent/utils.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/codec.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/errors.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/models.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/output_window.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/fake_vm.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/fixtures.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/test_codec_channel.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/test_output_window.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/common/tests/utils.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/logging/__init__.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/logging/formatters.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate/logging/processors.py +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/dependency_links.txt +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/entry_points.txt +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/requires.txt +0 -0
- {aisolate_agent-0.3.2 → aisolate_agent-0.3.4}/src/aisolate_agent.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aisolate-agent
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: AI Agent with intelligent planning and reasoning
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -30,7 +30,7 @@ AI Agent with intelligent planning and reasoning
|
|
|
30
30
|
## Local Installation
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
pip install path/to/aisolate_agent-0.3.
|
|
33
|
+
pip install path/to/aisolate_agent-0.3.4-py3-none-any.whl
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Main Agent class - public API for the three-tier tool architecture."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from types import MappingProxyType
|
|
4
|
+
from typing import Optional, Dict, Any, List, Iterable, Mapping, TYPE_CHECKING
|
|
4
5
|
import asyncio
|
|
5
6
|
import base64
|
|
6
7
|
import contextlib
|
|
@@ -11,6 +12,11 @@ from datetime import datetime, timezone
|
|
|
11
12
|
import aiohttp
|
|
12
13
|
|
|
13
14
|
from .config.agent_settings import AgentSettings
|
|
15
|
+
from .config.state_llm import (
|
|
16
|
+
StateLLMOverride,
|
|
17
|
+
resolve_effective_strategy,
|
|
18
|
+
validate_state_llm_overrides,
|
|
19
|
+
)
|
|
14
20
|
from .core.context import AgentContext
|
|
15
21
|
from .core.graph import AgentGraph
|
|
16
22
|
from .core.protocols import LLMStrategy, MemoryStrategy
|
|
@@ -136,7 +142,7 @@ class Agent:
|
|
|
136
142
|
actions: Optional[List[Any]] = None,
|
|
137
143
|
checkpoint_storage: Optional[Any] = None,
|
|
138
144
|
graph: Optional[AgentGraph] = None,
|
|
139
|
-
|
|
145
|
+
state_llm_overrides: Optional[Mapping[str, StateLLMOverride]] = None,
|
|
140
146
|
file_resolver: Optional[Any] = None,
|
|
141
147
|
status_llm: Optional[LLMStrategy] = None,
|
|
142
148
|
status_enter_labels: Optional[Dict[str, str]] = None,
|
|
@@ -163,9 +169,11 @@ class Agent:
|
|
|
163
169
|
``settings.enable_clarification``. Review is a fact of the
|
|
164
170
|
graph — an agent reviews its answers iff the graph has a
|
|
165
171
|
``critic`` node.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
172
|
+
state_llm_overrides: Map of graph node name → ``StateLLMOverride``
|
|
173
|
+
(model, full strategy, and/or reasoning effort). Validated at
|
|
174
|
+
construction against every graph this agent can execute;
|
|
175
|
+
before each turn, ``apply_state_llm_override`` installs the
|
|
176
|
+
node's effective strategy and effort.
|
|
169
177
|
file_resolver: Optional FileResolver for resolving file URLs
|
|
170
178
|
to bytes (used by the critic for image content).
|
|
171
179
|
status_enter_labels: node→text mapping for the deterministic
|
|
@@ -190,7 +198,19 @@ class Agent:
|
|
|
190
198
|
self.graph = graph or build_workflow(
|
|
191
199
|
clarification=self.settings.enable_clarification
|
|
192
200
|
)
|
|
193
|
-
|
|
201
|
+
# Per-node LLM overrides: validated here against every graph this
|
|
202
|
+
# agent can execute — its own, plus the lean sub graph that
|
|
203
|
+
# SubAgentTool forces onto delegates — then resolved once, so runtime
|
|
204
|
+
# reuses exactly the strategy objects that were validated.
|
|
205
|
+
_overrides = dict(state_llm_overrides or {})
|
|
206
|
+
validate_state_llm_overrides(
|
|
207
|
+
llm_strategy, _overrides, [self.graph, build_workflow(role="sub")]
|
|
208
|
+
)
|
|
209
|
+
self.state_llm_overrides = MappingProxyType(_overrides)
|
|
210
|
+
self._effective_llm = {
|
|
211
|
+
node: resolve_effective_strategy(llm_strategy, override)
|
|
212
|
+
for node, override in _overrides.items()
|
|
213
|
+
}
|
|
194
214
|
self.file_resolver = file_resolver
|
|
195
215
|
# Optional cheap side model that turns each turn into a one-line
|
|
196
216
|
# user-facing status update. None disables the feature entirely.
|
|
@@ -277,6 +297,22 @@ class Agent:
|
|
|
277
297
|
# per Agent instantiation.
|
|
278
298
|
_validate_managed_agents_acyclic(self)
|
|
279
299
|
|
|
300
|
+
def apply_state_llm_override(self, context: "AgentContext") -> None:
|
|
301
|
+
"""Install the current node's effective LLM configuration.
|
|
302
|
+
|
|
303
|
+
Called immediately before every paid turn — by ``run_streaming`` and
|
|
304
|
+
by ``SubAgentTool._execute_subagent`` — AFTER the node's ``on_enter``
|
|
305
|
+
installed its default hints, so an explicit override wins. A node
|
|
306
|
+
without an override runs the base strategy; a configured key absent
|
|
307
|
+
from the executing graph is skipped (valid on the agent's other
|
|
308
|
+
graph shape).
|
|
309
|
+
"""
|
|
310
|
+
node = context.current_node
|
|
311
|
+
context.llm = self._effective_llm.get(node, self.llm_strategy)
|
|
312
|
+
override = self.state_llm_overrides.get(node)
|
|
313
|
+
if override is not None and override.reasoning_effort is not None:
|
|
314
|
+
context.set_state_hint("reasoning_effort", override.reasoning_effort)
|
|
315
|
+
|
|
280
316
|
async def run(self, task: str) -> "FinalAnswerResult":
|
|
281
317
|
"""Run the agent on a single task and return the final answer.
|
|
282
318
|
|
|
@@ -1739,17 +1775,20 @@ class Agent:
|
|
|
1739
1775
|
)
|
|
1740
1776
|
turn_span.set_attribute("agent.task", context.task)
|
|
1741
1777
|
|
|
1742
|
-
#
|
|
1743
|
-
#
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1778
|
+
# Install the node's effective LLM configuration. Sits
|
|
1779
|
+
# before the retry loop so transient retries of this turn
|
|
1780
|
+
# keep one configuration; the next iteration re-resolves
|
|
1781
|
+
# because the turn may have routed to a different node.
|
|
1782
|
+
self.apply_state_llm_override(context)
|
|
1783
|
+
turn_span.set_attribute(
|
|
1784
|
+
"agent.llm.model",
|
|
1785
|
+
getattr(context.llm, "model", None) or "unknown",
|
|
1786
|
+
)
|
|
1787
|
+
_applied_effort = context.llm.applied_reasoning_effort(context)
|
|
1788
|
+
if _applied_effort is not None:
|
|
1789
|
+
turn_span.set_attribute(
|
|
1790
|
+
"agent.reasoning_effort", _applied_effort
|
|
1791
|
+
)
|
|
1753
1792
|
|
|
1754
1793
|
# Two retry classes wrap the turn: transient API errors
|
|
1755
1794
|
# (timeout, rate-limit, server error) so a network blip
|
|
@@ -1842,6 +1881,7 @@ class Agent:
|
|
|
1842
1881
|
reasoning=turn_result.reasoning,
|
|
1843
1882
|
model=getattr(context.llm, "model", None),
|
|
1844
1883
|
component=context.last_turn_component,
|
|
1884
|
+
reasoning_effort=context.last_applied_reasoning_effort,
|
|
1845
1885
|
agent_name=self.name,
|
|
1846
1886
|
)
|
|
1847
1887
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Configuration module for agent settings."""
|
|
2
|
+
|
|
3
|
+
from .agent_settings import AgentSettings
|
|
4
|
+
from .state_llm import (
|
|
5
|
+
StateLLMOverride,
|
|
6
|
+
resolve_effective_strategy,
|
|
7
|
+
validate_state_llm_overrides,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"AgentSettings",
|
|
12
|
+
"StateLLMOverride",
|
|
13
|
+
"resolve_effective_strategy",
|
|
14
|
+
"validate_state_llm_overrides",
|
|
15
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Per-graph-node LLM execution overrides.
|
|
2
|
+
|
|
3
|
+
``StateLLMOverride`` selects the model or full strategy and/or the reasoning
|
|
4
|
+
effort for one graph node. ``validate_state_llm_overrides`` is the public,
|
|
5
|
+
side-effect-free validator: ``Agent.__init__`` calls it, and a consuming
|
|
6
|
+
application's CI can call it against a versioned profile table without
|
|
7
|
+
constructing an ``Agent``. Rationale and contract:
|
|
8
|
+
``docs/architecture/state-llm-profiles.analysis.md``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import List, Mapping, Optional, Sequence, TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from ..core.graph import AgentGraph
|
|
18
|
+
from ..strategies.llm.base import BaseLLMStrategy
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"StateLLMOverride",
|
|
22
|
+
"resolve_effective_strategy",
|
|
23
|
+
"validate_state_llm_overrides",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class StateLLMOverride:
|
|
29
|
+
"""LLM execution override for one graph node.
|
|
30
|
+
|
|
31
|
+
Fields are independently optional: ``model`` shallow-clones the agent's
|
|
32
|
+
base strategy onto another model (same client/endpoint), ``strategy``
|
|
33
|
+
substitutes a full strategy object (different templates, endpoint, or
|
|
34
|
+
provider), and ``reasoning_effort`` overrides the hint installed by the
|
|
35
|
+
state's ``on_enter``. An omitted field inherits the current default.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
model: Optional[str] = None
|
|
39
|
+
strategy: Optional["BaseLLMStrategy"] = None
|
|
40
|
+
reasoning_effort: Optional[str] = None
|
|
41
|
+
|
|
42
|
+
def __post_init__(self) -> None:
|
|
43
|
+
if self.model is not None and self.strategy is not None:
|
|
44
|
+
raise ValueError("Set model or strategy, not both")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def resolve_effective_strategy(
|
|
48
|
+
base: "BaseLLMStrategy", override: Optional[StateLLMOverride]
|
|
49
|
+
) -> "BaseLLMStrategy":
|
|
50
|
+
"""The strategy a node executes with under ``override`` (pure)."""
|
|
51
|
+
if override is None:
|
|
52
|
+
return base
|
|
53
|
+
if override.strategy is not None:
|
|
54
|
+
return override.strategy
|
|
55
|
+
if override.model is not None:
|
|
56
|
+
return base.with_model(override.model)
|
|
57
|
+
return base
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def validate_state_llm_overrides(
|
|
61
|
+
base_strategy: "BaseLLMStrategy",
|
|
62
|
+
overrides: Mapping[str, StateLLMOverride],
|
|
63
|
+
graphs: Sequence["AgentGraph"],
|
|
64
|
+
) -> None:
|
|
65
|
+
"""Validate a full override mapping; raise one error naming every problem.
|
|
66
|
+
|
|
67
|
+
Pure and offline: resolves each entry's effective strategy and asks it to
|
|
68
|
+
validate the effort override, so effort support is checked against the
|
|
69
|
+
strategy/model that will actually execute. ``graphs`` is every graph the
|
|
70
|
+
agent can run; a key must name a node in at least one of them.
|
|
71
|
+
"""
|
|
72
|
+
known_nodes: set = set()
|
|
73
|
+
for graph in graphs:
|
|
74
|
+
known_nodes.update(graph.nodes)
|
|
75
|
+
|
|
76
|
+
problems: List[str] = []
|
|
77
|
+
for node, override in overrides.items():
|
|
78
|
+
if node not in known_nodes:
|
|
79
|
+
problems.append(
|
|
80
|
+
f"{node!r}: unknown graph node (known: {sorted(known_nodes)})"
|
|
81
|
+
)
|
|
82
|
+
if override.reasoning_effort is not None:
|
|
83
|
+
resolved = resolve_effective_strategy(base_strategy, override)
|
|
84
|
+
try:
|
|
85
|
+
resolved.validate_reasoning_effort_override(
|
|
86
|
+
override.reasoning_effort
|
|
87
|
+
)
|
|
88
|
+
except ValueError as exc:
|
|
89
|
+
problems.append(f"{node!r}: {exc}")
|
|
90
|
+
|
|
91
|
+
if problems:
|
|
92
|
+
raise ValueError("Invalid state_llm_overrides: " + "; ".join(problems))
|
|
@@ -224,6 +224,7 @@ class AgentContext:
|
|
|
224
224
|
self._last_turn_usage: Optional[TokenUsage] = None
|
|
225
225
|
self._last_turn_component: Optional[str] = None
|
|
226
226
|
self._last_turn_reasoning: Optional[str] = None
|
|
227
|
+
self._last_applied_reasoning_effort: Optional[str] = None
|
|
227
228
|
|
|
228
229
|
# Kernel state checkpoint tracking
|
|
229
230
|
self.checkpoint_key: Optional[str] = None
|
|
@@ -640,6 +641,20 @@ class AgentContext:
|
|
|
640
641
|
"""Component that acted in the most recent turn (main_agent/critic)."""
|
|
641
642
|
return self._last_turn_component
|
|
642
643
|
|
|
644
|
+
def set_last_applied_reasoning_effort(self, effort: Optional[str]) -> None:
|
|
645
|
+
"""Record the effort the strategy applied to this turn's LLM call.
|
|
646
|
+
|
|
647
|
+
Set by ``BaseLLMStrategy.generate_response`` at call time — post-turn
|
|
648
|
+
the graph has already transitioned, so hints no longer describe this
|
|
649
|
+
turn.
|
|
650
|
+
"""
|
|
651
|
+
self._last_applied_reasoning_effort = effort
|
|
652
|
+
|
|
653
|
+
@property
|
|
654
|
+
def last_applied_reasoning_effort(self) -> Optional[str]:
|
|
655
|
+
"""Applied effort of the most recent turn's own LLM call, if any."""
|
|
656
|
+
return self._last_applied_reasoning_effort
|
|
657
|
+
|
|
643
658
|
def set_last_reasoning(self, reasoning: Optional[str]) -> None:
|
|
644
659
|
"""Store the reasoning text from the most recent LLM call."""
|
|
645
660
|
self._last_turn_reasoning = reasoning
|
|
@@ -1063,6 +1078,7 @@ class AgentContext:
|
|
|
1063
1078
|
self._last_turn_usage = None
|
|
1064
1079
|
self._last_turn_component = None
|
|
1065
1080
|
self._last_turn_reasoning = None
|
|
1081
|
+
self._last_applied_reasoning_effort = None
|
|
1066
1082
|
|
|
1067
1083
|
# Capture the node identity BEFORE execution (routing moves it during
|
|
1068
1084
|
# handle()); the node name is the telemetry key — per-turn usage reads
|
|
@@ -185,6 +185,7 @@ class TurnCompletedEvent(AgentEvent):
|
|
|
185
185
|
reasoning: Optional[str] = None,
|
|
186
186
|
model: Optional[str] = None,
|
|
187
187
|
component: Optional[str] = None,
|
|
188
|
+
reasoning_effort: Optional[str] = None,
|
|
188
189
|
agent_name: str = "",
|
|
189
190
|
sub_conversation_id: Optional[str] = None,
|
|
190
191
|
delegation_id: Optional[str] = None,
|
|
@@ -201,6 +202,7 @@ class TurnCompletedEvent(AgentEvent):
|
|
|
201
202
|
# Which component acted this turn ("main_agent"/"critic"), so
|
|
202
203
|
# consumers can attribute the turn's usage per component live.
|
|
203
204
|
self.component = component
|
|
205
|
+
self.reasoning_effort = reasoning_effort
|
|
204
206
|
# Instance identity for sub-agent turns (lineage id + invocation id);
|
|
205
207
|
# both None on main-agent turns.
|
|
206
208
|
self.sub_conversation_id = sub_conversation_id
|
|
@@ -23,6 +23,14 @@ class LLMStrategy(Protocol):
|
|
|
23
23
|
"""Generate a response from the LLM based on the agent's history."""
|
|
24
24
|
...
|
|
25
25
|
|
|
26
|
+
def validate_reasoning_effort_override(self, value: str) -> None:
|
|
27
|
+
"""Raise ValueError unless the strategy can honor ``value`` at runtime."""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
def applied_reasoning_effort(self, context: "AgentContext") -> Optional[str]:
|
|
31
|
+
"""Provider-native effort this call applies; None = no runtime effort."""
|
|
32
|
+
...
|
|
33
|
+
|
|
26
34
|
def prepare_initial_history(self, context: "AgentContext") -> List["Message"]:
|
|
27
35
|
"""Creates the initial message history for the planning phase."""
|
|
28
36
|
...
|
|
@@ -7,9 +7,9 @@ markdown checklist, which is written to the ``task.md`` **artifact**
|
|
|
7
7
|
touches no closed-vocabulary kind; the checklist lives in the workspace manifest
|
|
8
8
|
and persists in the snapshot.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
sandbox-free — writing an artifact mutates
|
|
12
|
-
field), not the sandbox filesystem.
|
|
10
|
+
Runs on the base strategy unless a ``state_llm_overrides`` entry routes it
|
|
11
|
+
elsewhere. It is sandbox-free — writing an artifact mutates
|
|
12
|
+
``context.artifacts`` (a framework field), not the sandbox filesystem.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
from typing import List, Optional, TYPE_CHECKING
|
|
@@ -221,6 +221,10 @@ class BaseLLMStrategy:
|
|
|
221
221
|
- create_tool_response_message() for provider-specific formatting
|
|
222
222
|
- parse_assistant_response() if message structure differs significantly
|
|
223
223
|
- _extract_tool_call_args() for provider-specific argument extraction
|
|
224
|
+
|
|
225
|
+
Construction contract: creating a strategy performs no network I/O and
|
|
226
|
+
needs no live credentials, so configuration validators (e.g.
|
|
227
|
+
``validate_state_llm_overrides``) stay runnable in CI.
|
|
224
228
|
"""
|
|
225
229
|
|
|
226
230
|
#: Whether this strategy renders image parts (from the ``multimodal_parts``
|
|
@@ -297,6 +301,29 @@ class BaseLLMStrategy:
|
|
|
297
301
|
clone.model = model
|
|
298
302
|
return clone
|
|
299
303
|
|
|
304
|
+
def validate_reasoning_effort_override(self, value: str) -> None:
|
|
305
|
+
"""Raise ValueError unless this strategy can honor ``value`` at runtime.
|
|
306
|
+
|
|
307
|
+
Called on the RESOLVED per-node strategy during
|
|
308
|
+
``validate_state_llm_overrides`` — before any paid call. The base
|
|
309
|
+
default rejects, so a strategy that ignores the runtime effort hint
|
|
310
|
+
can never validate an override it would silently drop.
|
|
311
|
+
"""
|
|
312
|
+
raise ValueError(
|
|
313
|
+
f"{type(self).__name__} does not support runtime "
|
|
314
|
+
f"reasoning-effort overrides (got {value!r})"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def applied_reasoning_effort(self, context: "AgentContext") -> Optional[str]:
|
|
318
|
+
"""Provider-native description of the effort this call will apply.
|
|
319
|
+
|
|
320
|
+
``None`` means the strategy applies no runtime effort — telemetry
|
|
321
|
+
must then record nothing rather than echo the state hint. The
|
|
322
|
+
vocabulary is provider-native by design; consumers must not assume
|
|
323
|
+
the OpenAI scale.
|
|
324
|
+
"""
|
|
325
|
+
return None
|
|
326
|
+
|
|
300
327
|
# ------------------------------------------------------------------
|
|
301
328
|
# Response generation (template method)
|
|
302
329
|
# ------------------------------------------------------------------
|
|
@@ -311,6 +338,12 @@ class BaseLLMStrategy:
|
|
|
311
338
|
only the provider call in :meth:`_generate`; a strategy that merely
|
|
312
339
|
implements ``_generate`` is fully traced.
|
|
313
340
|
"""
|
|
341
|
+
# Captured at call time: by the time the driver builds the turn
|
|
342
|
+
# event, the graph has already transitioned and the hints belong to
|
|
343
|
+
# the next node.
|
|
344
|
+
context.set_last_applied_reasoning_effort(
|
|
345
|
+
self.applied_reasoning_effort(context)
|
|
346
|
+
)
|
|
314
347
|
# Identity attributes make a span self-describing in a mixed trace
|
|
315
348
|
# (main agent + sub-agents share one trace): who asked, from which
|
|
316
349
|
# graph node, on which turn.
|
|
@@ -386,13 +419,18 @@ class BaseLLMStrategy:
|
|
|
386
419
|
def _telemetry_invocation_parameters(
|
|
387
420
|
self, context: "AgentContext"
|
|
388
421
|
) -> Dict[str, Any]:
|
|
389
|
-
"""
|
|
390
|
-
|
|
422
|
+
"""Call parameters recorded as ``llm.invocation_parameters`` on the span.
|
|
423
|
+
|
|
424
|
+
The effort entry is the APPLIED value, not the state hint — a
|
|
425
|
+
strategy that ignores the hint records no effort at all.
|
|
426
|
+
"""
|
|
427
|
+
params: Dict[str, Any] = {
|
|
391
428
|
"tool_choice": context.get_state_hint("tool_choice", "auto"),
|
|
392
|
-
"reasoning_effort": context.get_state_hint(
|
|
393
|
-
"reasoning_effort", "medium"
|
|
394
|
-
),
|
|
395
429
|
}
|
|
430
|
+
effort = self.applied_reasoning_effort(context)
|
|
431
|
+
if effort is not None:
|
|
432
|
+
params["reasoning_effort"] = effort
|
|
433
|
+
return params
|
|
396
434
|
|
|
397
435
|
def _telemetry_tools(
|
|
398
436
|
self, context: "AgentContext"
|
|
@@ -462,7 +500,7 @@ class BaseLLMStrategy:
|
|
|
462
500
|
prompt_template = (
|
|
463
501
|
sub_agent_templates.get(f"task.{agent_name}")
|
|
464
502
|
or sub_agent_templates.get("task")
|
|
465
|
-
or "Create a plan to accomplish this task: {task}"
|
|
503
|
+
or "Create a plan to accomplish this task: {{ task }}"
|
|
466
504
|
)
|
|
467
505
|
rendered = render_template(
|
|
468
506
|
prompt_template,
|
|
@@ -125,7 +125,7 @@ class HarmonyLLMStrategy(BaseLLMStrategy):
|
|
|
125
125
|
def prepare_initial_history(self, context: "AgentContext") -> List["Message"]:
|
|
126
126
|
"""Creates the initial message history for the planning phase."""
|
|
127
127
|
initial_plan_template = self.templates.get("planning", {}).get(
|
|
128
|
-
"initial_plan", "Create a plan to accomplish this task: {task}"
|
|
128
|
+
"initial_plan", "Create a plan to accomplish this task: {{ task }}"
|
|
129
129
|
)
|
|
130
130
|
|
|
131
131
|
initial_plan = self._render_template(
|
|
@@ -234,7 +234,7 @@ class HarmonyLLMStrategy(BaseLLMStrategy):
|
|
|
234
234
|
) -> List["Message"]:
|
|
235
235
|
"""Build planning history with expert context from clarification."""
|
|
236
236
|
initial_plan_template = self.templates.get("planning", {}).get(
|
|
237
|
-
"initial_plan", "Create a plan to accomplish this task: {task}"
|
|
237
|
+
"initial_plan", "Create a plan to accomplish this task: {{ task }}"
|
|
238
238
|
)
|
|
239
239
|
initial_plan = self._render_template(
|
|
240
240
|
initial_plan_template,
|
|
@@ -308,7 +308,7 @@ class HarmonyLLMStrategy(BaseLLMStrategy):
|
|
|
308
308
|
"""Task-decomposition input for harmony: task + plan → a checklist."""
|
|
309
309
|
template = self.templates.get("task", {}).get(
|
|
310
310
|
"decompose",
|
|
311
|
-
"Break the plan into a concrete, checkable task list for the task: {task}",
|
|
311
|
+
"Break the plan into a concrete, checkable task list for the task: {{ task }}",
|
|
312
312
|
)
|
|
313
313
|
instructions = self._render_template(
|
|
314
314
|
template, self._get_template_variables(context)
|
|
@@ -413,7 +413,7 @@ class HarmonyLLMStrategy(BaseLLMStrategy):
|
|
|
413
413
|
) -> List["Message"]:
|
|
414
414
|
"""Build planning history from an already-enriched task brief (Harmony)."""
|
|
415
415
|
initial_plan_template = self.templates.get("planning", {}).get(
|
|
416
|
-
"initial_plan", "Create a plan to accomplish this task: {task}"
|
|
416
|
+
"initial_plan", "Create a plan to accomplish this task: {{ task }}"
|
|
417
417
|
)
|
|
418
418
|
initial_plan = self._render_template(
|
|
419
419
|
initial_plan_template,
|
|
@@ -71,6 +71,21 @@ def _coerce_to_dict(value: Any) -> Dict[str, Any]:
|
|
|
71
71
|
return {"type": "object", "properties": {}}
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def _reasoning_by_name(model: str) -> bool:
|
|
75
|
+
"""Name-prefix default for reasoning capability (first-party families).
|
|
76
|
+
|
|
77
|
+
Heterogeneous OpenAI-compatible catalogs (e.g. Azure AI Foundry hosting
|
|
78
|
+
DeepSeek/Qwen/Kimi models) defeat any name heuristic — callers declare
|
|
79
|
+
the capability via the ``reasoning_model`` constructor argument instead.
|
|
80
|
+
"""
|
|
81
|
+
return (
|
|
82
|
+
model.startswith("o1-")
|
|
83
|
+
or model.startswith("o3-")
|
|
84
|
+
or model.startswith("o4-")
|
|
85
|
+
or model.startswith("gpt-5")
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
74
89
|
class OpenAILLMStrategy(BaseLLMStrategy):
|
|
75
90
|
"""Provider strategy that bridges OpenAI's Responses API with internal message models."""
|
|
76
91
|
|
|
@@ -100,6 +115,7 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
100
115
|
azure_api_version: Optional[str] = None,
|
|
101
116
|
request_timeout: float = 300.0,
|
|
102
117
|
request_max_retries: int = 2,
|
|
118
|
+
reasoning_model: Optional[bool] = None,
|
|
103
119
|
) -> None:
|
|
104
120
|
super().__init__(
|
|
105
121
|
templates=templates,
|
|
@@ -140,12 +156,14 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
140
156
|
self.azure_api_version = azure_api_version
|
|
141
157
|
self.is_o1_model = self.model.startswith("o1-")
|
|
142
158
|
|
|
143
|
-
# Reasoning models support the reasoning.effort parameter
|
|
159
|
+
# Reasoning models support the reasoning.effort parameter. An
|
|
160
|
+
# explicit declaration wins over the name heuristic and survives
|
|
161
|
+
# with_model cloning.
|
|
162
|
+
self._reasoning_declared = reasoning_model
|
|
144
163
|
self.is_reasoning_model = (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
or self.model.startswith("gpt-5")
|
|
164
|
+
reasoning_model
|
|
165
|
+
if reasoning_model is not None
|
|
166
|
+
else _reasoning_by_name(self.model)
|
|
149
167
|
)
|
|
150
168
|
|
|
151
169
|
# ------------------------------------------------------------------
|
|
@@ -160,10 +178,9 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
160
178
|
clone.model = model
|
|
161
179
|
clone.is_o1_model = model.startswith("o1-")
|
|
162
180
|
clone.is_reasoning_model = (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
or model.startswith("gpt-5")
|
|
181
|
+
self._reasoning_declared
|
|
182
|
+
if self._reasoning_declared is not None
|
|
183
|
+
else _reasoning_by_name(model)
|
|
167
184
|
)
|
|
168
185
|
if api_version is not None:
|
|
169
186
|
clone.azure_api_version = api_version
|
|
@@ -185,6 +202,28 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
185
202
|
)
|
|
186
203
|
return clone
|
|
187
204
|
|
|
205
|
+
#: Provider's documented effort vocabulary — owned here, never in core.
|
|
206
|
+
_EFFORT_VALUES = frozenset({"none", "low", "medium", "high", "xhigh", "max"})
|
|
207
|
+
|
|
208
|
+
def validate_reasoning_effort_override(self, value: str) -> None:
|
|
209
|
+
if not self.is_reasoning_model:
|
|
210
|
+
raise ValueError(
|
|
211
|
+
f"model {self.model!r} is not reasoning-capable; a "
|
|
212
|
+
"reasoning-effort override would be silently dropped "
|
|
213
|
+
"(declare reasoning_model=True if the catalog model does "
|
|
214
|
+
"reason)"
|
|
215
|
+
)
|
|
216
|
+
if value not in self._EFFORT_VALUES:
|
|
217
|
+
raise ValueError(
|
|
218
|
+
f"unsupported reasoning effort {value!r} "
|
|
219
|
+
f"(known: {sorted(self._EFFORT_VALUES)})"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def applied_reasoning_effort(self, context: "AgentContext") -> Optional[str]:
|
|
223
|
+
if not self.is_reasoning_model:
|
|
224
|
+
return None
|
|
225
|
+
return context.get_state_hint("reasoning_effort", "medium")
|
|
226
|
+
|
|
188
227
|
async def _generate(self, context: "AgentContext") -> LLMResponse:
|
|
189
228
|
history = context.get_conversation_messages()
|
|
190
229
|
serialized_history = self._serialize_history(history)
|
|
@@ -295,7 +334,7 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
295
334
|
def prepare_initial_history(self, context: "AgentContext") -> List[Message]:
|
|
296
335
|
template = (
|
|
297
336
|
self.templates.get("planning", {}).get("initial_plan")
|
|
298
|
-
or "Create a plan to accomplish this task: {task}"
|
|
337
|
+
or "Create a plan to accomplish this task: {{ task }}"
|
|
299
338
|
)
|
|
300
339
|
initial_plan = self._render_template(
|
|
301
340
|
template,
|
|
@@ -354,7 +393,7 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
354
393
|
"""
|
|
355
394
|
template = (
|
|
356
395
|
self.templates.get("planning", {}).get("initial_plan")
|
|
357
|
-
or "Create a plan to accomplish this task: {task}"
|
|
396
|
+
or "Create a plan to accomplish this task: {{ task }}"
|
|
358
397
|
)
|
|
359
398
|
system_prompt = self._render_template(
|
|
360
399
|
template,
|
|
@@ -429,7 +468,7 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
429
468
|
"""
|
|
430
469
|
template = (
|
|
431
470
|
self.templates.get("task", {}).get("decompose")
|
|
432
|
-
or "Break the plan into a concrete, checkable task list for the task: {task}"
|
|
471
|
+
or "Break the plan into a concrete, checkable task list for the task: {{ task }}"
|
|
433
472
|
)
|
|
434
473
|
system_prompt = self._render_template(
|
|
435
474
|
template,
|
|
@@ -530,7 +569,7 @@ class OpenAILLMStrategy(BaseLLMStrategy):
|
|
|
530
569
|
"""
|
|
531
570
|
template = (
|
|
532
571
|
self.templates.get("planning", {}).get("initial_plan")
|
|
533
|
-
or "Create a plan to accomplish this task: {task}"
|
|
572
|
+
or "Create a plan to accomplish this task: {{ task }}"
|
|
534
573
|
)
|
|
535
574
|
system_prompt = self._render_template(
|
|
536
575
|
template,
|