agentbyte 0.30.0__tar.gz → 0.31.0__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.
- {agentbyte-0.30.0 → agentbyte-0.31.0}/CHANGELOG.md +53 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/PKG-INFO +4 -2
- {agentbyte-0.30.0 → agentbyte-0.31.0}/README.md +1 -1
- {agentbyte-0.30.0 → agentbyte-0.31.0}/pyproject.toml +3 -0
- agentbyte-0.31.0/src/agentbyte/__about__.py +2 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/agent.py +143 -47
- agentbyte-0.31.0/src/agentbyte/compaction/__init__.py +41 -0
- agentbyte-0.31.0/src/agentbyte/compaction/counters.py +192 -0
- agentbyte-0.31.0/src/agentbyte/compaction/errors.py +44 -0
- agentbyte-0.31.0/src/agentbyte/compaction/grouping.py +112 -0
- agentbyte-0.31.0/src/agentbyte/compaction/strategies.py +188 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/sqlite.py +7 -2
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/sqlite_db.py +7 -2
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/llm.py +13 -8
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/pairwise.py +11 -3
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/trajectory.py +11 -7
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/validation.py +29 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/pairwise.py +7 -2
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/runner.py +15 -1
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/model.py +3 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/types.py +10 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/messages.py +8 -1
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/__init__.py +2 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/base.py +226 -68
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/core_tools.py +1 -1
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/types.py +35 -3
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/__init__.py +8 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/checkpoint.py +88 -15
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/models.py +36 -5
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/runner.py +176 -94
- agentbyte-0.31.0/src/agentbyte/workflow/errors.py +13 -0
- agentbyte-0.31.0/src/agentbyte/workflow/sqlite_checkpoint.py +166 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/step.py +31 -2
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/subworkflow.py +62 -53
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_as_tool.py +48 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_tool_approval.py +7 -0
- agentbyte-0.31.0/tests/agents/test_tool_batch_resolution.py +274 -0
- agentbyte-0.31.0/tests/agents/test_tool_metadata.py +121 -0
- agentbyte-0.31.0/tests/compaction/test_compaction.py +360 -0
- agentbyte-0.31.0/tests/eval/test_score_integrity.py +409 -0
- agentbyte-0.31.0/tests/examples/test_compaction_webapp.py +109 -0
- agentbyte-0.31.0/tests/middleware/test_context_compaction.py +607 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_middleware_chain.py +0 -103
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/tools/test_tools.py +11 -0
- agentbyte-0.31.0/tests/workflow/recovery_worker.py +47 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_subworkflow_step.py +6 -7
- agentbyte-0.31.0/tests/workflow/test_workflow_reliability.py +561 -0
- agentbyte-0.30.0/src/agentbyte/__about__.py +0 -2
- agentbyte-0.30.0/tests/eval/test_score_integrity.py +0 -194
- {agentbyte-0.30.0 → agentbyte-0.31.0}/.gitignore +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/LICENSE +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/embedding_agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/agents/types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/cancellation_token.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/catalog.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/cli/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/cli/main.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/component.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/context.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/context_providers/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/context_providers/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/context_providers/skills.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/config.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/importer.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/json.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/loader.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/publish.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/publish_config.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/publishers.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/sources.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/write_config.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/dataset/writers.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/entity.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/decorator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/keyword.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/local.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/process.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/tool.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/checks/types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/comparison.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/eval_dataset.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/composite.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/judges/reference.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/report.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/splitting.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/runtime.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/eval/targets/workflow.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/execution_trace/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/execution_trace/collector.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/execution_trace/models.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/_retry_observability.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/auth.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure/auth.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure/chat.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure/embedding.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure/settings.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure_openai.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/embeddings_base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/openai/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/openai/chat.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/openai/embedding.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/openai/settings.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/openai_embedding.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/pricing.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/retry_policy.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/settings.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/llm/types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/logger.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/memory/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/memory/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/otel.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/retry.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/sql_usage.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/middleware/usage_logger.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/notebook.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/config.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/gepa.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/mipro.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/pareto.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/reflective.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/spec.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/optim/trace.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/ai.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/handoff.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/plan.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/policies.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/orchestration/round_robin.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/agents.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/clients.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instruction_registry.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/orchestration.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/streaming.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/presets/workflow.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/session_store.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/resources.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/scripts.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/sources.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/skills/validation.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/cancellation.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/composite.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/external.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/function_call.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/handoff.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/max_message.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/predicate.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/source.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/text_mention.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/timeout.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/termination/token_usage.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/coding_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/decorator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/memory_tool.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/tools/research_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/discovery.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/execution.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/models.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/registry.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/server.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/session_store.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/sessions.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/ui/assets/index-BF3DwXaF.js +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/ui/assets/index-ar5tOeqt.css +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/ui/index.html +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/webui/ui/vite.svg +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/core/workflow.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/defaults.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/loader.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/schema.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/schema_utils.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/echo.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/function.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/http.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/steps/transform.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/src/agentbyte/workflow/visualizer.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_basic.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_context_providers.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_error_response.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_event_types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_memory_integration.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_middleware_integration.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_response_accessors.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_retry_middleware.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_agent_stream_events.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/agents/test_embedding_agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/cli/test_registry_check.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/context_providers/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/context_providers/test_skill_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/context_providers/test_skills_provider.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/dataset/test_loader.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/dataset/test_multi_table.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/dataset/test_publish.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/dataset/test_sqlite_db.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_eval_dataset.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_execution_trajectories.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_multi_turn.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_pairwise.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_splitting.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/eval/test_types_and_judges.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_azure_client.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_azure_embedding_client.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_llm_types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_openai_client.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_openai_embedding_client.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_pricing.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_retry_observability.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_retry_policy_api.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/llm/test_retryable_error_substrings.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/memory/test_memory.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_deduplicate_tool_result.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_otel.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_retry_middleware.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_sql_usage.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/middleware/test_usage_logger.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_base_integration.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_config.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_gepa.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_mipro.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_pareto.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_reflective.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_score_integrity.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_spec.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/optim/test_trace.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_base_orchestrator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_orchestrator_finalization.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/orchestration/test_round_robin.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_agents.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_clients.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_instruction_registry.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_orchestration.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_streaming.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/presets/test_workflow.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/skills/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/skills/test_base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/skills/test_resources.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/skills/test_scripts.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/skills/test_sources.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_base.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_cancellation.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_composite.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_consecutive_agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_external.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_function_call.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_handoff.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_max_message.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_predicate.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_source.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_text_mention.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_timeout.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/termination/test_token_usage.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_cancellation_token.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_context.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_logger.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_messages.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_package_api.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_session_store.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_types.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/test_vanilla_chunker.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/tools/test_coding_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/tools/test_memory_tool.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/tools/test_research_tools.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/__init__.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/helpers.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_execution.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_package_api.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_registry.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_server.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_sessions.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/webui/test_workflow_streaming.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_agent_step_imports.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_checkpoint.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_agent.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_class.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_models.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_runner.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_schema.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_steps.py +0 -0
- {agentbyte-0.30.0 → agentbyte-0.31.0}/tests/workflow/test_workflow_visualizer.py +0 -0
|
@@ -4,6 +4,59 @@ All notable changes to Agentbyte are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format follows Keep a Changelog principles and semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.31.0] - 2026-09-30
|
|
10
|
+
|
|
11
|
+
Upgrade notes (breaking):
|
|
12
|
+
|
|
13
|
+
- `ContextCompactionMiddleware(max_tokens=..., keep_last=...)` → `ContextCompactionMiddleware(max_input_tokens=...)`; read counts from `metadata["compaction"]`.
|
|
14
|
+
- Middleware that rewrites a `model_call` payload must keep its keys: `context.data = {**context.data, "messages": new}`.
|
|
15
|
+
- Multi-call approval batches return every approval request at once; loop over `response.approval_requests`.
|
|
16
|
+
- Workflow steps must write back changed state explicitly (`context.set(...)`); in-place mutation of a value read from `WorkflowContext` no longer persists.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Workflow reliability (spec 0058): optional native-async `SQLiteCheckpointStore` (new `workflow-sqlite` extra, lazily imported driver) with immutable checkpoint IDs and per-run retention; checkpoint schema v2 with staged continuation and accepted responses (v1 checkpoints still load); `CheckpointStore.load_latest(..., execution_id=...)`; multiple nested input requests per step with batch validation and partial resume (`BaseStep.resume_from_requests`, `validate_resume_responses`); `WorkflowStateIsolationError`, `WorkflowCheckpointError`, `CheckpointConflictError`.
|
|
21
|
+
- Context compaction (spec 0049): new `agentbyte.compaction` package with `HeadTailCompaction`, `SlidingWindowCompaction`, `CharacterTokenCounter`, optional `TiktokenCounter` and `CompactionResult`. Tool-call batches and their results are kept or removed whole; system messages and the current turn are always kept; the budget covers messages, tools and output schema. Mandatory content that cannot fit raises `ContextBudgetExceeded` before any provider call.
|
|
22
|
+
- `BaseMiddleware.finalize_request` and `validate_request` hooks: after every `process_request`, the chain runs all `finalize_request` hooks (may change the payload), then all read-only `validate_request` hooks, immediately before the operation. A validator that changes the payload raises `MiddlewareContractError`.
|
|
23
|
+
- Tool message metadata (spec 0056): `ToolMessage.metadata` keeps an independent copy of the final `ToolResult.metadata` (e.g. `AgentAsTool` child usage) across run, streaming, approval resume and failed results. Sessions and checkpoints preserve it; model-provider requests never include it. Records without the field load as `{}`.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Breaking:** the agent no longer falls back to its own messages, tools or output format when middleware removes those keys from a `model_call` payload; a missing key raises. Set a key to `None` to omit it.
|
|
28
|
+
- Passing a new task while the conversation ends with an unresolved tool-call batch now ends the run with `finish_reason="error"` instead of sending an invalid history; resume with `task=None` first.
|
|
29
|
+
- **Breaking:** `ContextCompactionMiddleware` now takes keyword-only `max_input_tokens` (required), `strategy` and `counter`; `max_tokens` and `keep_last` were removed without aliases, and the fabricated summary placeholder is gone. Malformed, orphan or unresolved tool exchanges now raise `ToolExchangeError`/`PendingToolExchangeError` instead of being sent. Metadata moved to `metadata["compaction"]`, with per-pass counts in `passes`.
|
|
30
|
+
- **Breaking:** `ToolResult.metadata` and `ToolMessage.metadata` accept JSON values only (string-keyed objects, lists, strings, finite numbers, booleans, null). Tuples, enums, non-string keys, `Path`, `datetime`, models, NaN/inf raise `ToolMetadataError` (a `TypeError`); a custom tool producing such metadata now fails its call instead of succeeding.
|
|
31
|
+
- Tool metadata is now present on every `ToolMessage` sent by the WebUI server and stored in sessions, not only in verbose tool-response events.
|
|
32
|
+
- `CalculatorTool` no longer duplicates the computed value in metadata, so non-finite and complex results still succeed.
|
|
33
|
+
- **Breaking:** workflow staged state is isolated: `WorkflowContext` reads return detached copies, so steps must write changes back explicitly; values that cannot be isolated raise `WorkflowStateIsolationError`. Checkpoints are taken at quiescent recovery boundaries, and persistence failures stop the run with `WorkflowCheckpointError` instead of continuing unsaved.
|
|
34
|
+
- `FileCheckpointStore` is deprecated (legacy blocking backend); use `SQLiteCheckpointStore` or an application durable store. Migration guidance is in the workflow skill and checkpoint study topic. FastAPI still persists through its session store.
|
|
35
|
+
|
|
36
|
+
### Documentation
|
|
37
|
+
|
|
38
|
+
- Context compaction notebook (`notebooks/concepts/agent/10-context-compaction.ipynb`) and FastAPI example (`examples/compaction/`) showing budgets, 413/409 mapping, turn rollback, SSE and a context meter.
|
|
39
|
+
- Proposed spec 0059 (summarizing compaction).
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- Multi-call tool batches stay complete across approval pauses: calls after the first approval-gated call are no longer skipped (previously the model received tool calls without results after resume). All gated calls in a batch request approval in one round; resume runs the rest in original order; missing decisions keep `approval_needed` without a model call.
|
|
44
|
+
- Cancelling mid-batch records a failed `ToolMessage` (`error="Cancelled"`) for each call that did not run, so the session stays valid for the next task.
|
|
45
|
+
|
|
46
|
+
## [0.30.1] - 2026-09-30
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Judge score integrity follow-ups (spec 0055 v0.3.0): judges re-check cancellation after each model call, and `EvalRunner`/`PairwiseRunner` record a run as `cancelled` without judging it when the token is cancelled or the trajectory has `execution_status="cancelled"`.
|
|
51
|
+
- Raw-JSON judge responses with duplicate keys are rejected (`duplicate_criterion` for `LLMEvalJudge`, `invalid_response` for `PairwiseJudge`) instead of keeping the last value.
|
|
52
|
+
- When a target raises, `EvalRunner` and `PairwiseRunner` store only the exception type in `trajectory.error`, never the exception message.
|
|
53
|
+
- `ModelEvalTarget` records `execution_status` on failed and cancelled trajectories.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- **Breaking:** `criteria=None` selects judge defaults; an explicit empty list raises `JudgeScoringError("invalid_criteria")`. An empty `default_criteria` (`LLMEvalJudge`, `LLMTrajectoryJudge`) or `criteria` (`PairwiseJudge`) raises `ValueError` at construction.
|
|
58
|
+
- **Breaking:** a scored `EvalScore` carrying legacy `fallback` or `judge_failed` metadata fails validation.
|
|
59
|
+
|
|
7
60
|
## [0.30.0] - 2026-09-30
|
|
8
61
|
|
|
9
62
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentbyte
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.31.0
|
|
4
4
|
Summary: A toolkit for designing multiagent systems
|
|
5
5
|
Author-email: MrDataPsycho <mr.data.psycho@gmail.com>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -80,13 +80,15 @@ Requires-Dist: graphviz>=0.21; extra == 'viz'
|
|
|
80
80
|
Provides-Extra: webui
|
|
81
81
|
Requires-Dist: fastapi>=0.135.2; extra == 'webui'
|
|
82
82
|
Requires-Dist: uvicorn[standard]>=0.44.0; extra == 'webui'
|
|
83
|
+
Provides-Extra: workflow-sqlite
|
|
84
|
+
Requires-Dist: aiosqlite>=0.22.1; extra == 'workflow-sqlite'
|
|
83
85
|
Description-Content-Type: text/markdown
|
|
84
86
|
|
|
85
87
|
# Agentbyte
|
|
86
88
|
|
|
87
89
|
Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
|
|
88
90
|
|
|
89
|
-
Current release: **0.
|
|
91
|
+
Current release: **0.31.0**
|
|
90
92
|
|
|
91
93
|
## Building an Agent
|
|
92
94
|
|
|
@@ -234,6 +234,7 @@ class Agent(BaseAgent):
|
|
|
234
234
|
tool_name=tool_call.tool_name,
|
|
235
235
|
success=streamed_result.success,
|
|
236
236
|
error=streamed_result.error,
|
|
237
|
+
metadata=streamed_result.metadata,
|
|
237
238
|
)
|
|
238
239
|
working_context.add_message(tool_message)
|
|
239
240
|
yield tool_message
|
|
@@ -317,6 +318,7 @@ class Agent(BaseAgent):
|
|
|
317
318
|
tool_name=tool_call.tool_name,
|
|
318
319
|
success=result.success,
|
|
319
320
|
error=result.error,
|
|
321
|
+
metadata=result.metadata,
|
|
320
322
|
)
|
|
321
323
|
except Exception as exc:
|
|
322
324
|
message = ToolMessage(
|
|
@@ -339,6 +341,102 @@ class Agent(BaseAgent):
|
|
|
339
341
|
|
|
340
342
|
yield message
|
|
341
343
|
|
|
344
|
+
@staticmethod
|
|
345
|
+
def _unresolved_tail_calls(working_context: AgentContext) -> List[ToolCallRequest]:
|
|
346
|
+
"""Calls of the newest tool-call batch that have no result yet, in order.
|
|
347
|
+
|
|
348
|
+
Only a batch followed exclusively by tool results counts; results are
|
|
349
|
+
matched to that batch occurrence, not to earlier reuses of a call ID.
|
|
350
|
+
"""
|
|
351
|
+
resolved: set[str] = set()
|
|
352
|
+
for message in reversed(working_context.messages):
|
|
353
|
+
if isinstance(message, ToolMessage):
|
|
354
|
+
resolved.add(message.tool_call_id)
|
|
355
|
+
continue
|
|
356
|
+
if isinstance(message, AssistantMessage) and message.tool_calls:
|
|
357
|
+
return [c for c in message.tool_calls if c.call_id not in resolved]
|
|
358
|
+
return []
|
|
359
|
+
return []
|
|
360
|
+
|
|
361
|
+
def _awaits_approval(
|
|
362
|
+
self,
|
|
363
|
+
tool_call: ToolCallRequest,
|
|
364
|
+
working_context: AgentContext,
|
|
365
|
+
extra_tools: Optional[List[BaseTool]],
|
|
366
|
+
) -> bool:
|
|
367
|
+
"""Whether *tool_call* needs an approval decision that does not exist yet."""
|
|
368
|
+
tool = self._find_tool(tool_call.tool_name, extra_tools=extra_tools)
|
|
369
|
+
return (
|
|
370
|
+
tool is not None
|
|
371
|
+
and tool.approval_mode == ApprovalMode.ALWAYS
|
|
372
|
+
and working_context.get_approval_response(tool_call.call_id) is None
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
async def _resolve_tool_batch(
|
|
376
|
+
self,
|
|
377
|
+
working_context: AgentContext,
|
|
378
|
+
cancellation_token: Optional[CancellationToken],
|
|
379
|
+
verbose: bool,
|
|
380
|
+
extra_tools: Optional[List[BaseTool]],
|
|
381
|
+
outcome: dict[str, int | bool],
|
|
382
|
+
) -> AsyncGenerator[Union[Message, AgentEvent], None]:
|
|
383
|
+
"""Execute the newest batch's unresolved calls in their original order.
|
|
384
|
+
|
|
385
|
+
Execution stops before the first call still awaiting approval; approval
|
|
386
|
+
requests for every such call in the batch are registered together, so a
|
|
387
|
+
single decision round resolves the batch. Calls left unexecuted because
|
|
388
|
+
of cancellation receive an explicit failed result, keeping the batch
|
|
389
|
+
complete. ``outcome`` reports ``executed`` and ``paused``.
|
|
390
|
+
"""
|
|
391
|
+
pending = self._unresolved_tail_calls(working_context)
|
|
392
|
+
awaiting = [
|
|
393
|
+
c for c in pending if self._awaits_approval(c, working_context, extra_tools)
|
|
394
|
+
]
|
|
395
|
+
stop_at = awaiting[0].call_id if awaiting else None
|
|
396
|
+
|
|
397
|
+
for tool_call in pending:
|
|
398
|
+
if tool_call.call_id == stop_at:
|
|
399
|
+
break
|
|
400
|
+
outcome["executed"] = int(outcome["executed"]) + 1
|
|
401
|
+
try:
|
|
402
|
+
async for item in self._execute_tool_call(
|
|
403
|
+
tool_call,
|
|
404
|
+
working_context,
|
|
405
|
+
cancellation_token,
|
|
406
|
+
verbose,
|
|
407
|
+
extra_tools=extra_tools,
|
|
408
|
+
):
|
|
409
|
+
yield item
|
|
410
|
+
if isinstance(item, ToolApprovalEvent):
|
|
411
|
+
outcome["paused"] = True
|
|
412
|
+
return
|
|
413
|
+
except asyncio.CancelledError:
|
|
414
|
+
for skipped in self._unresolved_tail_calls(working_context):
|
|
415
|
+
working_context.add_message(
|
|
416
|
+
ToolMessage(
|
|
417
|
+
content="Tool execution cancelled before it ran",
|
|
418
|
+
source=self.name,
|
|
419
|
+
tool_call_id=skipped.call_id,
|
|
420
|
+
tool_name=skipped.tool_name,
|
|
421
|
+
success=False,
|
|
422
|
+
error="Cancelled",
|
|
423
|
+
)
|
|
424
|
+
)
|
|
425
|
+
raise
|
|
426
|
+
|
|
427
|
+
if not awaiting:
|
|
428
|
+
return
|
|
429
|
+
|
|
430
|
+
outcome["paused"] = True
|
|
431
|
+
for tool_call in awaiting:
|
|
432
|
+
if tool_call.call_id in working_context.pending_tool_calls:
|
|
433
|
+
continue # already requested in an earlier run
|
|
434
|
+
request = working_context.add_approval_request(
|
|
435
|
+
tool_call=tool_call,
|
|
436
|
+
tool_name=tool_call.tool_name,
|
|
437
|
+
)
|
|
438
|
+
yield ToolApprovalEvent(source=self.name, approval_request=request)
|
|
439
|
+
|
|
342
440
|
@trace_stream("agent")
|
|
343
441
|
async def run_stream(
|
|
344
442
|
self,
|
|
@@ -428,6 +526,11 @@ class Agent(BaseAgent):
|
|
|
428
526
|
|
|
429
527
|
try:
|
|
430
528
|
task_messages = self._convert_task_to_messages(task) if task else []
|
|
529
|
+
if task_messages and self._unresolved_tail_calls(working_context):
|
|
530
|
+
raise AgentExecutionError(
|
|
531
|
+
"The conversation ends with unresolved tool calls; resolve pending "
|
|
532
|
+
"approvals by resuming with task=None before sending a new task."
|
|
533
|
+
)
|
|
431
534
|
for message in task_messages:
|
|
432
535
|
working_context.add_message(message)
|
|
433
536
|
|
|
@@ -453,32 +556,22 @@ class Agent(BaseAgent):
|
|
|
453
556
|
if cancellation_token and cancellation_token.is_cancelled():
|
|
454
557
|
raise asyncio.CancelledError()
|
|
455
558
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
async for item in self._execute_tool_call(
|
|
462
|
-
approved_call,
|
|
559
|
+
# Resume: finish the newest tool-call batch (approved, denied and
|
|
560
|
+
# not-yet-run siblings, in order) before asking the model again.
|
|
561
|
+
if self._unresolved_tail_calls(working_context):
|
|
562
|
+
outcome: dict[str, int | bool] = {"executed": 0, "paused": False}
|
|
563
|
+
async for item in self._resolve_tool_batch(
|
|
463
564
|
working_context,
|
|
464
565
|
cancellation_token,
|
|
465
566
|
verbose,
|
|
466
|
-
|
|
467
|
-
|
|
567
|
+
provider_tools,
|
|
568
|
+
outcome,
|
|
468
569
|
):
|
|
469
570
|
yield item
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
source=self.name,
|
|
475
|
-
tool_call_id=rejected_call_id,
|
|
476
|
-
tool_name=rejected_call.tool_name,
|
|
477
|
-
success=False,
|
|
478
|
-
error="Approval denied",
|
|
479
|
-
)
|
|
480
|
-
working_context.add_message(denial_message)
|
|
481
|
-
yield denial_message
|
|
571
|
+
tool_calls += int(outcome["executed"])
|
|
572
|
+
if outcome["paused"]:
|
|
573
|
+
finish_reason = "approval_needed"
|
|
574
|
+
break
|
|
482
575
|
|
|
483
576
|
llm_messages = await self._prepare_llm_messages([], working_context, extra_instructions=extra_instructions)
|
|
484
577
|
if self.memory is not None:
|
|
@@ -560,11 +653,25 @@ class Agent(BaseAgent):
|
|
|
560
653
|
break
|
|
561
654
|
|
|
562
655
|
async def _execute_model_call(payload: dict[str, object]):
|
|
563
|
-
|
|
656
|
+
# Send exactly the final middleware payload: falling back to
|
|
657
|
+
# the agent's own values would bypass request validation
|
|
658
|
+
# (e.g. compaction budgets) done on that payload.
|
|
659
|
+
missing = [
|
|
660
|
+
key
|
|
661
|
+
for key in ("messages", "tools", "output_format")
|
|
662
|
+
if key not in payload
|
|
663
|
+
]
|
|
664
|
+
if missing:
|
|
665
|
+
raise ValueError(
|
|
666
|
+
f"model_call payload is missing {missing}; middleware "
|
|
667
|
+
"must preserve payload keys (set a key to None to omit it)"
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
payload_messages = payload["messages"]
|
|
564
671
|
if not isinstance(payload_messages, list):
|
|
565
672
|
raise ValueError("model_call payload messages must be a list")
|
|
566
673
|
|
|
567
|
-
payload_tools = payload
|
|
674
|
+
payload_tools = payload["tools"]
|
|
568
675
|
if payload_tools is not None and not isinstance(
|
|
569
676
|
payload_tools, list
|
|
570
677
|
):
|
|
@@ -572,9 +679,7 @@ class Agent(BaseAgent):
|
|
|
572
679
|
"model_call payload tools must be a list or None"
|
|
573
680
|
)
|
|
574
681
|
|
|
575
|
-
payload_output_format = payload
|
|
576
|
-
"output_format", self.output_format
|
|
577
|
-
)
|
|
682
|
+
payload_output_format = payload["output_format"]
|
|
578
683
|
if payload_output_format is not None and not isinstance(
|
|
579
684
|
payload_output_format, type
|
|
580
685
|
):
|
|
@@ -667,27 +772,18 @@ class Agent(BaseAgent):
|
|
|
667
772
|
finish_reason = "max_iterations_finalized"
|
|
668
773
|
break
|
|
669
774
|
|
|
670
|
-
|
|
671
|
-
for
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if isinstance(item, ToolApprovalEvent):
|
|
683
|
-
finish_reason = "approval_needed"
|
|
684
|
-
approval_pause = True
|
|
685
|
-
break
|
|
686
|
-
|
|
687
|
-
if approval_pause:
|
|
688
|
-
break
|
|
689
|
-
|
|
690
|
-
if approval_pause:
|
|
775
|
+
outcome = {"executed": 0, "paused": False}
|
|
776
|
+
async for item in self._resolve_tool_batch(
|
|
777
|
+
working_context,
|
|
778
|
+
cancellation_token,
|
|
779
|
+
verbose,
|
|
780
|
+
provider_tools,
|
|
781
|
+
outcome,
|
|
782
|
+
):
|
|
783
|
+
yield item
|
|
784
|
+
tool_calls += int(outcome["executed"])
|
|
785
|
+
if outcome["paused"]:
|
|
786
|
+
finish_reason = "approval_needed"
|
|
691
787
|
break
|
|
692
788
|
|
|
693
789
|
if not self.summarize_tool_result:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Context compaction that keeps outbound conversations provider-valid.
|
|
2
|
+
|
|
3
|
+
Strategies select whole message groups (a tool request and all its results are
|
|
4
|
+
one group) so that a complete model-call request fits an input-token budget,
|
|
5
|
+
or raise :class:`ContextBudgetExceeded` before any provider I/O.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from agentbyte.compaction.counters import (
|
|
9
|
+
CharacterTokenCounter,
|
|
10
|
+
TiktokenCounter,
|
|
11
|
+
TokenCounter,
|
|
12
|
+
)
|
|
13
|
+
from agentbyte.compaction.errors import (
|
|
14
|
+
CompactionError,
|
|
15
|
+
ContextBudgetExceeded,
|
|
16
|
+
PendingToolExchangeError,
|
|
17
|
+
ToolExchangeError,
|
|
18
|
+
)
|
|
19
|
+
from agentbyte.compaction.grouping import MessageGroup, group_messages
|
|
20
|
+
from agentbyte.compaction.strategies import (
|
|
21
|
+
CompactionResult,
|
|
22
|
+
CompactionStrategy,
|
|
23
|
+
HeadTailCompaction,
|
|
24
|
+
SlidingWindowCompaction,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"CharacterTokenCounter",
|
|
29
|
+
"CompactionError",
|
|
30
|
+
"CompactionResult",
|
|
31
|
+
"CompactionStrategy",
|
|
32
|
+
"ContextBudgetExceeded",
|
|
33
|
+
"HeadTailCompaction",
|
|
34
|
+
"MessageGroup",
|
|
35
|
+
"PendingToolExchangeError",
|
|
36
|
+
"SlidingWindowCompaction",
|
|
37
|
+
"TiktokenCounter",
|
|
38
|
+
"TokenCounter",
|
|
39
|
+
"ToolExchangeError",
|
|
40
|
+
"group_messages",
|
|
41
|
+
]
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Token counters used to budget complete model-call requests.
|
|
2
|
+
|
|
3
|
+
Counts are estimates: they approximate, but never promise, provider-exact
|
|
4
|
+
token usage. Text is counted as text (Unicode code points / tokenizer tokens),
|
|
5
|
+
never as escaped JSON sequences, and internal metadata that is not sent to
|
|
6
|
+
providers (for example ``ToolMessage.metadata``) is excluded.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import math
|
|
13
|
+
from abc import ABC, abstractmethod
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
from agentbyte.messages import (
|
|
19
|
+
AssistantMessage,
|
|
20
|
+
MultiModalMessage,
|
|
21
|
+
SystemMessage,
|
|
22
|
+
ToolMessage,
|
|
23
|
+
UserMessage,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
_KNOWN_MESSAGE_TYPES = (
|
|
27
|
+
SystemMessage,
|
|
28
|
+
UserMessage,
|
|
29
|
+
AssistantMessage,
|
|
30
|
+
ToolMessage,
|
|
31
|
+
MultiModalMessage,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _to_json_text(value: Any) -> str:
|
|
36
|
+
"""Serialize *value* compactly without escaping non-ASCII characters."""
|
|
37
|
+
return json.dumps(value, ensure_ascii=False, sort_keys=True, default=str)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TokenCounter(ABC):
|
|
41
|
+
"""Counts tokens for every component of a model-call request.
|
|
42
|
+
|
|
43
|
+
Subclasses implement :meth:`count_text`; message, tool and schema counting
|
|
44
|
+
is shared so that every counter budgets the same request components.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
#: Label recorded in results and metadata (e.g. ``"character_estimate"``).
|
|
48
|
+
kind: str = "custom"
|
|
49
|
+
|
|
50
|
+
def __init__(self, *, message_overhead: int = 4, media_tokens: int = 1_000):
|
|
51
|
+
if message_overhead < 0:
|
|
52
|
+
raise ValueError("message_overhead must be non-negative")
|
|
53
|
+
if media_tokens < 0:
|
|
54
|
+
raise ValueError("media_tokens must be non-negative")
|
|
55
|
+
self.message_overhead = message_overhead
|
|
56
|
+
self.media_tokens = media_tokens
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def count_text(self, text: str) -> int:
|
|
60
|
+
"""Return the token count for plain *text*."""
|
|
61
|
+
|
|
62
|
+
def count_message(self, message: Any) -> int:
|
|
63
|
+
"""Count one outbound message, including tool-call arguments and media.
|
|
64
|
+
|
|
65
|
+
Messages of unknown types are never interpreted: their whole serialized
|
|
66
|
+
form is counted, so the budget errs towards overcounting.
|
|
67
|
+
"""
|
|
68
|
+
if not isinstance(message, _KNOWN_MESSAGE_TYPES):
|
|
69
|
+
opaque = (
|
|
70
|
+
message.model_dump_json()
|
|
71
|
+
if isinstance(message, BaseModel)
|
|
72
|
+
else str(message)
|
|
73
|
+
)
|
|
74
|
+
return self.message_overhead + self.count_text(opaque)
|
|
75
|
+
|
|
76
|
+
tokens = self.message_overhead
|
|
77
|
+
content = getattr(message, "content", None)
|
|
78
|
+
if isinstance(content, str):
|
|
79
|
+
tokens += self.count_text(content)
|
|
80
|
+
elif content is not None:
|
|
81
|
+
tokens += self.count_text(_to_json_text(content))
|
|
82
|
+
|
|
83
|
+
if isinstance(message, AssistantMessage) and message.tool_calls:
|
|
84
|
+
for call in message.tool_calls:
|
|
85
|
+
tokens += self.count_text(call.tool_name)
|
|
86
|
+
tokens += self.count_text(call.call_id)
|
|
87
|
+
tokens += self.count_text(_to_json_text(call.parameters))
|
|
88
|
+
elif isinstance(message, ToolMessage):
|
|
89
|
+
tokens += self.count_text(message.tool_call_id)
|
|
90
|
+
elif isinstance(message, MultiModalMessage):
|
|
91
|
+
if message.is_text() and message.data is not None:
|
|
92
|
+
data = message.data
|
|
93
|
+
text = data.decode("utf-8", errors="ignore") if isinstance(data, bytes) else data
|
|
94
|
+
if text != message.content:
|
|
95
|
+
tokens += self.count_text(text)
|
|
96
|
+
else:
|
|
97
|
+
# Binary media is budgeted with a declared flat estimate; its
|
|
98
|
+
# base64 payload is not text and is never counted as such.
|
|
99
|
+
tokens += self.media_tokens
|
|
100
|
+
return tokens
|
|
101
|
+
|
|
102
|
+
def count_messages(self, messages: list[Any]) -> int:
|
|
103
|
+
"""Count a list of outbound messages."""
|
|
104
|
+
return sum(self.count_message(message) for message in messages)
|
|
105
|
+
|
|
106
|
+
def count_tools(self, tools: list[dict[str, Any]] | None) -> int:
|
|
107
|
+
"""Count provider tool definitions."""
|
|
108
|
+
if not tools:
|
|
109
|
+
return 0
|
|
110
|
+
return sum(self.count_text(_to_json_text(tool)) for tool in tools)
|
|
111
|
+
|
|
112
|
+
def count_output_schema(self, output_schema: Any) -> int:
|
|
113
|
+
"""Count a structured-output schema (Pydantic model type or JSON schema)."""
|
|
114
|
+
if output_schema is None:
|
|
115
|
+
return 0
|
|
116
|
+
if isinstance(output_schema, type) and issubclass(output_schema, BaseModel):
|
|
117
|
+
return self.count_text(_to_json_text(output_schema.model_json_schema()))
|
|
118
|
+
return self.count_text(_to_json_text(output_schema))
|
|
119
|
+
|
|
120
|
+
def count_request(
|
|
121
|
+
self,
|
|
122
|
+
messages: list[Any],
|
|
123
|
+
*,
|
|
124
|
+
tools: list[dict[str, Any]] | None = None,
|
|
125
|
+
output_schema: Any = None,
|
|
126
|
+
) -> int:
|
|
127
|
+
"""Count the complete request input: messages, tools and output schema."""
|
|
128
|
+
return (
|
|
129
|
+
self.count_messages(messages)
|
|
130
|
+
+ self.count_tools(tools)
|
|
131
|
+
+ self.count_output_schema(output_schema)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class CharacterTokenCounter(TokenCounter):
|
|
136
|
+
"""Dependency-free estimate: Unicode characters divided by ``chars_per_token``.
|
|
137
|
+
|
|
138
|
+
Rounds up per text component, so any nonempty text costs at least one token.
|
|
139
|
+
Accuracy varies by language and tokenizer; treat counts as estimates.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
kind = "character_estimate"
|
|
143
|
+
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
*,
|
|
147
|
+
chars_per_token: float = 4.0,
|
|
148
|
+
message_overhead: int = 4,
|
|
149
|
+
media_tokens: int = 1_000,
|
|
150
|
+
):
|
|
151
|
+
super().__init__(message_overhead=message_overhead, media_tokens=media_tokens)
|
|
152
|
+
if chars_per_token <= 0:
|
|
153
|
+
raise ValueError("chars_per_token must be greater than zero")
|
|
154
|
+
self.chars_per_token = chars_per_token
|
|
155
|
+
|
|
156
|
+
def count_text(self, text: str) -> int:
|
|
157
|
+
if not text:
|
|
158
|
+
return 0
|
|
159
|
+
return math.ceil(len(text) / self.chars_per_token)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TiktokenCounter(TokenCounter):
|
|
163
|
+
"""Estimate using a ``tiktoken`` encoding (optional dependency).
|
|
164
|
+
|
|
165
|
+
Tokenizer counts are closer to OpenAI-family billing but still exclude
|
|
166
|
+
provider-specific framing, so they remain estimates.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
kind = "tiktoken_estimate"
|
|
170
|
+
|
|
171
|
+
def __init__(
|
|
172
|
+
self,
|
|
173
|
+
encoding_name: str = "o200k_base",
|
|
174
|
+
*,
|
|
175
|
+
message_overhead: int = 4,
|
|
176
|
+
media_tokens: int = 1_000,
|
|
177
|
+
):
|
|
178
|
+
super().__init__(message_overhead=message_overhead, media_tokens=media_tokens)
|
|
179
|
+
try:
|
|
180
|
+
import tiktoken
|
|
181
|
+
except ImportError as exc:
|
|
182
|
+
raise ImportError(
|
|
183
|
+
"TiktokenCounter requires the optional 'tiktoken' package; "
|
|
184
|
+
"install it or use CharacterTokenCounter."
|
|
185
|
+
) from exc
|
|
186
|
+
self.encoding_name = encoding_name
|
|
187
|
+
self._encoding = tiktoken.get_encoding(encoding_name)
|
|
188
|
+
|
|
189
|
+
def count_text(self, text: str) -> int:
|
|
190
|
+
if not text:
|
|
191
|
+
return 0
|
|
192
|
+
return len(self._encoding.encode(text, disallowed_special=()))
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Exceptions raised by context compaction."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CompactionError(Exception):
|
|
7
|
+
"""Base class for context-compaction failures."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ToolExchangeError(CompactionError):
|
|
11
|
+
"""Outbound history contains a malformed or orphaned tool exchange.
|
|
12
|
+
|
|
13
|
+
Raised before provider I/O. Compaction never repairs history by inventing
|
|
14
|
+
tool calls or results.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PendingToolExchangeError(ToolExchangeError):
|
|
19
|
+
"""A tool-call batch has no result for one or more calls.
|
|
20
|
+
|
|
21
|
+
The unresolved batch stays in session history, but it cannot be sent for a
|
|
22
|
+
new model generation until every call has a result or approval resolution.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, message: str, *, pending_call_ids: list[str]):
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
self.pending_call_ids = pending_call_ids
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ContextBudgetExceeded(CompactionError):
|
|
31
|
+
"""Mandatory request content cannot fit the configured input budget."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
message: str,
|
|
36
|
+
*,
|
|
37
|
+
required_tokens: int,
|
|
38
|
+
max_input_tokens: int,
|
|
39
|
+
counter_kind: str,
|
|
40
|
+
):
|
|
41
|
+
super().__init__(message)
|
|
42
|
+
self.required_tokens = required_tokens
|
|
43
|
+
self.max_input_tokens = max_input_tokens
|
|
44
|
+
self.counter_kind = counter_kind
|