iac-code 0.3.1__tar.gz → 0.4.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.
- {iac_code-0.3.1 → iac_code-0.4.0}/PKG-INFO +1 -1
- iac_code-0.4.0/src/iac_code/__init__.py +2 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/server.py +135 -28
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/session.py +7 -1
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/slash_registry.py +41 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/agent_loop.py +61 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/cli/main.py +1 -1
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/__init__.py +40 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/auth.py +240 -8
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/clear.py +11 -1
- iac_code-0.4.0/src/iac_code/commands/memory.py +85 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/registry.py +18 -0
- iac_code-0.4.0/src/iac_code/commands/rename.py +43 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/resume.py +25 -4
- iac_code-0.4.0/src/iac_code/commands/skills.py +29 -0
- iac_code-0.4.0/src/iac_code/commands/status.py +98 -0
- iac_code-0.4.0/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po +726 -187
- iac_code-0.4.0/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po +723 -187
- iac_code-0.4.0/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po +724 -187
- iac_code-0.4.0/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po +710 -187
- iac_code-0.4.0/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po +721 -187
- iac_code-0.4.0/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po +703 -187
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/memory/memory_manager.py +71 -16
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/memory/memory_tools.py +6 -1
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/manager.py +22 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/registry.py +1 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/thinking.py +1 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/agent_factory.py +6 -3
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/providers/aliyun.py +107 -5
- iac_code-0.4.0/src/iac_code/services/providers/aliyun_oauth.py +583 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/session_index.py +48 -24
- iac_code-0.4.0/src/iac_code/services/session_metadata.py +78 -0
- iac_code-0.4.0/src/iac_code/services/session_resolver.py +73 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/session_storage.py +116 -5
- iac_code-0.4.0/src/iac_code/services/session_usage.py +176 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/SKILL.md +9 -0
- iac_code-0.4.0/src/iac_code/skills/bundled/iac_aliyun/references/template-parameter-recommendation.md +165 -0
- iac_code-0.4.0/src/iac_code/skills/management.py +81 -0
- iac_code-0.4.0/src/iac_code/skills/settings.py +61 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/skill_tool.py +13 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/base.py +4 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/aliyun_api.py +18 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_client.py +9 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_stack_instances.py +3 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/registry.py +10 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/banner.py +15 -2
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/resume_picker.py +25 -2
- iac_code-0.4.0/src/iac_code/ui/dialogs/skills_picker.py +297 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/repl.py +289 -79
- iac_code-0.4.0/src/iac_code/ui/suggestions/command_provider.py +135 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/token_extractor.py +20 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/project_paths.py +44 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/PKG-INFO +1 -1
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/SOURCES.txt +12 -0
- iac_code-0.3.1/src/iac_code/__init__.py +0 -2
- iac_code-0.3.1/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.1/src/iac_code/ui/suggestions/command_provider.py +0 -43
- {iac_code-0.3.1 → iac_code-0.4.0}/LICENSE +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/MANIFEST.in +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/README.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/pyproject.toml +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/setup.cfg +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/setup.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/agent_card.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/app.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/artifacts.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/client.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/events.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/executor.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/exposure.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/metrics.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/parts.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/persistence.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/push.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/push_queue.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/push_secrets.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/push_worker.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/router.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/signing.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/task_store.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transport.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/base.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/dispatcher.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/grpc.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/grpc_jsonrpc.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/http.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/redis_streams.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/stdio.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/unix.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/transports/websocket.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/a2a/types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/convert.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/http_sse.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/mcp.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/metrics.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/state.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/tools.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/acp/version.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/agent_tool.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/agent_types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/message.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/agent/system_prompt.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/cli/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/cli/headless.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/cli/install_git_bash.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/cli/output_formats.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/compact.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/debug.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/effort.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/exit.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/help.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/model.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/commands/tasks.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/config.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/i18n/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/memory/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/anthropic_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/azure_openai_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/base.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/dashscope_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/deepseek_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/gemini_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/kimi_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/lmstudio_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/minimax_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/modelscope_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/ollama_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/openai_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/openrouter_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/retry.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/siliconflow_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/stream_watchdog.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/volcengine_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/providers/zhipu_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/capabilities/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/capabilities/auto_detect.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/capabilities/multimodal.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/cloud_credentials.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/context_manager.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/permissions/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/permissions/loader.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/permissions/pipeline.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/permissions/storage.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/providers/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/qwenpaw_source.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/attributes.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/client.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/config.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/constants.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/content_serializer.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/events.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/fallback.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/identity.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/metrics.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/names.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/sanitize.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/sink.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/tracing.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/telemetry/types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/token_budget.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/token_counter.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/services/update_checker.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/auto_trigger.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/auto_trigger.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/ecs.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/oss.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/rds.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/redis.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/slb.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/vpc.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/ros-template.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/template-parameters.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/terraform-template.md +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/scripts/tf2ros.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/bundled/simplify.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/discovery.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/frontmatter.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/listing.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/loader.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/processor.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/renderer.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/skills/skill_definition.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/state/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/state/app_state.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tasks/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tasks/notification_queue.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tasks/task_state.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tasks/task_tools.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/bash_tool.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/command_parser.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/mode_validation.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/path_validation.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/permissions.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/readonly_commands.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/rule_matching.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/bash/safety_checks.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/aliyun_doc_search.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/api_hooks.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/endpoints.yml +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/ros_parameters.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/ros_validate.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_stack.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_yaml.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/user_agent.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/base_api.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/base_stack.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/cloud/types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/edit_file.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/glob.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/grep.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/list_files.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/read_file.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/result_storage.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/tool_executor.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/web_fetch.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/tools/write_file.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/types/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/types/permissions.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/types/skill_source.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/types/stream_events.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/dialog.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/divider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/fuzzy_picker.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/progress_bar.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/search_box.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/select.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/status_icon.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/components/tabs.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/in_place_render.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/input_history.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/key_event.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/prompt_input.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/raw_input.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/raw_input_win.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/core/screen.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/global_search.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/history_search.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/model_picker.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/dialogs/quick_open.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/keybindings/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/keybindings/manager.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/renderer.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/spinner.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/aggregator.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/directory_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/file_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/shell_history_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/skill_provider.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/suggestions/types.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/ui/transcript_view.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/background_housekeeping.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/cleanup.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/console.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/file_security.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/__init__.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/clipboard.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/format_detect.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/pasted_content.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/processor.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/resizer.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/image/store.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/json_utils.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/log.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/platform.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/signals.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/tool_input_parser.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code/utils/windows_paths.py +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/dependency_links.txt +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/entry_points.txt +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/requires.txt +0 -0
- {iac_code-0.3.1 → iac_code-0.4.0}/src/iac_code.egg-info/top_level.txt +0 -0
|
@@ -18,8 +18,12 @@ from iac_code.acp.types import ACPContentBlock, MCPServer
|
|
|
18
18
|
from iac_code.acp.version import negotiate_version
|
|
19
19
|
from iac_code.commands import LocalCommand, create_default_registry
|
|
20
20
|
from iac_code.config import DEFAULT_MODEL, get_active_provider_key, load_saved_model
|
|
21
|
+
from iac_code.i18n import _
|
|
21
22
|
from iac_code.services.agent_factory import AgentFactoryOptions, create_agent_runtime
|
|
23
|
+
from iac_code.services.session_index import SessionEntry, SessionIndex
|
|
24
|
+
from iac_code.services.session_resolver import ResolutionStatus, resolve_session_argument
|
|
22
25
|
from iac_code.services.session_storage import SessionStorage
|
|
26
|
+
from iac_code.utils.project_paths import format_resume_command, same_project_path
|
|
23
27
|
|
|
24
28
|
SESSION_IDLE_TIMEOUT = 3600 # 1 hour
|
|
25
29
|
CLEANUP_INTERVAL = 300 # 5 minutes
|
|
@@ -152,7 +156,12 @@ class ACPServer:
|
|
|
152
156
|
runtime.session_id,
|
|
153
157
|
)
|
|
154
158
|
session = ACPSession(
|
|
155
|
-
runtime.session_id,
|
|
159
|
+
runtime.session_id,
|
|
160
|
+
runtime.agent_loop,
|
|
161
|
+
self.conn,
|
|
162
|
+
mcp_configs=mcp_configs,
|
|
163
|
+
metrics=self.metrics,
|
|
164
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
156
165
|
)
|
|
157
166
|
self.sessions[session.id] = session
|
|
158
167
|
self.metrics.record_session_created()
|
|
@@ -228,25 +237,16 @@ class ACPServer:
|
|
|
228
237
|
cwd: str | None = None,
|
|
229
238
|
**kwargs: Any,
|
|
230
239
|
) -> acp.schema.ListSessionsResponse:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
session_ids: list[str] = []
|
|
234
|
-
if cwd:
|
|
235
|
-
project_dir = get_project_dir(cwd)
|
|
236
|
-
if project_dir.exists():
|
|
237
|
-
session_ids = [p.stem for p in project_dir.glob("*.jsonl")]
|
|
238
|
-
else:
|
|
239
|
-
projects_root = get_projects_dir()
|
|
240
|
-
if projects_root.exists():
|
|
241
|
-
session_ids = [p.stem for p in projects_root.glob("*/*.jsonl")]
|
|
240
|
+
index = SessionIndex()
|
|
241
|
+
entries = index.list_for_cwd(cwd) if cwd else index.list_all_projects()
|
|
242
242
|
return acp.schema.ListSessionsResponse(
|
|
243
243
|
sessions=[
|
|
244
244
|
acp.schema.SessionInfo(
|
|
245
|
-
session_id=session_id,
|
|
246
|
-
cwd=cwd or "",
|
|
247
|
-
title=
|
|
245
|
+
session_id=entry.session_id,
|
|
246
|
+
cwd=entry.cwd or cwd or "",
|
|
247
|
+
title=entry.title,
|
|
248
248
|
)
|
|
249
|
-
for
|
|
249
|
+
for entry in entries
|
|
250
250
|
],
|
|
251
251
|
next_cursor=None,
|
|
252
252
|
)
|
|
@@ -297,7 +297,14 @@ class ACPServer:
|
|
|
297
297
|
runtime.agent_loop.context_manager.load_messages(history)
|
|
298
298
|
|
|
299
299
|
# 4. Register session
|
|
300
|
-
session = ACPSession(
|
|
300
|
+
session = ACPSession(
|
|
301
|
+
session_id,
|
|
302
|
+
runtime.agent_loop,
|
|
303
|
+
self.conn,
|
|
304
|
+
mcp_configs=mcp_configs,
|
|
305
|
+
metrics=self.metrics,
|
|
306
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
307
|
+
)
|
|
301
308
|
self.sessions[session_id] = session
|
|
302
309
|
self.metrics.record_session_created()
|
|
303
310
|
logger.info("Session loaded, session_id=%s, history_messages=%d", session_id, len(history))
|
|
@@ -360,7 +367,12 @@ class ACPServer:
|
|
|
360
367
|
|
|
361
368
|
# 4. Register the forked session
|
|
362
369
|
session = ACPSession(
|
|
363
|
-
new_session_id,
|
|
370
|
+
new_session_id,
|
|
371
|
+
runtime.agent_loop,
|
|
372
|
+
self.conn,
|
|
373
|
+
mcp_configs=mcp_configs,
|
|
374
|
+
metrics=self.metrics,
|
|
375
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
364
376
|
)
|
|
365
377
|
self.sessions[new_session_id] = session
|
|
366
378
|
self.metrics.record_session_created()
|
|
@@ -384,20 +396,66 @@ class ACPServer:
|
|
|
384
396
|
mcp_servers: list[MCPServer] | None = None,
|
|
385
397
|
**kwargs: Any,
|
|
386
398
|
) -> acp.schema.ResumeSessionResponse:
|
|
387
|
-
# 1. If session is still active in memory,
|
|
388
|
-
|
|
399
|
+
# 1. If session is still active in memory by exact id, enforce project ownership before returning.
|
|
400
|
+
active_session = self.sessions.get(session_id)
|
|
401
|
+
if active_session is not None:
|
|
402
|
+
error = _active_session_project_error(cwd, session_id, session_id, active_session)
|
|
403
|
+
if error is not None:
|
|
404
|
+
raise error
|
|
389
405
|
await self._push_available_commands(session_id)
|
|
390
406
|
return acp.schema.ResumeSessionResponse()
|
|
391
407
|
|
|
392
408
|
if self.conn is None:
|
|
393
409
|
raise acp.RequestError.internal_error({"error": "ACP client not connected"})
|
|
394
410
|
|
|
395
|
-
|
|
411
|
+
resolution = resolve_session_argument(SessionIndex(), cwd, session_id)
|
|
412
|
+
if resolution.status == ResolutionStatus.NOT_FOUND:
|
|
413
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
414
|
+
if resolution.status == ResolutionStatus.AMBIGUOUS_NAME:
|
|
415
|
+
candidate_ids = [entry.session_id for entry in resolution.candidates]
|
|
416
|
+
message = _("Session name is ambiguous. Candidates: {candidates}").format(
|
|
417
|
+
candidates=", ".join(candidate_ids)
|
|
418
|
+
)
|
|
419
|
+
raise _invalid_params(
|
|
420
|
+
message,
|
|
421
|
+
{
|
|
422
|
+
"session_id": session_id,
|
|
423
|
+
"candidates": [_resume_candidate_data(entry) for entry in resolution.candidates],
|
|
424
|
+
},
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
entry = resolution.entry
|
|
428
|
+
if entry is None: # pragma: no cover - defensive guard for inconsistent resolver output
|
|
429
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
430
|
+
|
|
431
|
+
resolved_session_id = entry.session_id
|
|
432
|
+
if entry.cwd and not same_project_path(entry.cwd, cwd):
|
|
433
|
+
hint = _resume_command(entry.cwd, resolved_session_id)
|
|
434
|
+
message = _("Session belongs to another project. Run: {hint}").format(hint=hint)
|
|
435
|
+
raise _invalid_params(
|
|
436
|
+
message,
|
|
437
|
+
{
|
|
438
|
+
"session_id": session_id,
|
|
439
|
+
"resolved_session_id": resolved_session_id,
|
|
440
|
+
"cwd": entry.cwd,
|
|
441
|
+
"hint": hint,
|
|
442
|
+
},
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
active_session = self.sessions.get(resolved_session_id)
|
|
446
|
+
if active_session is not None:
|
|
447
|
+
error = _active_session_project_error(cwd, session_id, resolved_session_id, active_session)
|
|
448
|
+
if error is not None:
|
|
449
|
+
raise error
|
|
450
|
+
await self._push_available_commands(resolved_session_id)
|
|
451
|
+
return acp.schema.ResumeSessionResponse()
|
|
452
|
+
|
|
453
|
+
# 2. Try to load persisted history from SessionStorage.
|
|
396
454
|
storage = SessionStorage()
|
|
397
|
-
if not storage.exists(cwd,
|
|
398
|
-
raise
|
|
455
|
+
if not storage.exists(cwd, resolved_session_id):
|
|
456
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
399
457
|
|
|
400
|
-
history = storage.load(cwd,
|
|
458
|
+
history = storage.load(cwd, resolved_session_id)
|
|
401
459
|
history = SessionStorage.repair_interrupted(history)
|
|
402
460
|
|
|
403
461
|
# Convert MCP server configs from ACP protocol types to internal dicts
|
|
@@ -405,7 +463,7 @@ class ACPServer:
|
|
|
405
463
|
|
|
406
464
|
# 3. Rebuild agent runtime with restored history
|
|
407
465
|
model = load_saved_model() or DEFAULT_MODEL
|
|
408
|
-
runtime = self._create_runtime_with_auth_check(model=model, session_id=
|
|
466
|
+
runtime = self._create_runtime_with_auth_check(model=model, session_id=resolved_session_id, cwd=cwd)
|
|
409
467
|
replace_bash_with_acp_terminal(
|
|
410
468
|
runtime.tool_registry,
|
|
411
469
|
self.client_capabilities,
|
|
@@ -418,10 +476,17 @@ class ACPServer:
|
|
|
418
476
|
runtime.agent_loop.context_manager.load_messages(history)
|
|
419
477
|
|
|
420
478
|
# 4. Register the resumed session
|
|
421
|
-
session = ACPSession(
|
|
422
|
-
|
|
479
|
+
session = ACPSession(
|
|
480
|
+
resolved_session_id,
|
|
481
|
+
runtime.agent_loop,
|
|
482
|
+
self.conn,
|
|
483
|
+
mcp_configs=mcp_configs,
|
|
484
|
+
metrics=self.metrics,
|
|
485
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
486
|
+
)
|
|
487
|
+
self.sessions[resolved_session_id] = session
|
|
423
488
|
self.metrics.record_session_created()
|
|
424
|
-
await self._push_available_commands(
|
|
489
|
+
await self._push_available_commands(resolved_session_id)
|
|
425
490
|
|
|
426
491
|
return acp.schema.ResumeSessionResponse()
|
|
427
492
|
|
|
@@ -619,6 +684,48 @@ def _convert_mcp_servers(mcp_servers: list[MCPServer] | None) -> list[dict[str,
|
|
|
619
684
|
return configs
|
|
620
685
|
|
|
621
686
|
|
|
687
|
+
def _invalid_params(message: str, data: dict[str, Any] | None = None) -> acp.RequestError:
|
|
688
|
+
"""Create an ACP invalid-params error with a useful message."""
|
|
689
|
+
return acp.RequestError(-32602, message, data)
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def _resume_command(cwd: str, session_id: str) -> str:
|
|
693
|
+
return format_resume_command(cwd, session_id)
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def _active_session_cwd(session: ACPSession) -> str | None:
|
|
697
|
+
cwd = getattr(session.agent_loop, "_cwd", None)
|
|
698
|
+
return cwd if isinstance(cwd, str) and cwd else None
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _active_session_project_error(
|
|
702
|
+
cwd: str, session_id: str, resolved_session_id: str, session: ACPSession
|
|
703
|
+
) -> acp.RequestError | None:
|
|
704
|
+
active_cwd = _active_session_cwd(session)
|
|
705
|
+
if not active_cwd or same_project_path(active_cwd, cwd):
|
|
706
|
+
return None
|
|
707
|
+
hint = _resume_command(active_cwd, resolved_session_id)
|
|
708
|
+
message = _("Session belongs to another project. Run: {hint}").format(hint=hint)
|
|
709
|
+
return _invalid_params(
|
|
710
|
+
message,
|
|
711
|
+
{
|
|
712
|
+
"session_id": session_id,
|
|
713
|
+
"resolved_session_id": resolved_session_id,
|
|
714
|
+
"cwd": active_cwd,
|
|
715
|
+
"hint": hint,
|
|
716
|
+
},
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
def _resume_candidate_data(entry: SessionEntry) -> dict[str, str | None]:
|
|
721
|
+
return {
|
|
722
|
+
"session_id": entry.session_id,
|
|
723
|
+
"name": entry.name,
|
|
724
|
+
"cwd": entry.cwd,
|
|
725
|
+
"command": _resume_command(entry.cwd, entry.session_id),
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
|
|
622
729
|
# ---------------------------------------------------------------------------
|
|
623
730
|
# Auth methods declaration
|
|
624
731
|
# ---------------------------------------------------------------------------
|
|
@@ -165,9 +165,11 @@ class ACPSession:
|
|
|
165
165
|
conn: acp.Client,
|
|
166
166
|
mcp_configs: list[dict] | None = None,
|
|
167
167
|
metrics: ACPMetrics | None = None,
|
|
168
|
+
memory_manager=None,
|
|
168
169
|
) -> None:
|
|
169
170
|
self.id = session_id
|
|
170
171
|
self.agent_loop = agent_loop
|
|
172
|
+
self.memory_manager = memory_manager
|
|
171
173
|
self._conn = conn
|
|
172
174
|
self._current_task: asyncio.Task | None = None
|
|
173
175
|
self._replay_task: asyncio.Task[None] | None = None
|
|
@@ -292,7 +294,11 @@ class ACPSession:
|
|
|
292
294
|
prompt_text = acp_blocks_to_prompt_text(prompt)
|
|
293
295
|
slash_registry = ACPSlashRegistry()
|
|
294
296
|
if slash_registry.is_slash_command(prompt_text):
|
|
295
|
-
result = await slash_registry.execute(
|
|
297
|
+
result = await slash_registry.execute(
|
|
298
|
+
prompt_text,
|
|
299
|
+
self.agent_loop,
|
|
300
|
+
memory_manager=self.memory_manager,
|
|
301
|
+
)
|
|
296
302
|
await self._conn.session_update(
|
|
297
303
|
session_id=self.id,
|
|
298
304
|
update=acp.schema.AgentMessageChunk(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""ACP slash command registry.
|
|
2
2
|
|
|
3
3
|
Manages commands supported over the ACP protocol.
|
|
4
|
-
Only /compact, /clear, and /
|
|
4
|
+
Only /compact, /clear, /debug, /memory, and /rename are allowed;
|
|
5
5
|
all other slash commands are rejected with a clear message.
|
|
6
6
|
"""
|
|
7
7
|
|
|
@@ -10,10 +10,12 @@ from __future__ import annotations
|
|
|
10
10
|
import logging
|
|
11
11
|
|
|
12
12
|
from iac_code.i18n import _
|
|
13
|
+
from iac_code.services.session_metadata import normalize_session_name
|
|
14
|
+
from iac_code.services.session_storage import SessionStorage
|
|
13
15
|
|
|
14
16
|
logger = logging.getLogger(__name__)
|
|
15
17
|
|
|
16
|
-
ACP_SUPPORTED_COMMANDS: frozenset[str] = frozenset({"compact", "clear", "debug"})
|
|
18
|
+
ACP_SUPPORTED_COMMANDS: frozenset[str] = frozenset({"compact", "clear", "debug", "memory", "rename"})
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class ACPSlashRegistry:
|
|
@@ -51,6 +53,10 @@ class ACPSlashRegistry:
|
|
|
51
53
|
return await self._handle_clear(agent_loop)
|
|
52
54
|
if cmd_name == "debug":
|
|
53
55
|
return self._handle_debug(args_str)
|
|
56
|
+
if cmd_name == "memory":
|
|
57
|
+
return self._handle_memory(args_str, context.get("memory_manager"))
|
|
58
|
+
if cmd_name == "rename":
|
|
59
|
+
return self._handle_rename(args_str, agent_loop)
|
|
54
60
|
|
|
55
61
|
# Should not reach here
|
|
56
62
|
return _("Command '/{cmd_name}' handler not implemented.").format(cmd_name=cmd_name) # pragma: no cover
|
|
@@ -123,3 +129,36 @@ class ACPSlashRegistry:
|
|
|
123
129
|
return _("Debug logging disabled.")
|
|
124
130
|
|
|
125
131
|
return _("Usage: /debug [on|off]")
|
|
132
|
+
|
|
133
|
+
def _handle_memory(self, args: str, memory_manager) -> str:
|
|
134
|
+
"""View and manage persistent memories."""
|
|
135
|
+
if memory_manager is None:
|
|
136
|
+
return _("Memory manager is unavailable.")
|
|
137
|
+
|
|
138
|
+
from iac_code.commands.memory import execute_memory_command
|
|
139
|
+
|
|
140
|
+
return execute_memory_command(memory_manager, args.split())
|
|
141
|
+
|
|
142
|
+
def _handle_rename(self, args: str, agent_loop) -> str:
|
|
143
|
+
"""Rename the current ACP session non-interactively."""
|
|
144
|
+
parts = args.split()
|
|
145
|
+
if len(parts) != 1:
|
|
146
|
+
return _("Usage: /rename <name>")
|
|
147
|
+
|
|
148
|
+
cwd = getattr(agent_loop, "_cwd", None)
|
|
149
|
+
session_id = getattr(agent_loop, "_session_id", None)
|
|
150
|
+
git_branch = getattr(agent_loop, "_current_git_branch", None)
|
|
151
|
+
if not isinstance(cwd, str) or not isinstance(session_id, str):
|
|
152
|
+
return _("Rename is only available after a session is created.")
|
|
153
|
+
if not isinstance(git_branch, str):
|
|
154
|
+
git_branch = None
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
name = normalize_session_name(parts[0])
|
|
158
|
+
result = SessionStorage().rename_session(cwd, session_id, name, git_branch=git_branch)
|
|
159
|
+
except ValueError as exc:
|
|
160
|
+
return str(exc)
|
|
161
|
+
|
|
162
|
+
if result == "unchanged":
|
|
163
|
+
return _("Session is already named {name}").format(name=name)
|
|
164
|
+
return _("Renamed session to {name}").format(name=name)
|
|
@@ -15,6 +15,7 @@ from loguru import logger
|
|
|
15
15
|
from iac_code.agent.message import ContentBlock, TextBlock, ThinkingBlock, ToolResultBlock, ToolUseBlock
|
|
16
16
|
from iac_code.i18n import _
|
|
17
17
|
from iac_code.services.context_manager import ContextManager
|
|
18
|
+
from iac_code.services.session_usage import SessionUsageStore, SessionUsageTotals
|
|
18
19
|
from iac_code.tools.base import ToolContext, ToolRegistry, ToolResult
|
|
19
20
|
from iac_code.tools.result_storage import ResultStorage
|
|
20
21
|
from iac_code.tools.tool_executor import ToolCallRequest, ToolExecutor
|
|
@@ -65,6 +66,7 @@ class AgentLoop:
|
|
|
65
66
|
tool_registry: ToolRegistry,
|
|
66
67
|
max_turns: int = 100,
|
|
67
68
|
session_storage: Any = None, # SessionStorage
|
|
69
|
+
session_usage_store: SessionUsageStore | None = None,
|
|
68
70
|
session_id: str | None = None,
|
|
69
71
|
resume_messages: list | None = None,
|
|
70
72
|
cwd: str | None = None,
|
|
@@ -79,6 +81,8 @@ class AgentLoop:
|
|
|
79
81
|
self._session_storage = session_storage
|
|
80
82
|
self._session_id = session_id or str(uuid.uuid4())[:8]
|
|
81
83
|
self._cwd = cwd or os.getcwd()
|
|
84
|
+
self._session_usage_store = session_usage_store or SessionUsageStore()
|
|
85
|
+
self._session_usage_totals = self._session_usage_store.load(self._cwd, self._session_id)
|
|
82
86
|
self._permission_context = permission_context
|
|
83
87
|
self._permission_context_getter = permission_context_getter
|
|
84
88
|
self._auto_trigger_skills = auto_trigger_skills or []
|
|
@@ -113,6 +117,10 @@ class AgentLoop:
|
|
|
113
117
|
self.system_prompt = system_prompt
|
|
114
118
|
self.context_manager.set_system_prompt(system_prompt)
|
|
115
119
|
|
|
120
|
+
def set_auto_trigger_skills(self, skill_commands: list[Any] | None) -> None:
|
|
121
|
+
"""Refresh skills considered for automatic trigger injection."""
|
|
122
|
+
self._auto_trigger_skills = list(skill_commands or [])
|
|
123
|
+
|
|
116
124
|
def _get_tool_definitions(self):
|
|
117
125
|
"""Convert tool registry to provider ToolDefinition format."""
|
|
118
126
|
from iac_code.providers.base import ToolDefinition
|
|
@@ -250,6 +258,7 @@ class AgentLoop:
|
|
|
250
258
|
final_text_chunks.append(event.text)
|
|
251
259
|
if isinstance(event, MessageEndEvent):
|
|
252
260
|
final_stop_reason = event.stop_reason
|
|
261
|
+
self._record_session_usage(event.usage)
|
|
253
262
|
yield event
|
|
254
263
|
except asyncio.CancelledError:
|
|
255
264
|
log_event(Events.SESSION_CANCELLED, {"stage": "in_query"})
|
|
@@ -609,6 +618,7 @@ class AgentLoop:
|
|
|
609
618
|
messages=[ProviderMessage.user(compaction_prompt)],
|
|
610
619
|
system="You are a helpful assistant that summarizes conversations concisely.",
|
|
611
620
|
)
|
|
621
|
+
self._record_response_usage(response)
|
|
612
622
|
if response.text:
|
|
613
623
|
original, new = self.context_manager.apply_compaction(response.text)
|
|
614
624
|
duration_ms = int((time.monotonic() - started) * 1000)
|
|
@@ -650,6 +660,7 @@ class AgentLoop:
|
|
|
650
660
|
messages=[ProviderMessage.user(compaction_prompt)],
|
|
651
661
|
system="You are a helpful assistant that summarizes conversations concisely.",
|
|
652
662
|
)
|
|
663
|
+
self._record_response_usage(response)
|
|
653
664
|
if response.text:
|
|
654
665
|
original, compacted = self.context_manager.apply_compaction(response.text)
|
|
655
666
|
return CompactResult(
|
|
@@ -691,6 +702,7 @@ class AgentLoop:
|
|
|
691
702
|
self.context_manager.reset()
|
|
692
703
|
if resume_messages:
|
|
693
704
|
self.context_manager.load_messages(resume_messages)
|
|
705
|
+
self._session_usage_totals = self._session_usage_store.load(self._cwd, self._session_id)
|
|
694
706
|
self._result_storage = ResultStorage(
|
|
695
707
|
storage_dir=os.path.join(str(get_config_dir()), "tool-results", session_id),
|
|
696
708
|
)
|
|
@@ -712,5 +724,54 @@ class AgentLoop:
|
|
|
712
724
|
self._auto_loaded_skills.clear()
|
|
713
725
|
self.context_manager.reset()
|
|
714
726
|
|
|
727
|
+
@property
|
|
728
|
+
def session_id(self) -> str:
|
|
729
|
+
return self._session_id
|
|
730
|
+
|
|
731
|
+
@property
|
|
732
|
+
def max_turns(self) -> int:
|
|
733
|
+
return self._max_turns
|
|
734
|
+
|
|
715
735
|
def get_context_usage(self) -> dict:
|
|
716
736
|
return self.context_manager.get_usage()
|
|
737
|
+
|
|
738
|
+
def get_session_usage(self) -> SessionUsageTotals:
|
|
739
|
+
return self._session_usage_totals.copy()
|
|
740
|
+
|
|
741
|
+
def _record_session_usage(self, usage: Usage) -> None:
|
|
742
|
+
if not self._session_usage_totals.add(usage):
|
|
743
|
+
return
|
|
744
|
+
|
|
745
|
+
provider = self._get_runtime_provider_key()
|
|
746
|
+
model = self._provider_manager.get_model_name() if hasattr(self._provider_manager, "get_model_name") else ""
|
|
747
|
+
try:
|
|
748
|
+
self._session_usage_store.append(
|
|
749
|
+
self._cwd,
|
|
750
|
+
self._session_id,
|
|
751
|
+
usage,
|
|
752
|
+
provider=provider,
|
|
753
|
+
model=model,
|
|
754
|
+
)
|
|
755
|
+
except Exception as exc:
|
|
756
|
+
logger.debug("Failed to persist session usage for {}: {}", self._session_id, exc)
|
|
757
|
+
|
|
758
|
+
def _record_response_usage(self, response: Any) -> None:
|
|
759
|
+
usage = getattr(response, "usage", None)
|
|
760
|
+
if isinstance(usage, Usage):
|
|
761
|
+
self._record_session_usage(usage)
|
|
762
|
+
|
|
763
|
+
def _get_runtime_provider_key(self) -> str:
|
|
764
|
+
if hasattr(self._provider_manager, "get_provider_key"):
|
|
765
|
+
try:
|
|
766
|
+
provider_key = self._provider_manager.get_provider_key()
|
|
767
|
+
except Exception:
|
|
768
|
+
pass
|
|
769
|
+
else:
|
|
770
|
+
if isinstance(provider_key, str):
|
|
771
|
+
return provider_key
|
|
772
|
+
try:
|
|
773
|
+
from iac_code.config import get_active_provider_key
|
|
774
|
+
|
|
775
|
+
return get_active_provider_key() or ""
|
|
776
|
+
except Exception:
|
|
777
|
+
return ""
|
|
@@ -86,7 +86,7 @@ def main(
|
|
|
86
86
|
debug: bool = typer.Option(False, "--debug", "-d", help=_("Enable debug logging")),
|
|
87
87
|
verbose: bool = typer.Option(False, "--verbose", help=_("Show headless progress on stderr")),
|
|
88
88
|
version: bool = typer.Option(False, "--version", "-v", "-V", is_eager=True, help=_("Show version and exit")),
|
|
89
|
-
resume: str = typer.Option("", "--resume", "-r", help=_("Resume a session by ID")),
|
|
89
|
+
resume: str = typer.Option("", "--resume", "-r", help=_("Resume a session by ID or name")),
|
|
90
90
|
continue_session: bool = typer.Option(False, "--continue", "-c", help=_("Resume the most recent session")),
|
|
91
91
|
install_completion: bool = typer.Option(
|
|
92
92
|
None,
|
|
@@ -7,9 +7,13 @@ from iac_code.commands.debug import debug_command
|
|
|
7
7
|
from iac_code.commands.effort import effort_command
|
|
8
8
|
from iac_code.commands.exit import exit_command
|
|
9
9
|
from iac_code.commands.help import help_command
|
|
10
|
+
from iac_code.commands.memory import memory_command
|
|
10
11
|
from iac_code.commands.model import model_command
|
|
11
|
-
from iac_code.commands.registry import Command, CommandRegistry, LocalCommand, PromptCommand
|
|
12
|
+
from iac_code.commands.registry import Command, CommandRegistry, CommandResult, LocalCommand, PromptCommand
|
|
13
|
+
from iac_code.commands.rename import rename_command
|
|
12
14
|
from iac_code.commands.resume import resume_command
|
|
15
|
+
from iac_code.commands.skills import skills_command
|
|
16
|
+
from iac_code.commands.status import status_command
|
|
13
17
|
from iac_code.i18n import _
|
|
14
18
|
|
|
15
19
|
|
|
@@ -87,6 +91,15 @@ def create_default_registry() -> CommandRegistry:
|
|
|
87
91
|
history_mode="session",
|
|
88
92
|
)
|
|
89
93
|
)
|
|
94
|
+
registry.register(
|
|
95
|
+
LocalCommand(
|
|
96
|
+
name="memory",
|
|
97
|
+
description=_("View and manage persistent memories"),
|
|
98
|
+
handler=memory_command,
|
|
99
|
+
arg_hint=_("[<name>|search <query>|delete <name>|help]"),
|
|
100
|
+
history_mode="session",
|
|
101
|
+
)
|
|
102
|
+
)
|
|
90
103
|
registry.register(
|
|
91
104
|
LocalCommand(
|
|
92
105
|
name="resume",
|
|
@@ -96,7 +109,32 @@ def create_default_registry() -> CommandRegistry:
|
|
|
96
109
|
history_mode="session",
|
|
97
110
|
)
|
|
98
111
|
)
|
|
112
|
+
registry.register(
|
|
113
|
+
LocalCommand(
|
|
114
|
+
name="rename",
|
|
115
|
+
description=_("Rename the current session"),
|
|
116
|
+
handler=rename_command,
|
|
117
|
+
arg_hint="<name>",
|
|
118
|
+
history_mode="session",
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
registry.register(
|
|
122
|
+
LocalCommand(
|
|
123
|
+
name="skills",
|
|
124
|
+
description=_("Manage skills"),
|
|
125
|
+
handler=skills_command,
|
|
126
|
+
history_mode="session",
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
registry.register(
|
|
130
|
+
LocalCommand(
|
|
131
|
+
name="status",
|
|
132
|
+
description=_("Show current session status"),
|
|
133
|
+
handler=status_command,
|
|
134
|
+
history_mode="session",
|
|
135
|
+
)
|
|
136
|
+
)
|
|
99
137
|
return registry
|
|
100
138
|
|
|
101
139
|
|
|
102
|
-
__all__ = ["Command", "CommandRegistry", "LocalCommand", "PromptCommand", "create_default_registry"]
|
|
140
|
+
__all__ = ["Command", "CommandRegistry", "CommandResult", "LocalCommand", "PromptCommand", "create_default_registry"]
|