iac-code 0.1.0__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.
Files changed (184) hide show
  1. iac_code/__init__.py +2 -0
  2. iac_code/acp/__init__.py +97 -0
  3. iac_code/acp/convert.py +423 -0
  4. iac_code/acp/http_sse.py +448 -0
  5. iac_code/acp/mcp.py +54 -0
  6. iac_code/acp/metrics.py +71 -0
  7. iac_code/acp/server.py +662 -0
  8. iac_code/acp/session.py +446 -0
  9. iac_code/acp/slash_registry.py +125 -0
  10. iac_code/acp/state.py +99 -0
  11. iac_code/acp/tools.py +112 -0
  12. iac_code/acp/types.py +13 -0
  13. iac_code/acp/version.py +26 -0
  14. iac_code/agent/__init__.py +19 -0
  15. iac_code/agent/agent_loop.py +640 -0
  16. iac_code/agent/agent_tool.py +269 -0
  17. iac_code/agent/agent_types.py +87 -0
  18. iac_code/agent/message.py +153 -0
  19. iac_code/agent/system_prompt.py +313 -0
  20. iac_code/cli/__init__.py +3 -0
  21. iac_code/cli/headless.py +114 -0
  22. iac_code/cli/main.py +246 -0
  23. iac_code/cli/output_formats.py +125 -0
  24. iac_code/commands/__init__.py +93 -0
  25. iac_code/commands/auth.py +1055 -0
  26. iac_code/commands/clear.py +34 -0
  27. iac_code/commands/compact.py +43 -0
  28. iac_code/commands/debug.py +45 -0
  29. iac_code/commands/effort.py +116 -0
  30. iac_code/commands/exit.py +10 -0
  31. iac_code/commands/help.py +49 -0
  32. iac_code/commands/model.py +130 -0
  33. iac_code/commands/registry.py +245 -0
  34. iac_code/commands/resume.py +49 -0
  35. iac_code/commands/tasks.py +41 -0
  36. iac_code/config.py +304 -0
  37. iac_code/i18n/__init__.py +141 -0
  38. iac_code/i18n/locales/zh/LC_MESSAGES/messages.po +1355 -0
  39. iac_code/memory/__init__.py +1 -0
  40. iac_code/memory/memory_manager.py +92 -0
  41. iac_code/memory/memory_tools.py +88 -0
  42. iac_code/providers/__init__.py +1 -0
  43. iac_code/providers/anthropic_provider.py +284 -0
  44. iac_code/providers/base.py +128 -0
  45. iac_code/providers/dashscope_provider.py +47 -0
  46. iac_code/providers/deepseek_provider.py +36 -0
  47. iac_code/providers/manager.py +399 -0
  48. iac_code/providers/openai_provider.py +344 -0
  49. iac_code/providers/retry.py +58 -0
  50. iac_code/providers/stream_watchdog.py +47 -0
  51. iac_code/providers/thinking.py +164 -0
  52. iac_code/services/__init__.py +1 -0
  53. iac_code/services/agent_factory.py +127 -0
  54. iac_code/services/cloud_credentials.py +22 -0
  55. iac_code/services/context_manager.py +221 -0
  56. iac_code/services/providers/__init__.py +1 -0
  57. iac_code/services/providers/aliyun.py +232 -0
  58. iac_code/services/session_index.py +281 -0
  59. iac_code/services/session_storage.py +245 -0
  60. iac_code/services/telemetry/__init__.py +66 -0
  61. iac_code/services/telemetry/attributes.py +84 -0
  62. iac_code/services/telemetry/client.py +330 -0
  63. iac_code/services/telemetry/config.py +76 -0
  64. iac_code/services/telemetry/constants.py +75 -0
  65. iac_code/services/telemetry/content_serializer.py +124 -0
  66. iac_code/services/telemetry/events.py +42 -0
  67. iac_code/services/telemetry/fallback.py +59 -0
  68. iac_code/services/telemetry/identity.py +73 -0
  69. iac_code/services/telemetry/metrics.py +62 -0
  70. iac_code/services/telemetry/names.py +199 -0
  71. iac_code/services/telemetry/sanitize.py +88 -0
  72. iac_code/services/telemetry/sink.py +67 -0
  73. iac_code/services/telemetry/tracing.py +38 -0
  74. iac_code/services/telemetry/types.py +13 -0
  75. iac_code/services/token_budget.py +54 -0
  76. iac_code/services/token_counter.py +76 -0
  77. iac_code/skills/__init__.py +1 -0
  78. iac_code/skills/bundled/__init__.py +94 -0
  79. iac_code/skills/bundled/iac_aliyun/SKILL.md +192 -0
  80. iac_code/skills/bundled/iac_aliyun/__init__.py +16 -0
  81. iac_code/skills/bundled/iac_aliyun/references/cloud-products/ecs.md +167 -0
  82. iac_code/skills/bundled/iac_aliyun/references/cloud-products/oss.md +69 -0
  83. iac_code/skills/bundled/iac_aliyun/references/cloud-products/rds.md +95 -0
  84. iac_code/skills/bundled/iac_aliyun/references/cloud-products/redis.md +100 -0
  85. iac_code/skills/bundled/iac_aliyun/references/cloud-products/slb.md +60 -0
  86. iac_code/skills/bundled/iac_aliyun/references/cloud-products/vpc.md +54 -0
  87. iac_code/skills/bundled/iac_aliyun/references/ros-template.md +155 -0
  88. iac_code/skills/bundled/iac_aliyun/references/template-parameters.md +206 -0
  89. iac_code/skills/bundled/iac_aliyun/references/terraform-template.md +101 -0
  90. iac_code/skills/bundled/iac_aliyun/scripts/tf2ros.py +77 -0
  91. iac_code/skills/bundled/simplify.py +28 -0
  92. iac_code/skills/discovery.py +136 -0
  93. iac_code/skills/frontmatter.py +119 -0
  94. iac_code/skills/listing.py +92 -0
  95. iac_code/skills/loader.py +42 -0
  96. iac_code/skills/processor.py +81 -0
  97. iac_code/skills/renderer.py +157 -0
  98. iac_code/skills/skill_definition.py +82 -0
  99. iac_code/skills/skill_tool.py +261 -0
  100. iac_code/state/__init__.py +5 -0
  101. iac_code/state/app_state.py +122 -0
  102. iac_code/tasks/__init__.py +1 -0
  103. iac_code/tasks/notification_queue.py +28 -0
  104. iac_code/tasks/task_state.py +66 -0
  105. iac_code/tasks/task_tools.py +114 -0
  106. iac_code/tools/__init__.py +8 -0
  107. iac_code/tools/base.py +226 -0
  108. iac_code/tools/bash.py +133 -0
  109. iac_code/tools/cloud/__init__.py +0 -0
  110. iac_code/tools/cloud/aliyun/__init__.py +0 -0
  111. iac_code/tools/cloud/aliyun/aliyun_api.py +510 -0
  112. iac_code/tools/cloud/aliyun/aliyun_doc_search.py +145 -0
  113. iac_code/tools/cloud/aliyun/endpoints.yml +343 -0
  114. iac_code/tools/cloud/aliyun/ros_client.py +56 -0
  115. iac_code/tools/cloud/aliyun/ros_stack.py +633 -0
  116. iac_code/tools/cloud/aliyun/ros_stack_instances.py +247 -0
  117. iac_code/tools/cloud/base_api.py +162 -0
  118. iac_code/tools/cloud/base_stack.py +242 -0
  119. iac_code/tools/cloud/registry.py +20 -0
  120. iac_code/tools/cloud/types.py +105 -0
  121. iac_code/tools/edit_file.py +121 -0
  122. iac_code/tools/glob.py +103 -0
  123. iac_code/tools/grep.py +254 -0
  124. iac_code/tools/list_files.py +104 -0
  125. iac_code/tools/read_file.py +127 -0
  126. iac_code/tools/result_storage.py +39 -0
  127. iac_code/tools/tool_executor.py +165 -0
  128. iac_code/tools/web_fetch.py +177 -0
  129. iac_code/tools/write_file.py +88 -0
  130. iac_code/types/__init__.py +40 -0
  131. iac_code/types/permissions.py +26 -0
  132. iac_code/types/skill_source.py +11 -0
  133. iac_code/types/stream_events.py +227 -0
  134. iac_code/ui/__init__.py +5 -0
  135. iac_code/ui/banner.py +110 -0
  136. iac_code/ui/components/__init__.py +0 -0
  137. iac_code/ui/components/dialog.py +142 -0
  138. iac_code/ui/components/divider.py +20 -0
  139. iac_code/ui/components/fuzzy_picker.py +308 -0
  140. iac_code/ui/components/progress_bar.py +54 -0
  141. iac_code/ui/components/search_box.py +165 -0
  142. iac_code/ui/components/select.py +319 -0
  143. iac_code/ui/components/status_icon.py +42 -0
  144. iac_code/ui/components/tabs.py +128 -0
  145. iac_code/ui/core/__init__.py +0 -0
  146. iac_code/ui/core/in_place_render.py +129 -0
  147. iac_code/ui/core/input_history.py +118 -0
  148. iac_code/ui/core/key_event.py +41 -0
  149. iac_code/ui/core/prompt_input.py +507 -0
  150. iac_code/ui/core/raw_input.py +302 -0
  151. iac_code/ui/core/screen.py +80 -0
  152. iac_code/ui/dialogs/__init__.py +0 -0
  153. iac_code/ui/dialogs/global_search.py +178 -0
  154. iac_code/ui/dialogs/history_search.py +100 -0
  155. iac_code/ui/dialogs/model_picker.py +280 -0
  156. iac_code/ui/dialogs/quick_open.py +108 -0
  157. iac_code/ui/dialogs/resume_picker.py +749 -0
  158. iac_code/ui/keybindings/__init__.py +0 -0
  159. iac_code/ui/keybindings/manager.py +124 -0
  160. iac_code/ui/renderer.py +1535 -0
  161. iac_code/ui/repl.py +772 -0
  162. iac_code/ui/spinner.py +112 -0
  163. iac_code/ui/suggestions/__init__.py +0 -0
  164. iac_code/ui/suggestions/aggregator.py +171 -0
  165. iac_code/ui/suggestions/command_provider.py +43 -0
  166. iac_code/ui/suggestions/directory_provider.py +95 -0
  167. iac_code/ui/suggestions/file_provider.py +121 -0
  168. iac_code/ui/suggestions/shell_history_provider.py +108 -0
  169. iac_code/ui/suggestions/token_extractor.py +77 -0
  170. iac_code/ui/suggestions/types.py +45 -0
  171. iac_code/ui/transcript_view.py +199 -0
  172. iac_code/utils/__init__.py +0 -0
  173. iac_code/utils/background_housekeeping.py +53 -0
  174. iac_code/utils/cleanup.py +68 -0
  175. iac_code/utils/json_utils.py +60 -0
  176. iac_code/utils/log.py +150 -0
  177. iac_code/utils/project_paths.py +74 -0
  178. iac_code/utils/tool_input_parser.py +62 -0
  179. iac_code-0.1.0.dist-info/LICENSE +201 -0
  180. iac_code-0.1.0.dist-info/METADATA +64 -0
  181. iac_code-0.1.0.dist-info/RECORD +184 -0
  182. iac_code-0.1.0.dist-info/WHEEL +5 -0
  183. iac_code-0.1.0.dist-info/entry_points.txt +2 -0
  184. iac_code-0.1.0.dist-info/top_level.txt +1 -0
