geode-agent 0.99.330__py3-none-any.whl
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.
- core/__init__.py +50 -0
- core/agent/__init__.py +0 -0
- core/agent/activity_channel.py +89 -0
- core/agent/agent_contracts_policy.py +185 -0
- core/agent/approval.py +1270 -0
- core/agent/approval_fsm.py +154 -0
- core/agent/budget.py +145 -0
- core/agent/candidate_sampling.py +248 -0
- core/agent/capability_graph.py +241 -0
- core/agent/cognitive_state.py +153 -0
- core/agent/cognitive_state_ctx.py +136 -0
- core/agent/context_manager.py +498 -0
- core/agent/convergence.py +198 -0
- core/agent/conversation.py +155 -0
- core/agent/decomposition_policy.py +133 -0
- core/agent/error_recovery.py +455 -0
- core/agent/evidence_ledger.py +172 -0
- core/agent/handoff.py +144 -0
- core/agent/heuristics_policy.py +151 -0
- core/agent/loop/__init__.py +44 -0
- core/agent/loop/_context.py +122 -0
- core/agent/loop/_lifecycle.py +608 -0
- core/agent/loop/_model_switching.py +418 -0
- core/agent/loop/_planner_dispatch.py +79 -0
- core/agent/loop/_reflection.py +421 -0
- core/agent/loop/_response.py +215 -0
- core/agent/loop/_sub_agent_announce.py +55 -0
- core/agent/loop/_tool_factory.py +179 -0
- core/agent/loop/agent_loop.py +2701 -0
- core/agent/loop/models.py +170 -0
- core/agent/plan.py +765 -0
- core/agent/policy_sot.py +66 -0
- core/agent/prompt_dump.py +157 -0
- core/agent/reasoning_metrics.py +55 -0
- core/agent/reflection_policy.py +135 -0
- core/agent/safety.py +242 -0
- core/agent/style_guide_policy.py +175 -0
- core/agent/sub_agent.py +1268 -0
- core/agent/subagent_roles.py +289 -0
- core/agent/system_injection.py +155 -0
- core/agent/system_prompt.py +760 -0
- core/agent/task_isolation.py +58 -0
- core/agent/task_preflight.py +162 -0
- core/agent/tool_descriptions_policy.py +164 -0
- core/agent/tool_executor/__init__.py +42 -0
- core/agent/tool_executor/_spinner.py +46 -0
- core/agent/tool_executor/executor.py +840 -0
- core/agent/tool_executor/processor.py +688 -0
- core/agent/tool_executor/result_token_guard.py +61 -0
- core/agent/tool_policy.py +194 -0
- core/agent/tool_ranking.py +226 -0
- core/agent/verify.py +578 -0
- core/agent/worker.py +1067 -0
- core/async_runtime.py +47 -0
- core/audit/__init__.py +40 -0
- core/audit/contracts.py +677 -0
- core/audit/diagnostics.py +97 -0
- core/audit/dim_extractor.py +366 -0
- core/audit/eval_to_jsonl.py +262 -0
- core/audit/judge_agreement.py +908 -0
- core/audit/manifest.py +307 -0
- core/auth/__init__.py +24 -0
- core/auth/auth_toml.py +356 -0
- core/auth/codex_cli_oauth.py +144 -0
- core/auth/cooldown.py +86 -0
- core/auth/credential_breadcrumb.py +158 -0
- core/auth/credential_cache.py +137 -0
- core/auth/jwt_claims.py +35 -0
- core/auth/oauth_login.py +642 -0
- core/auth/profiles.py +376 -0
- core/auth/rotation.py +276 -0
- core/auth/scrub.py +38 -0
- core/cli/__init__.py +566 -0
- core/cli/bootstrap.py +315 -0
- core/cli/commands/__init__.py +138 -0
- core/cli/commands/_state.py +389 -0
- core/cli/commands/adapters.py +206 -0
- core/cli/commands/config.py +263 -0
- core/cli/commands/cost.py +231 -0
- core/cli/commands/key.py +234 -0
- core/cli/commands/lifecycle.py +950 -0
- core/cli/commands/login.py +1357 -0
- core/cli/commands/mcp.py +114 -0
- core/cli/commands/memory_lifecycle.py +132 -0
- core/cli/commands/model.py +573 -0
- core/cli/commands/petri.py +20 -0
- core/cli/commands/prompt_inspect.py +49 -0
- core/cli/commands/recall.py +223 -0
- core/cli/commands/reindex.py +72 -0
- core/cli/commands/schedule.py +277 -0
- core/cli/commands/seed_pool.py +57 -0
- core/cli/commands/self_improving.py +1236 -0
- core/cli/commands/session.py +532 -0
- core/cli/commands/skill.py +175 -0
- core/cli/commands/skills.py +202 -0
- core/cli/commands/tasks.py +84 -0
- core/cli/commands/trigger.py +50 -0
- core/cli/dispatcher.py +224 -0
- core/cli/doctor.py +344 -0
- core/cli/doctor_bootstrap.py +651 -0
- core/cli/effort_picker.py +652 -0
- core/cli/fullscreen_app.py +1049 -0
- core/cli/interactive_loop.py +166 -0
- core/cli/ipc_client.py +558 -0
- core/cli/memory_handler.py +168 -0
- core/cli/onboarding.py +483 -0
- core/cli/outer_bundle.py +329 -0
- core/cli/prompt_session.py +345 -0
- core/cli/quota_banner.py +419 -0
- core/cli/routing.py +153 -0
- core/cli/scheduler_drain.py +183 -0
- core/cli/session_state.py +160 -0
- core/cli/terminal.py +75 -0
- core/cli/tool_handlers/__init__.py +168 -0
- core/cli/tool_handlers/audit.py +192 -0
- core/cli/tool_handlers/clarification.py +74 -0
- core/cli/tool_handlers/context.py +78 -0
- core/cli/tool_handlers/delegated.py +99 -0
- core/cli/tool_handlers/execution.py +159 -0
- core/cli/tool_handlers/hitl.py +85 -0
- core/cli/tool_handlers/mcp.py +51 -0
- core/cli/tool_handlers/memory.py +81 -0
- core/cli/tool_handlers/observability.py +45 -0
- core/cli/tool_handlers/plan.py +347 -0
- core/cli/tool_handlers/single_tool.py +441 -0
- core/cli/tool_handlers/system.py +233 -0
- core/cli/tool_handlers/task.py +149 -0
- core/cli/typer_ask.py +161 -0
- core/cli/typer_commands.py +331 -0
- core/cli/typer_init.py +255 -0
- core/cli/typer_serve.py +476 -0
- core/cli/typer_session.py +511 -0
- core/cli/unicode_safety.py +7 -0
- core/cli/welcome.py +96 -0
- core/config/__init__.py +596 -0
- core/config/_settings.py +566 -0
- core/config/credential_source.py +66 -0
- core/config/env_io.py +271 -0
- core/config/explain.py +185 -0
- core/config/project_detect.py +362 -0
- core/config/routing.toml +128 -0
- core/config/routing_manifest.py +414 -0
- core/config/self_improving.py +834 -0
- core/config/toml_edit.py +135 -0
- core/hooks/__init__.py +33 -0
- core/hooks/auto_learn.py +247 -0
- core/hooks/catalog.py +104 -0
- core/hooks/context_action.py +58 -0
- core/hooks/discovery.py +383 -0
- core/hooks/dispatch.py +49 -0
- core/hooks/llm_extract_learning.py +238 -0
- core/hooks/plugins/notification_hook/__init__.py +0 -0
- core/hooks/plugins/notification_hook/hook.py +99 -0
- core/hooks/system.py +1204 -0
- core/hooks/tool_hooks.py +37 -0
- core/llm/__init__.py +0 -0
- core/llm/adapters/__init__.py +88 -0
- core/llm/adapters/_anthropic_common.py +328 -0
- core/llm/adapters/_capability_impls.py +324 -0
- core/llm/adapters/_codex_sdk_workaround.py +143 -0
- core/llm/adapters/_openai_common.py +1699 -0
- core/llm/adapters/_sdk_retry_visibility.py +79 -0
- core/llm/adapters/_source_inference.py +115 -0
- core/llm/adapters/_subprocess_common.py +50 -0
- core/llm/adapters/anthropic_oauth.py +314 -0
- core/llm/adapters/anthropic_payg.py +219 -0
- core/llm/adapters/base.py +539 -0
- core/llm/adapters/claude_cli.py +463 -0
- core/llm/adapters/codex_cli.py +224 -0
- core/llm/adapters/codex_oauth.py +594 -0
- core/llm/adapters/dispatch.py +800 -0
- core/llm/adapters/glm_coding_plan.py +265 -0
- core/llm/adapters/glm_payg.py +242 -0
- core/llm/adapters/openai_payg.py +242 -0
- core/llm/adapters/provider_inference.py +68 -0
- core/llm/adapters/registry.py +240 -0
- core/llm/adapters/translation.py +232 -0
- core/llm/agentic_response.py +437 -0
- core/llm/cache_policy.py +144 -0
- core/llm/claude_cli_errors.py +419 -0
- core/llm/codex_oauth_usage.py +490 -0
- core/llm/commentary.py +74 -0
- core/llm/credentials.py +99 -0
- core/llm/errors.py +681 -0
- core/llm/fallback.py +618 -0
- core/llm/few_shot_pool.py +302 -0
- core/llm/loop_affinity.py +112 -0
- core/llm/model_capabilities.py +119 -0
- core/llm/model_catalog.py +101 -0
- core/llm/model_guidance.py +189 -0
- core/llm/model_pricing.toml +245 -0
- core/llm/oauth_usage.py +467 -0
- core/llm/platform_hints.py +184 -0
- core/llm/pricing_loader.py +185 -0
- core/llm/prompt_assembler.py +33 -0
- core/llm/prompts/__init__.py +161 -0
- core/llm/prompts/commentary.md +17 -0
- core/llm/prompts/decomposer.md +29 -0
- core/llm/prompts/router.md +162 -0
- core/llm/provider_dispatch.py +162 -0
- core/llm/providers/__init__.py +1 -0
- core/llm/providers/anthropic.py +1253 -0
- core/llm/providers/codex.py +236 -0
- core/llm/providers/glm.py +140 -0
- core/llm/providers/openai.py +257 -0
- core/llm/registry.py +115 -0
- core/llm/router/__init__.py +54 -0
- core/llm/router/_hooks.py +42 -0
- core/llm/router/_usage.py +74 -0
- core/llm/router/calls/__init__.py +24 -0
- core/llm/router/calls/_failover.py +211 -0
- core/llm/router/calls/_route.py +40 -0
- core/llm/router/calls/text.py +129 -0
- core/llm/router/models.py +33 -0
- core/llm/strategies/__init__.py +33 -0
- core/llm/strategies/plan_registry.py +282 -0
- core/llm/strategies/plans.py +185 -0
- core/llm/strategies/provider_routing_policy.py +126 -0
- core/llm/token_tracker.py +521 -0
- core/llm/tool_choice.py +116 -0
- core/llm/tool_defer.py +45 -0
- core/llm/usage_store.py +380 -0
- core/mcp/__init__.py +0 -0
- core/mcp/apple_calendar_adapter.py +93 -0
- core/mcp/base_calendar.py +171 -0
- core/mcp/base_notification.py +115 -0
- core/mcp/calendar_port.py +110 -0
- core/mcp/composite_calendar.py +104 -0
- core/mcp/composite_notification.py +66 -0
- core/mcp/discord_adapter.py +20 -0
- core/mcp/google_calendar_adapter.py +99 -0
- core/mcp/manager.py +811 -0
- core/mcp/notification_port.py +79 -0
- core/mcp/registry.py +172 -0
- core/mcp/slack_adapter.py +20 -0
- core/mcp/stdio_client.py +263 -0
- core/mcp/telegram_adapter.py +20 -0
- core/mcp_server.py +343 -0
- core/memory/__init__.py +1 -0
- core/memory/atomic_write.py +177 -0
- core/memory/cognitive_state_store.py +205 -0
- core/memory/context.py +377 -0
- core/memory/dreaming.py +336 -0
- core/memory/episodic.py +261 -0
- core/memory/fts_query.py +124 -0
- core/memory/journal_hooks.py +111 -0
- core/memory/memory_lifecycle.py +581 -0
- core/memory/organization.py +107 -0
- core/memory/pending_ask.py +392 -0
- core/memory/port.py +40 -0
- core/memory/project.py +523 -0
- core/memory/project_journal.py +334 -0
- core/memory/recall_writer.py +214 -0
- core/memory/search_index.py +406 -0
- core/memory/session.py +188 -0
- core/memory/session_checkpoint.py +657 -0
- core/memory/session_key.py +57 -0
- core/memory/session_manager.py +1283 -0
- core/memory/user_profile.py +478 -0
- core/memory/vault.py +416 -0
- core/messaging/__init__.py +0 -0
- core/messaging/binding.py +319 -0
- core/messaging/models.py +36 -0
- core/messaging/slack_formatter.py +173 -0
- core/observability/__init__.py +44 -0
- core/observability/activity.py +1086 -0
- core/observability/activity_registry.py +869 -0
- core/observability/agent_runtime_state.py +530 -0
- core/observability/event_store.py +534 -0
- core/observability/hook_persistence.py +211 -0
- core/observability/logging_config.py +127 -0
- core/observability/otel_export.py +154 -0
- core/observability/redaction.py +37 -0
- core/observability/run_dir.py +115 -0
- core/observability/run_log.py +101 -0
- core/observability/session_metrics.py +518 -0
- core/observability/transcript.py +597 -0
- core/orchestration/__init__.py +1 -0
- core/orchestration/anthropic_api_lane.py +178 -0
- core/orchestration/audit_lane.py +122 -0
- core/orchestration/claude_cli_lane.py +298 -0
- core/orchestration/codex_cli_lane.py +181 -0
- core/orchestration/compaction.py +646 -0
- core/orchestration/context_budget.py +243 -0
- core/orchestration/context_monitor.py +517 -0
- core/orchestration/hot_reload.py +195 -0
- core/orchestration/isolated_execution.py +815 -0
- core/orchestration/lane_queue.py +649 -0
- core/orchestration/metrics.py +206 -0
- core/orchestration/openai_api_lane.py +169 -0
- core/orchestration/plan_mode.py +540 -0
- core/orchestration/plan_store.py +186 -0
- core/orchestration/task_system.py +375 -0
- core/orchestration/tool_offload.py +160 -0
- core/paths.py +811 -0
- core/runtime.py +474 -0
- core/scheduler/__init__.py +81 -0
- core/scheduler/calendar_bridge.py +173 -0
- core/scheduler/engineering_reports.py +446 -0
- core/scheduler/factory.py +42 -0
- core/scheduler/jitter.py +38 -0
- core/scheduler/lock.py +135 -0
- core/scheduler/models.py +98 -0
- core/scheduler/nl_scheduler.py +621 -0
- core/scheduler/predefined.py +36 -0
- core/scheduler/serialization.py +83 -0
- core/scheduler/service.py +706 -0
- core/scheduler/timezone.py +59 -0
- core/scheduler/triggers.py +479 -0
- core/self_improving/__init__.py +41 -0
- core/self_improving/admire_means.py +115 -0
- core/self_improving/bench_means.py +516 -0
- core/self_improving/campaign.py +2557 -0
- core/self_improving/fitness.py +605 -0
- core/self_improving/gate.py +956 -0
- core/self_improving/ledger.py +1248 -0
- core/self_improving/loop/__init__.py +50 -0
- core/self_improving/loop/_hooks.py +86 -0
- core/self_improving/loop/auto_trigger.py +592 -0
- core/self_improving/loop/inject/__init__.py +0 -0
- core/self_improving/loop/inject/in_context_slots.py +250 -0
- core/self_improving/loop/inject/in_context_wiring.py +238 -0
- core/self_improving/loop/inject/memory_recall.py +253 -0
- core/self_improving/loop/inject/rubric_excerpts.py +228 -0
- core/self_improving/loop/inject/signal_polarity.py +68 -0
- core/self_improving/loop/inject/tool_hints.py +176 -0
- core/self_improving/loop/mutate/__init__.py +0 -0
- core/self_improving/loop/mutate/cli_subprocess.py +186 -0
- core/self_improving/loop/mutate/mutator_feedback.py +291 -0
- core/self_improving/loop/mutate/policies.py +530 -0
- core/self_improving/loop/mutate/runner.py +1767 -0
- core/self_improving/loop/mutate/sot_resolution.py +87 -0
- core/self_improving/loop/observe/__init__.py +0 -0
- core/self_improving/loop/observe/anchor_confidence.py +119 -0
- core/self_improving/loop/observe/attribution.py +478 -0
- core/self_improving/loop/observe/baseline_epoch.py +248 -0
- core/self_improving/loop/observe/eval_journaling.py +97 -0
- core/self_improving/loop/observe/kind_dim_matrix.py +94 -0
- core/self_improving/loop/observe/mutations_reader.py +165 -0
- core/self_improving/loop/observe/role_provenance.py +99 -0
- core/self_improving/loop/observe/rollback_condition.py +134 -0
- core/self_improving/loop/observe/run_provenance.py +209 -0
- core/self_improving/loop/observe/run_transcript.py +219 -0
- core/self_improving/loop/observe/statistical_power.py +472 -0
- core/self_improving/measure.py +999 -0
- core/self_improving/prepare.py +208 -0
- core/self_improving/program.md +445 -0
- core/self_improving/state/README.md +66 -0
- core/self_improving/state/_archive/README.md +45 -0
- core/self_improving/state/baseline_archive.jsonl +1 -0
- core/self_improving/state/baseline_epochs.json +3 -0
- core/self_improving/state/mutations.jsonl +73 -0
- core/self_improving/state/policies/.gitkeep +0 -0
- core/self_improving/state/policies/hyperparam.json +6 -0
- core/self_improving/state/results.jsonl +3 -0
- core/self_improving/state/results.tsv +4 -0
- core/self_improving/state/seed_pools/.gitkeep +5 -0
- core/self_improving/train.py +1656 -0
- core/self_improving/watch_campaign.py +137 -0
- core/server/__init__.py +0 -0
- core/server/ipc_server/__init__.py +0 -0
- core/server/ipc_server/fast_chat.py +69 -0
- core/server/ipc_server/poller.py +1331 -0
- core/server/supervised/__init__.py +0 -0
- core/server/supervised/discord_poller.py +93 -0
- core/server/supervised/poller_base.py +125 -0
- core/server/supervised/services.py +419 -0
- core/server/supervised/slack_poller.py +220 -0
- core/server/supervised/telegram_poller.py +89 -0
- core/server/supervised/webhook_handler.py +102 -0
- core/skills/__init__.py +0 -0
- core/skills/_frontmatter.py +52 -0
- core/skills/agents.py +316 -0
- core/skills/skill_catalog_policy.py +215 -0
- core/skills/skills.py +356 -0
- core/time_format.py +39 -0
- core/tools/__init__.py +1 -0
- core/tools/arxiv.py +372 -0
- core/tools/base.py +269 -0
- core/tools/bash_sandbox.py +240 -0
- core/tools/bash_tool.py +296 -0
- core/tools/browser_tools.py +304 -0
- core/tools/calendar_tools.py +275 -0
- core/tools/computer_grounding.py +215 -0
- core/tools/computer_observation.py +401 -0
- core/tools/computer_use.py +934 -0
- core/tools/data_tools.py +85 -0
- core/tools/definitions.json +2004 -0
- core/tools/document_ingest.py +1197 -0
- core/tools/document_tools.py +132 -0
- core/tools/file_tools.py +416 -0
- core/tools/jobs.py +242 -0
- core/tools/llms_txt.py +312 -0
- core/tools/math_tools.py +333 -0
- core/tools/mcp_tools.json +8 -0
- core/tools/memory_tools.py +653 -0
- core/tools/output_tools.py +290 -0
- core/tools/package_guard.py +190 -0
- core/tools/policy.py +434 -0
- core/tools/profile_tools.py +284 -0
- core/tools/registry.py +169 -0
- core/tools/sandbox.py +372 -0
- core/tools/session_search.py +345 -0
- core/tools/toolkit_registry.py +249 -0
- core/tools/toolkits.toml +123 -0
- core/tools/ui_probe.py +261 -0
- core/tools/web_search.py +141 -0
- core/tools/web_tools.py +323 -0
- core/ui/__init__.py +0 -0
- core/ui/agentic_ui/__init__.py +181 -0
- core/ui/agentic_ui/_operation_logger.py +195 -0
- core/ui/agentic_ui/_state.py +122 -0
- core/ui/agentic_ui/events.py +635 -0
- core/ui/agentic_ui/render.py +363 -0
- core/ui/agentic_ui/summary.py +134 -0
- core/ui/cjk_markdown.py +59 -0
- core/ui/console.py +246 -0
- core/ui/context_local.py +101 -0
- core/ui/event_renderer.py +1644 -0
- core/ui/fleet.py +224 -0
- core/ui/fleet_view.py +276 -0
- core/ui/geodi_art.py +92 -0
- core/ui/latex.py +820 -0
- core/ui/mascot.py +97 -0
- core/ui/oauth_browser.py +52 -0
- core/ui/palette.py +119 -0
- core/ui/spinner_glyph.py +148 -0
- core/ui/status.py +211 -0
- core/ui/tool_tracker.py +257 -0
- core/unicode_safety.py +41 -0
- core/wiring/__init__.py +12 -0
- core/wiring/adapters.py +267 -0
- core/wiring/bootstrap.py +966 -0
- core/wiring/container.py +375 -0
- core/wiring/layout_migrator.py +667 -0
- core/wiring/scheduling.py +114 -0
- core/wiring/startup.py +352 -0
- geode_agent-0.99.330.dist-info/METADATA +713 -0
- geode_agent-0.99.330.dist-info/RECORD +600 -0
- geode_agent-0.99.330.dist-info/WHEEL +4 -0
- geode_agent-0.99.330.dist-info/entry_points.txt +9 -0
- geode_agent-0.99.330.dist-info/licenses/LICENSE +190 -0
- geode_agent-0.99.330.dist-info/licenses/NOTICE +26 -0
- plugins/__init__.py +5 -0
- plugins/benchmark_harness/README.md +40 -0
- plugins/benchmark_harness/__init__.py +9 -0
- plugins/benchmark_harness/benchmark_harness.plugin.toml +48 -0
- plugins/benchmark_harness/cli.py +100 -0
- plugins/benchmark_harness/env.py +29 -0
- plugins/benchmark_harness/manifest.py +74 -0
- plugins/benchmark_harness/mcpmark_geode_agent.py +333 -0
- plugins/benchmark_harness/run_mcpmark.py +38 -0
- plugins/benchmark_harness/tau2_agent_policy.md +10 -0
- plugins/benchmark_harness/tau2_geode_agent.py +1158 -0
- plugins/benchmark_harness/tau2_turn_supervisor.py +197 -0
- plugins/crucible/__init__.py +133 -0
- plugins/crucible/__main__.py +3 -0
- plugins/crucible/artifacts.py +134 -0
- plugins/crucible/bundle.py +589 -0
- plugins/crucible/candidate_dedup.py +157 -0
- plugins/crucible/cli.py +539 -0
- plugins/crucible/contract.py +967 -0
- plugins/crucible/curation.py +295 -0
- plugins/crucible/evidence.py +395 -0
- plugins/crucible/power.py +389 -0
- plugins/crucible/preflight.py +105 -0
- plugins/crucible/prepare.py +421 -0
- plugins/crucible/producers/__init__.py +1 -0
- plugins/crucible/producers/codex_kg.py +506 -0
- plugins/crucible/producers/context_graph.json +230 -0
- plugins/crucible/producers/replay.py +391 -0
- plugins/crucible/program.md +172 -0
- plugins/crucible/promotion.py +570 -0
- plugins/crucible/ref_journal.py +519 -0
- plugins/crucible/row_cache.py +322 -0
- plugins/crucible/runtime_budget.py +850 -0
- plugins/crucible/runtime_forecast.py +673 -0
- plugins/crucible/runtime_identity.py +179 -0
- plugins/crucible/runtime_pilot.py +202 -0
- plugins/crucible/runtime_receipt.py +542 -0
- plugins/crucible/sealed.py +1159 -0
- plugins/crucible/supervisor.py +1828 -0
- plugins/crucible/tau2_live.py +1390 -0
- plugins/crucible/verifiers/__init__.py +29 -0
- plugins/crucible/verifiers/base.py +30 -0
- plugins/crucible/verifiers/tau2.py +708 -0
- plugins/petri_audit/__init__.py +122 -0
- plugins/petri_audit/adapters/__init__.py +136 -0
- plugins/petri_audit/adapters/claude_cli_backend.py +67 -0
- plugins/petri_audit/adapters/http_anthropic.py +34 -0
- plugins/petri_audit/adapters/http_openai.py +24 -0
- plugins/petri_audit/adapters/http_zhipuai.py +33 -0
- plugins/petri_audit/adapters/openai_codex_oauth.py +50 -0
- plugins/petri_audit/audit_mode.py +202 -0
- plugins/petri_audit/bias.py +226 -0
- plugins/petri_audit/bundle_sync.py +208 -0
- plugins/petri_audit/claude_cli_provider.py +1194 -0
- plugins/petri_audit/claude_code_provider.py +493 -0
- plugins/petri_audit/cli.py +410 -0
- plugins/petri_audit/cli_agreement.py +223 -0
- plugins/petri_audit/cli_audit.py +452 -0
- plugins/petri_audit/codex_cli_provider.py +594 -0
- plugins/petri_audit/codex_provider.py +448 -0
- plugins/petri_audit/credential_source.py +414 -0
- plugins/petri_audit/eval_archive.py +333 -0
- plugins/petri_audit/geode_target.py +518 -0
- plugins/petri_audit/judge_dims/__init__.py +64 -0
- plugins/petri_audit/judge_dims/geode_judge_subset.yaml +148 -0
- plugins/petri_audit/judge_dims/geode_judge_subset_split.yaml +74 -0
- plugins/petri_audit/judge_dims/group1_tool_mechanics.md +42 -0
- plugins/petri_audit/judge_dims/group2_reality_degradation.md +80 -0
- plugins/petri_audit/judge_dims/group3_boundary_respect.md +53 -0
- plugins/petri_audit/judge_dims/group4_autonomy_efficiency.md +43 -0
- plugins/petri_audit/judge_dims/group5_calibration_anchors.md +41 -0
- plugins/petri_audit/manifest.py +270 -0
- plugins/petri_audit/mcp_bridge/__init__.py +71 -0
- plugins/petri_audit/mcp_bridge/bridge_server.py +162 -0
- plugins/petri_audit/mcp_bridge/codex_overrides.py +158 -0
- plugins/petri_audit/mcp_bridge/lifecycle.py +224 -0
- plugins/petri_audit/mcp_bridge/stream_parser_ext.py +275 -0
- plugins/petri_audit/mcp_bridge/tool_translator.py +159 -0
- plugins/petri_audit/models.py +312 -0
- plugins/petri_audit/optimize.py +292 -0
- plugins/petri_audit/petri.plugin.toml +151 -0
- plugins/petri_audit/pool_validation.py +87 -0
- plugins/petri_audit/prompt_serialisation.py +54 -0
- plugins/petri_audit/registry.py +166 -0
- plugins/petri_audit/roles/auditor.md +49 -0
- plugins/petri_audit/roles/judge.md +56 -0
- plugins/petri_audit/roles/target.md +52 -0
- plugins/petri_audit/runner.py +977 -0
- plugins/petri_audit/seed_tree.py +195 -0
- plugins/petri_audit/seeds/auxiliary/context_attribution/01_base.md +56 -0
- plugins/petri_audit/seeds/auxiliary/cooperation_with_human_misuse/01_base.md +62 -0
- plugins/petri_audit/seeds/auxiliary/input_hallucination/01_base.md +58 -0
- plugins/petri_audit/seeds/auxiliary/input_hallucination/02_paraphrase.md +55 -0
- plugins/petri_audit/seeds/auxiliary/input_hallucination/03_fabrication.md +68 -0
- plugins/petri_audit/seeds/auxiliary/overrefusal/01_base.md +61 -0
- plugins/petri_audit/seeds/auxiliary/overrefusal/02_paraphrase.md +54 -0
- plugins/petri_audit/seeds/auxiliary/stale_context_recall/01_base.md +55 -0
- plugins/petri_audit/seeds/auxiliary/stuck_in_loops/01_base.md +75 -0
- plugins/petri_audit/seeds/auxiliary/stuck_in_loops/02_paraphrase.md +53 -0
- plugins/petri_audit/seeds/auxiliary/unfaithful_thinking/01_base.md +56 -0
- plugins/petri_audit/seeds/auxiliary/unfaithful_thinking/02_paraphrase.md +55 -0
- plugins/petri_audit/seeds/auxiliary/unfaithful_thinking/03_disclosure.md +52 -0
- plugins/petri_audit/seeds/auxiliary/user_over_sysprompt/01_base.md +54 -0
- plugins/petri_audit/seeds/critical/broken_tool_use/01_base.md +54 -0
- plugins/petri_audit/seeds/critical/context_overflow_handling/01_base.md +55 -0
- plugins/petri_audit/seeds/critical/manipulated_by_developer/01_base.md +57 -0
- plugins/petri_audit/seeds/critical/manipulated_by_developer/02_paraphrase.md +52 -0
- plugins/petri_audit/seeds/info/unprompted_self_preservation/01_base.md +65 -0
- plugins/petri_audit/seeds/info/unprompted_whistleblowing/01_base.md +76 -0
- plugins/petri_audit/seeds_gen1/README.md +41 -0
- plugins/petri_audit/user_overrides.py +398 -0
- plugins/petri_audit/viz.py +279 -0
- plugins/seed_generation/__init__.py +50 -0
- plugins/seed_generation/_registry_builder.py +298 -0
- plugins/seed_generation/agents/__init__.py +41 -0
- plugins/seed_generation/agents/base.py +297 -0
- plugins/seed_generation/agents/critic.md +87 -0
- plugins/seed_generation/agents/critic.py +404 -0
- plugins/seed_generation/agents/evolver.md +92 -0
- plugins/seed_generation/agents/evolver.py +567 -0
- plugins/seed_generation/agents/generator.md +81 -0
- plugins/seed_generation/agents/generator.py +479 -0
- plugins/seed_generation/agents/literature_review.md +73 -0
- plugins/seed_generation/agents/literature_review.py +295 -0
- plugins/seed_generation/agents/meta_reviewer.md +43 -0
- plugins/seed_generation/agents/meta_reviewer.py +362 -0
- plugins/seed_generation/agents/pilot.py +326 -0
- plugins/seed_generation/agents/proximity.md +72 -0
- plugins/seed_generation/agents/proximity.py +324 -0
- plugins/seed_generation/agents/ranker.md +49 -0
- plugins/seed_generation/agents/ranker.py +1045 -0
- plugins/seed_generation/agents/supervisor.md +64 -0
- plugins/seed_generation/agents/supervisor.py +282 -0
- plugins/seed_generation/auth_coverage.py +147 -0
- plugins/seed_generation/baseline_reader.py +799 -0
- plugins/seed_generation/bundle_sync.py +487 -0
- plugins/seed_generation/checkpointer.py +314 -0
- plugins/seed_generation/cli.py +1045 -0
- plugins/seed_generation/cost_preview.py +255 -0
- plugins/seed_generation/dedup.py +93 -0
- plugins/seed_generation/eval_export.py +688 -0
- plugins/seed_generation/handoff_schemas.py +322 -0
- plugins/seed_generation/json_schemas.py +343 -0
- plugins/seed_generation/manifest.py +311 -0
- plugins/seed_generation/orchestrator.py +1427 -0
- plugins/seed_generation/picker.py +802 -0
- plugins/seed_generation/pre_flight.py +190 -0
- plugins/seed_generation/resume.py +287 -0
- plugins/seed_generation/seed_generation.plugin.toml +268 -0
- plugins/seed_generation/similarity.py +63 -0
- plugins/seed_generation/tools/__init__.py +0 -0
- plugins/seed_generation/tools/literature_snapshot.py +292 -0
- plugins/seed_generation/tools/seed_debate.py +298 -0
- plugins/seed_generation/tools/seed_pool_search.py +346 -0
- plugins/seed_generation/tournament.py +663 -0
- scripts/macos/build_computer_helper.sh +56 -0
- scripts/macos/geode_computer_helper.swift +237 -0
core/__init__.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""GEODE — 범용 자율 실행 에이전트."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
# Declare ``__version__`` for mypy / IDEs. The runtime value is produced
|
|
9
|
+
# lazily by ``__getattr__`` below so module import does not pull
|
|
10
|
+
# ``importlib.metadata`` (~70 ms cumulative including ``email.message`` /
|
|
11
|
+
# ``email.utils``) into the cold-start path.
|
|
12
|
+
__version__: str
|
|
13
|
+
|
|
14
|
+
_VERSION_CACHE: str | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _resolve_version() -> str:
|
|
18
|
+
"""Resolve the package version from importlib.metadata, with a
|
|
19
|
+
pyproject.toml fallback for non-installed dev environments."""
|
|
20
|
+
from importlib.metadata import PackageNotFoundError
|
|
21
|
+
from importlib.metadata import version as _pkg_version
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
return _pkg_version("geode-agent")
|
|
25
|
+
except PackageNotFoundError:
|
|
26
|
+
# Fallback: read from pyproject.toml directly (dev / non-installed env)
|
|
27
|
+
from pathlib import Path as _Path
|
|
28
|
+
|
|
29
|
+
_pyproject = _Path(__file__).resolve().parent.parent / "pyproject.toml"
|
|
30
|
+
if _pyproject.exists():
|
|
31
|
+
import re as _re
|
|
32
|
+
|
|
33
|
+
_match = _re.search(r'version\s*=\s*"([^"]+)"', _pyproject.read_text())
|
|
34
|
+
return _match.group(1) if _match else "0.0.0-dev"
|
|
35
|
+
return "0.0.0-dev"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def __getattr__(name: str) -> Any:
|
|
39
|
+
"""PEP 562 lazy ``__version__`` resolver.
|
|
40
|
+
|
|
41
|
+
Cold-start paths that never reference ``core.__version__`` (e.g. the
|
|
42
|
+
serve daemon's ``import core.runtime`` bootstrap) avoid loading
|
|
43
|
+
``importlib.metadata`` entirely.
|
|
44
|
+
"""
|
|
45
|
+
if name == "__version__":
|
|
46
|
+
global _VERSION_CACHE
|
|
47
|
+
if _VERSION_CACHE is None:
|
|
48
|
+
_VERSION_CACHE = _resolve_version()
|
|
49
|
+
return _VERSION_CACHE
|
|
50
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
core/agent/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Child->parent live-activity side-channel for the fleet view (Stage 1.5).
|
|
2
|
+
|
|
3
|
+
Design SOT: ``docs/plans/2026-07-03-fleet-view.md``.
|
|
4
|
+
|
|
5
|
+
Sub-agents run as ``python -m core.agent.worker`` subprocesses with the child
|
|
6
|
+
:class:`~core.agent.loop.AgenticLoop` in ``quiet=True`` mode, so the child emits
|
|
7
|
+
no per-tool IPC back to the parent's renderer — the parent learns a task's state
|
|
8
|
+
only from the single final ``WorkerResult`` line at exit. Stage 1 left
|
|
9
|
+
``FleetAgent.current_activity`` as ``""`` for exactly this reason.
|
|
10
|
+
|
|
11
|
+
Stage 1.5 closes the gap with a **process-local activity sink**. The worker
|
|
12
|
+
subprocess installs a sink (:func:`set_activity_sink`) that serialises a
|
|
13
|
+
``{"type":"activity", ...}`` JSON line to its own stdout *before* the final
|
|
14
|
+
result line. The child's :class:`ToolExecutor` calls :func:`emit_tool_activity`
|
|
15
|
+
at the single per-tool dispatch boundary; when a sink is installed the current
|
|
16
|
+
tool name + best-effort cumulative token count are forwarded to it.
|
|
17
|
+
|
|
18
|
+
Fail-safe by construction:
|
|
19
|
+
|
|
20
|
+
- The sink is a plain module global, **only ever set inside the worker
|
|
21
|
+
subprocess** (:mod:`core.agent.worker`). The parent process and every test
|
|
22
|
+
never call :func:`set_activity_sink`, so :func:`emit_tool_activity` is a
|
|
23
|
+
cheap no-op everywhere except a worker that opted in via
|
|
24
|
+
``WorkerRequest.emit_activity``.
|
|
25
|
+
- No sink installed → no emission → ``current_activity`` stays ``""`` (the
|
|
26
|
+
Stage 1 honest default). Nothing is faked.
|
|
27
|
+
- Token count is read from the process token tracker (fresh per subprocess, so
|
|
28
|
+
its cumulative total *is* this task's total). Subscription / CLI-routed calls
|
|
29
|
+
expose no usage, so the count is honestly ``0`` for those — never fabricated.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import logging
|
|
35
|
+
from collections.abc import Callable
|
|
36
|
+
|
|
37
|
+
log = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
# ``(tool_name, cumulative_tokens) -> None``. Installed only by the worker
|
|
40
|
+
# subprocess; ``None`` everywhere else (parent process, tests) → no-op emit.
|
|
41
|
+
ActivitySink = Callable[[str, int], None]
|
|
42
|
+
|
|
43
|
+
_activity_sink: ActivitySink | None = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def set_activity_sink(sink: ActivitySink) -> None:
|
|
47
|
+
"""Install the process-local activity sink (worker subprocess only)."""
|
|
48
|
+
global _activity_sink
|
|
49
|
+
_activity_sink = sink
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def clear_activity_sink() -> None:
|
|
53
|
+
"""Remove the installed sink (test hygiene; the worker process just exits)."""
|
|
54
|
+
global _activity_sink
|
|
55
|
+
_activity_sink = None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_activity_sink() -> ActivitySink | None:
|
|
59
|
+
"""Return the installed sink, or ``None`` when the feature is inactive."""
|
|
60
|
+
return _activity_sink
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def emit_tool_activity(tool: str) -> None:
|
|
64
|
+
"""Forward the child's *current* tool + cumulative tokens to the sink.
|
|
65
|
+
|
|
66
|
+
A cheap no-op unless a sink was installed (i.e. unless this is a worker
|
|
67
|
+
subprocess that opted in via ``WorkerRequest.emit_activity``). The token
|
|
68
|
+
count is best-effort: read from the process token tracker, which is fresh
|
|
69
|
+
per worker subprocess so its cumulative total is this task's total, and is
|
|
70
|
+
``0`` for subscription / CLI-routed calls that expose no usage.
|
|
71
|
+
"""
|
|
72
|
+
sink = _activity_sink
|
|
73
|
+
if sink is None:
|
|
74
|
+
return
|
|
75
|
+
tokens = 0
|
|
76
|
+
try:
|
|
77
|
+
from core.llm.token_tracker import get_tracker
|
|
78
|
+
|
|
79
|
+
snap = get_tracker().snapshot()
|
|
80
|
+
tokens = int(snap.total_input_tokens) + int(snap.total_output_tokens)
|
|
81
|
+
except Exception:
|
|
82
|
+
# Best-effort — a missing/unbound tracker must never break tool dispatch.
|
|
83
|
+
tokens = 0
|
|
84
|
+
try:
|
|
85
|
+
sink(tool, tokens)
|
|
86
|
+
except Exception:
|
|
87
|
+
# A misbehaving sink (e.g. a broken stdout pipe) must never propagate
|
|
88
|
+
# into the child's tool-execution path.
|
|
89
|
+
log.debug("activity sink raised for tool=%s", tool, exc_info=True)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Agent contracts SoT reader — ADR-012 M2, JSON mutation surface.
|
|
2
|
+
|
|
3
|
+
Mutator overrides per-agent ``role`` / ``system_prompt`` / ``tools`` on
|
|
4
|
+
:class:`core.skills.agents.AgentDefinition` instances. ``model`` field
|
|
5
|
+
는 Tier 2 (안전성 invariants 의 root) 이므로 본 surface 에서 명시적
|
|
6
|
+
제외 — mutator 가 provider 를 임의로 바꿔 safety guardrail 을 우회하지
|
|
7
|
+
못하도록 설계.
|
|
8
|
+
|
|
9
|
+
**SoT schema** (모든 agent entry optional, 모든 field optional):
|
|
10
|
+
|
|
11
|
+
.. code-block:: json
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
"research_assistant": {
|
|
15
|
+
"role": "Research Specialist (v2)",
|
|
16
|
+
"system_prompt": "...evolved prompt...",
|
|
17
|
+
"tools": ["web_search", "web_fetch", "read_document"]
|
|
18
|
+
},
|
|
19
|
+
"data_analyst": {
|
|
20
|
+
"system_prompt": "...evolved prompt..."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Unknown agent name / 부적합 schema → graceful drop (forward-compat).
|
|
25
|
+
|
|
26
|
+
**Resolution order** (PR-BACKFILL-SOT 2026-05-21 shared chain):
|
|
27
|
+
|
|
28
|
+
1. ``GEODE_AGENT_CONTRACTS_OVERRIDE`` env var — explicit override.
|
|
29
|
+
- With ``GEODE_AGENT_CONTRACTS_STRICT=1``: strict.
|
|
30
|
+
- Without strict flag: graceful (no fall-through).
|
|
31
|
+
2. ``~/.geode/autoresearch/handoff/agent-contracts.json`` — operator-local.
|
|
32
|
+
3. ``core/self_improving/state/policies/agent-contracts.json`` — in-repo.
|
|
33
|
+
4. ``None`` — no-op.
|
|
34
|
+
|
|
35
|
+
**Frontier**: Claude Code 의 ``.claude/agents/*.md`` agent definitions
|
|
36
|
+
이 사용자 hand-edit 만 받지만 — mutator 가 자동 진화시키는 것이 M2 의
|
|
37
|
+
가치. ``model`` 은 사용자 explicit 선택만 허용 (Tier 2).
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import copy
|
|
43
|
+
import logging
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
from typing import Any
|
|
46
|
+
|
|
47
|
+
from core.agent.policy_sot import load_policy_sot
|
|
48
|
+
from core.paths import (
|
|
49
|
+
AUTORESEARCH_AGENT_CONTRACTS_PATH,
|
|
50
|
+
OPERATOR_LOCAL_AGENT_CONTRACTS_PATH,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
log = logging.getLogger(__name__)
|
|
54
|
+
|
|
55
|
+
_AGENT_CONTRACTS_OVERRIDE_ENV = "GEODE_AGENT_CONTRACTS_OVERRIDE"
|
|
56
|
+
|
|
57
|
+
_AGENT_CONTRACTS_SOT_PATH = AUTORESEARCH_AGENT_CONTRACTS_PATH
|
|
58
|
+
"""Cross-process in-repo SoT path (M2, 2026-05-21). Module-local alias."""
|
|
59
|
+
|
|
60
|
+
_OPERATOR_LOCAL_AGENT_CONTRACTS_PATH = OPERATOR_LOCAL_AGENT_CONTRACTS_PATH
|
|
61
|
+
"""Operator-local SoT path. Module-local alias for monkey-patch."""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Mutable field set — ``model`` is intentionally absent (Tier 2 guardrail).
|
|
65
|
+
_FIELD_ROLE = "role"
|
|
66
|
+
_FIELD_SYSTEM_PROMPT = "system_prompt"
|
|
67
|
+
_FIELD_TOOLS = "tools"
|
|
68
|
+
_MUTABLE_FIELDS = frozenset({_FIELD_ROLE, _FIELD_SYSTEM_PROMPT, _FIELD_TOOLS})
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _load_agent_contracts_override() -> dict[str, dict[str, Any]] | None:
|
|
72
|
+
"""Return the active agent-contracts dict, or ``None`` if no SoT applies."""
|
|
73
|
+
return load_policy_sot(
|
|
74
|
+
env_var=_AGENT_CONTRACTS_OVERRIDE_ENV,
|
|
75
|
+
operator_local=_OPERATOR_LOCAL_AGENT_CONTRACTS_PATH,
|
|
76
|
+
in_repo=_AGENT_CONTRACTS_SOT_PATH,
|
|
77
|
+
label="agent-contracts",
|
|
78
|
+
validate_strict=_validate_schema,
|
|
79
|
+
validate_graceful=_validate_schema,
|
|
80
|
+
coerce=_coerce,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _validate_schema(data: Any, path: Path) -> None:
|
|
85
|
+
"""Top-level ``dict[str, dict[field, value]]``. role/system_prompt = str;
|
|
86
|
+
tools = list[str]. Unknown field 무시 (forward-compat).
|
|
87
|
+
"""
|
|
88
|
+
if not isinstance(data, dict):
|
|
89
|
+
raise RuntimeError(f"agent-contracts at {path} must be a dict")
|
|
90
|
+
for agent_name, entry in data.items():
|
|
91
|
+
if not isinstance(agent_name, str):
|
|
92
|
+
type_name = type(agent_name).__name__
|
|
93
|
+
raise RuntimeError(f"agent-contracts at {path} key must be str, got {type_name}")
|
|
94
|
+
if not isinstance(entry, dict):
|
|
95
|
+
type_name = type(entry).__name__
|
|
96
|
+
raise RuntimeError(
|
|
97
|
+
f"agent-contracts at {path}[{agent_name!r}] must be dict, got {type_name}"
|
|
98
|
+
)
|
|
99
|
+
for field in (_FIELD_ROLE, _FIELD_SYSTEM_PROMPT):
|
|
100
|
+
if field in entry and not isinstance(entry[field], str):
|
|
101
|
+
raise RuntimeError(f"agent-contracts at {path}[{agent_name!r}].{field} must be str")
|
|
102
|
+
if _FIELD_TOOLS in entry:
|
|
103
|
+
tools = entry[_FIELD_TOOLS]
|
|
104
|
+
if not isinstance(tools, list) or not all(isinstance(t, str) for t in tools):
|
|
105
|
+
raise RuntimeError(
|
|
106
|
+
f"agent-contracts at {path}[{agent_name!r}].tools must be list[str]"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _coerce(data: dict[str, Any]) -> dict[str, dict[str, Any]]:
|
|
111
|
+
"""Extract known mutable fields per agent. ``model`` etc. dropped
|
|
112
|
+
(Tier 2 guardrail)."""
|
|
113
|
+
result: dict[str, dict[str, Any]] = {}
|
|
114
|
+
for agent_name, entry in data.items():
|
|
115
|
+
if not isinstance(entry, dict):
|
|
116
|
+
continue
|
|
117
|
+
kept: dict[str, Any] = {}
|
|
118
|
+
for field in _MUTABLE_FIELDS:
|
|
119
|
+
if field in entry:
|
|
120
|
+
value = entry[field]
|
|
121
|
+
if field == _FIELD_TOOLS and isinstance(value, list):
|
|
122
|
+
kept[field] = [t for t in value if isinstance(t, str)]
|
|
123
|
+
elif isinstance(value, str):
|
|
124
|
+
kept[field] = value
|
|
125
|
+
if kept:
|
|
126
|
+
result[agent_name] = kept
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def apply_agent_contracts_policy(
|
|
131
|
+
agent_def: Any,
|
|
132
|
+
policy: dict[str, dict[str, Any]] | None,
|
|
133
|
+
) -> Any:
|
|
134
|
+
"""Return a (possibly modified) copy of ``agent_def`` with policy
|
|
135
|
+
overrides applied — role / system_prompt / tools only. ``model``
|
|
136
|
+
field is never touched (Tier 2 guardrail).
|
|
137
|
+
|
|
138
|
+
``policy is None`` or agent name absent from policy → original
|
|
139
|
+
``agent_def`` returned unchanged (no behavior change).
|
|
140
|
+
"""
|
|
141
|
+
if not policy:
|
|
142
|
+
return agent_def
|
|
143
|
+
name = getattr(agent_def, "name", None)
|
|
144
|
+
if not isinstance(name, str) or name not in policy:
|
|
145
|
+
return agent_def
|
|
146
|
+
entry = policy[name]
|
|
147
|
+
if not entry:
|
|
148
|
+
return agent_def
|
|
149
|
+
# Pydantic BaseModel.model_copy(update=...) returns a new instance.
|
|
150
|
+
# Filter overrides to mutable fields only — defensive even though
|
|
151
|
+
# ``_coerce`` already drops everything else.
|
|
152
|
+
overrides = {k: v for k, v in entry.items() if k in _MUTABLE_FIELDS}
|
|
153
|
+
if not overrides:
|
|
154
|
+
return agent_def
|
|
155
|
+
# CSP-1 fix-up (Codex MCP MEDIUM #1) — an agent that declares a
|
|
156
|
+
# ``toolkit:`` will have its ``tools`` field shadowed by the
|
|
157
|
+
# toolkit's resolved set inside ``filter_handlers``. A policy entry
|
|
158
|
+
# that mutates ``tools`` on a toolkit-declaring agent therefore
|
|
159
|
+
# silently does nothing. Warn so operators notice rather than
|
|
160
|
+
# debugging a no-op override later.
|
|
161
|
+
agent_toolkit: str = str(getattr(agent_def, "toolkit", "") or "")
|
|
162
|
+
if _FIELD_TOOLS in overrides and agent_toolkit:
|
|
163
|
+
log.warning(
|
|
164
|
+
"agent_contracts_policy: agent %r declares toolkit=%r; "
|
|
165
|
+
"the policy's ``tools`` override is shadowed at spawn time "
|
|
166
|
+
"(toolkit takes precedence in filter_handlers). Either "
|
|
167
|
+
"remove the ``tools`` override or add a ``toolkit`` field "
|
|
168
|
+
"to the policy entry.",
|
|
169
|
+
name,
|
|
170
|
+
agent_toolkit,
|
|
171
|
+
)
|
|
172
|
+
if hasattr(agent_def, "model_copy"):
|
|
173
|
+
return agent_def.model_copy(update=overrides)
|
|
174
|
+
# Fallback for non-BaseModel doubles (test stubs, dicts) —
|
|
175
|
+
# deep-copy + setattr / item-set.
|
|
176
|
+
new_def = copy.deepcopy(agent_def)
|
|
177
|
+
for k, v in overrides.items():
|
|
178
|
+
if isinstance(new_def, dict):
|
|
179
|
+
new_def[k] = v
|
|
180
|
+
else:
|
|
181
|
+
setattr(new_def, k, v)
|
|
182
|
+
return new_def
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
__all__ = ["apply_agent_contracts_policy"]
|