iac_code/acp/tools.py ADDED
@@ -0,0 +1,112 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from contextlib import suppress
5
+
6
+ import acp
7
+
8
+ from iac_code.tools.base import Tool, ToolContext, ToolResult
9
+
10
+ TERMINAL_TIMEOUT = 300 # 5 minutes default timeout
11
+
12
+
13
+ class ACPTerminalBashTool(Tool):
14
+ def __init__(self, original: Tool, conn: acp.Client, session_id: str) -> None:
15
+ self._original = original
16
+ self._conn = conn
17
+ self._session_id = session_id
18
+
19
+ @property
20
+ def name(self) -> str:
21
+ return self._original.name
22
+
23
+ @property
24
+ def description(self) -> str:
25
+ return self._original.description
26
+
27
+ @property
28
+ def input_schema(self) -> dict:
29
+ return self._original.input_schema
30
+
31
+ @property
32
+ def timeout(self) -> float | None:
33
+ return self._original.timeout
34
+
35
+ def is_read_only(self, input: dict | None = None) -> bool:
36
+ return self._original.is_read_only(input)
37
+
38
+ def is_destructive(self, input: dict | None = None) -> bool:
39
+ return self._original.is_destructive(input)
40
+
41
+ async def check_permissions(self, input: dict, context: dict | None = None):
42
+ return await self._original.check_permissions(input, context)
43
+
44
+ async def execute(self, *, tool_input: dict, context: ToolContext) -> ToolResult:
45
+ command = tool_input.get("command")
46
+ if not command:
47
+ return ToolResult.error("Bash command is required.")
48
+
49
+ timeout = tool_input.get("timeout", TERMINAL_TIMEOUT)
50
+ terminal_id: str | None = None
51
+ try:
52
+ created = await self._conn.create_terminal(
53
+ command=command,
54
+ session_id=self._session_id,
55
+ cwd=context.cwd,
56
+ output_byte_limit=50_000,
57
+ )
58
+ terminal_id = created.terminal_id
59
+
60
+ try:
61
+ async with asyncio.timeout(timeout):
62
+ exit_status = await self._conn.wait_for_terminal_exit(
63
+ session_id=self._session_id,
64
+ terminal_id=terminal_id,
65
+ )
66
+ output = await self._conn.terminal_output(
67
+ session_id=self._session_id,
68
+ terminal_id=terminal_id,
69
+ )
70
+ except TimeoutError:
71
+ with suppress(Exception):
72
+ await self._conn.kill_terminal(session_id=self._session_id, terminal_id=terminal_id)
73
+ return ToolResult.error(f"Command timed out after {timeout} seconds")
74
+
75
+ if output.exit_status:
76
+ exit_status = output.exit_status
77
+
78
+ # TODO: Push TerminalToolCallContent via session_update for streaming output.
79
+ # Currently Tool.execute only returns ToolResult; streaming will be handled
80
+ # at the session layer in a future phase.
81
+
82
+ if exit_status.signal:
83
+ return ToolResult.error(f"Command terminated by signal: {exit_status.signal}\n{output.output}")
84
+ if exit_status.exit_code not in (None, 0):
85
+ return ToolResult.error(f"Command failed with exit code {exit_status.exit_code}\n{output.output}")
86
+ return ToolResult.success(output.output)
87
+ except asyncio.CancelledError:
88
+ if terminal_id is not None:
89
+ with suppress(Exception):
90
+ await self._conn.kill_terminal(session_id=self._session_id, terminal_id=terminal_id)
91
+ with suppress(Exception):
92
+ await self._conn.release_terminal(session_id=self._session_id, terminal_id=terminal_id)
93
+ raise
94
+ finally:
95
+ if terminal_id is not None:
96
+ with suppress(Exception):
97
+ await self._conn.release_terminal(session_id=self._session_id, terminal_id=terminal_id)
98
+
99
+
100
+ def replace_bash_with_acp_terminal(tool_registry, client_capabilities, conn: acp.Client, session_id: str) -> set[str]:
101
+ """Replace the local bash tool with an ACP terminal-backed tool.
102
+
103
+ Returns the set of tool names that were replaced (whose output is
104
+ streamed via the ACP terminal and should be marked as already displayed).
105
+ """
106
+ if not client_capabilities or not client_capabilities.terminal:
107
+ return set()
108
+ bash = tool_registry.get("bash")
109
+ if bash is None:
110
+ return set()
111
+ tool_registry.register(ACPTerminalBashTool(bash, conn, session_id))
112
+ return {"bash"}
iac_code/acp/types.py ADDED
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ import acp
4
+
5
+ ACPContentBlock = (
6
+ acp.schema.TextContentBlock
7
+ | acp.schema.ImageContentBlock
8
+ | acp.schema.AudioContentBlock
9
+ | acp.schema.ResourceContentBlock
10
+ | acp.schema.EmbeddedResourceContentBlock
11
+ )
12
+
13
+ MCPServer = acp.schema.HttpMcpServer | acp.schema.SseMcpServer | acp.schema.McpServerStdio
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class ACPVersionSpec:
8
+ protocol_version: int
9
+ sdk_version: str
10
+
11
+
12
+ CURRENT_VERSION = ACPVersionSpec(protocol_version=1, sdk_version="0.9.0")
13
+ SUPPORTED_VERSIONS: dict[int, ACPVersionSpec] = {1: CURRENT_VERSION}
14
+ MIN_PROTOCOL_VERSION = 1
15
+
16
+
17
+ def negotiate_version(client_protocol_version: int) -> ACPVersionSpec:
18
+ if client_protocol_version < MIN_PROTOCOL_VERSION:
19
+ return CURRENT_VERSION
20
+
21
+ best: ACPVersionSpec | None = None
22
+ for version, spec in SUPPORTED_VERSIONS.items():
23
+ if version <= client_protocol_version and (best is None or version > best.protocol_version):
24
+ best = spec
25
+
26
+ return best if best is not None else CURRENT_VERSION
@@ -0,0 +1,19 @@
1
+ from iac_code.agent.message import (
2
+ ContentBlock,
3
+ Conversation,
4
+ Message,
5
+ TextBlock,
6
+ ToolResultBlock,
7
+ ToolUseBlock,
8
+ )
9
+ from iac_code.agent.system_prompt import build_system_prompt
10
+
11
+ __all__ = [
12
+ "ContentBlock",
13
+ "Conversation",
14
+ "Message",
15
+ "TextBlock",
16
+ "ToolResultBlock",
17
+ "ToolUseBlock",
18
+ "build_system_prompt",
19
+ ]