symphony-code 0.0.1__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 (169) hide show
  1. coding_agent/__init__.py +20 -0
  2. coding_agent/_lazy.py +17 -0
  3. coding_agent/addons/__init__.py +35 -0
  4. coding_agent/addons/approvals.py +224 -0
  5. coding_agent/addons/compaction/__init__.py +36 -0
  6. coding_agent/addons/compaction/addon.py +88 -0
  7. coding_agent/addons/compaction/compactor.py +138 -0
  8. coding_agent/addons/compaction/prompts.py +20 -0
  9. coding_agent/addons/compaction/transcript.py +118 -0
  10. coding_agent/addons/evaluation/__init__.py +68 -0
  11. coding_agent/addons/evaluation/addon.py +199 -0
  12. coding_agent/addons/evaluation/evaluators.py +245 -0
  13. coding_agent/addons/evaluation/handlers.py +66 -0
  14. coding_agent/addons/evaluation/policy.py +277 -0
  15. coding_agent/addons/evaluation/protocol.py +192 -0
  16. coding_agent/addons/evaluation/state.py +284 -0
  17. coding_agent/addons/langfuse/__init__.py +24 -0
  18. coding_agent/addons/langfuse/addon.py +465 -0
  19. coding_agent/addons/langfuse/install.py +79 -0
  20. coding_agent/addons/langfuse/serialize.py +158 -0
  21. coding_agent/addons/learning/__init__.py +33 -0
  22. coding_agent/addons/learning/addon.py +181 -0
  23. coding_agent/addons/learning/loop.py +247 -0
  24. coding_agent/addons/learning/prompts.py +26 -0
  25. coding_agent/addons/learning/sanitize.py +64 -0
  26. coding_agent/addons/learning/store.py +522 -0
  27. coding_agent/addons/manager/__init__.py +18 -0
  28. coding_agent/addons/manager/bridge.py +74 -0
  29. coding_agent/addons/manager/discovery.py +34 -0
  30. coding_agent/addons/manager/report.py +33 -0
  31. coding_agent/addons/manager/runtime.py +76 -0
  32. coding_agent/addons/manager/tool_changes.py +16 -0
  33. coding_agent/addons/persistence/__init__.py +41 -0
  34. coding_agent/addons/persistence/active.py +132 -0
  35. coding_agent/addons/persistence/artifacts.py +110 -0
  36. coding_agent/addons/persistence/collection.py +166 -0
  37. coding_agent/addons/persistence/compatibility.py +30 -0
  38. coding_agent/addons/persistence/images.py +133 -0
  39. coding_agent/addons/persistence/jsonl.py +1195 -0
  40. coding_agent/addons/persistence/presentation.py +104 -0
  41. coding_agent/addons/plugins/__init__.py +19 -0
  42. coding_agent/addons/plugins/install.py +37 -0
  43. coding_agent/addons/plugins/manager.py +140 -0
  44. coding_agent/addons/plugins/models.py +50 -0
  45. coding_agent/addons/skills/__init__.py +28 -0
  46. coding_agent/addons/skills/addon.py +26 -0
  47. coding_agent/addons/skills/args.py +78 -0
  48. coding_agent/addons/skills/bundled_skills/addon-authoring/SKILL.md +77 -0
  49. coding_agent/addons/skills/bundled_skills/context-budget/SKILL.md +12 -0
  50. coding_agent/addons/skills/bundled_skills/orient-first/SKILL.md +16 -0
  51. coding_agent/addons/skills/bundled_skills/security-boundary/SKILL.md +16 -0
  52. coding_agent/addons/skills/bundled_skills/skill-discipline/SKILL.md +13 -0
  53. coding_agent/addons/skills/bundled_skills/surgical-edit/SKILL.md +11 -0
  54. coding_agent/addons/skills/bundled_skills/systematic-debug/SKILL.md +18 -0
  55. coding_agent/addons/skills/bundled_skills/verify-before-done/SKILL.md +11 -0
  56. coding_agent/addons/skills/frontmatter.py +57 -0
  57. coding_agent/addons/skills/models.py +57 -0
  58. coding_agent/addons/skills/registry.py +109 -0
  59. coding_agent/addons/skills/tool.py +54 -0
  60. coding_agent/addons/voice/__init__.py +5 -0
  61. coding_agent/addons/voice/addon.py +106 -0
  62. coding_agent/addons/voice/credentials.py +42 -0
  63. coding_agent/addons/voice/playback.py +42 -0
  64. coding_agent/addons/voice/speak.py +287 -0
  65. coding_agent/addons/voice/stream.py +651 -0
  66. coding_agent/addons/voice/summary.py +126 -0
  67. coding_agent/agent.py +523 -0
  68. coding_agent/bench/__init__.py +1 -0
  69. coding_agent/bench/cli.py +200 -0
  70. coding_agent/bench/patch.py +78 -0
  71. coding_agent/commands/__init__.py +5 -0
  72. coding_agent/commands/catalog.py +179 -0
  73. coding_agent/commands/jev_argument.py +40 -0
  74. coding_agent/config/__init__.py +51 -0
  75. coding_agent/config/config.py +376 -0
  76. coding_agent/config/credentials.py +153 -0
  77. coding_agent/config/personalities.json +34 -0
  78. coding_agent/config/personalities.py +170 -0
  79. coding_agent/config/prompts.py +67 -0
  80. coding_agent/protocols/__init__.py +5 -0
  81. coding_agent/protocols/acp/README.md +36 -0
  82. coding_agent/protocols/acp/__init__.py +27 -0
  83. coding_agent/protocols/acp/mapping.py +164 -0
  84. coding_agent/protocols/acp/server.py +261 -0
  85. coding_agent/protocols/acp/transport.py +72 -0
  86. coding_agent/protocols/stdio/README.md +36 -0
  87. coding_agent/protocols/stdio/__init__.py +37 -0
  88. coding_agent/protocols/stdio/catalog.py +49 -0
  89. coding_agent/protocols/stdio/commands.py +218 -0
  90. coding_agent/protocols/stdio/server.py +181 -0
  91. coding_agent/protocols/stdio/transport.py +71 -0
  92. coding_agent/py.typed +0 -0
  93. coding_agent/resources/__init__.py +5 -0
  94. coding_agent/resources/usage.py +264 -0
  95. coding_agent/run/__init__.py +1 -0
  96. coding_agent/run/cli.py +99 -0
  97. coding_agent/run/detach.py +37 -0
  98. coding_agent/run/interrupted.py +67 -0
  99. coding_agent/run/log_sink.py +46 -0
  100. coding_agent/tools/__init__.py +73 -0
  101. coding_agent/tools/ask_user.py +61 -0
  102. coding_agent/tools/base.py +136 -0
  103. coding_agent/tools/bash.py +288 -0
  104. coding_agent/tools/bash_jobs.py +116 -0
  105. coding_agent/tools/generate_image.py +123 -0
  106. coding_agent/tools/memory.py +100 -0
  107. coding_agent/tools/patch.py +218 -0
  108. coding_agent/tools/read_file.py +167 -0
  109. coding_agent/tools/search.py +433 -0
  110. coding_agent/tools/web_search.py +151 -0
  111. coding_agent/tools/write_file.py +40 -0
  112. coding_agent/tui/EFFICIENCY_PLAN.md +25 -0
  113. coding_agent/tui/__init__.py +22 -0
  114. coding_agent/tui/__main__.py +122 -0
  115. coding_agent/tui/app.py +456 -0
  116. coding_agent/tui/chrome/__init__.py +33 -0
  117. coding_agent/tui/chrome/footer.py +274 -0
  118. coding_agent/tui/chrome/topbar.py +259 -0
  119. coding_agent/tui/commands/__init__.py +45 -0
  120. coding_agent/tui/commands/catalog.py +35 -0
  121. coding_agent/tui/commands/manager.py +557 -0
  122. coding_agent/tui/composer/__init__.py +18 -0
  123. coding_agent/tui/composer/input.py +219 -0
  124. coding_agent/tui/composer/slash_menu.py +341 -0
  125. coding_agent/tui/composer/surface.py +330 -0
  126. coding_agent/tui/composer/voice.py +267 -0
  127. coding_agent/tui/composer/voice_mode.py +491 -0
  128. coding_agent/tui/runtime/__init__.py +23 -0
  129. coding_agent/tui/runtime/events.py +728 -0
  130. coding_agent/tui/runtime/sink.py +115 -0
  131. coding_agent/tui/runtime/state.py +145 -0
  132. coding_agent/tui/runtime/subagent.py +531 -0
  133. coding_agent/tui/runtime/turn.py +206 -0
  134. coding_agent/tui/screens/__init__.py +54 -0
  135. coding_agent/tui/screens/ask.py +69 -0
  136. coding_agent/tui/screens/context.py +195 -0
  137. coding_agent/tui/screens/dashboard.py +91 -0
  138. coding_agent/tui/screens/diff.py +302 -0
  139. coding_agent/tui/screens/extensions.py +68 -0
  140. coding_agent/tui/screens/file_selector.py +167 -0
  141. coding_agent/tui/screens/history.py +458 -0
  142. coding_agent/tui/screens/langfuse.py +142 -0
  143. coding_agent/tui/screens/learning.py +113 -0
  144. coding_agent/tui/screens/modal.py +131 -0
  145. coding_agent/tui/screens/onboard.py +455 -0
  146. coding_agent/tui/screens/resume.py +163 -0
  147. coding_agent/tui/theme/__init__.py +49 -0
  148. coding_agent/tui/theme/load.py +325 -0
  149. coding_agent/tui/theme/style.py +95 -0
  150. coding_agent/tui/theme/theme.toml +1687 -0
  151. coding_agent/tui/tools/__init__.py +53 -0
  152. coding_agent/tui/tools/activity.py +184 -0
  153. coding_agent/tui/tools/calls.py +560 -0
  154. coding_agent/tui/tools/code_view.py +52 -0
  155. coding_agent/tui/tools/images.py +250 -0
  156. coding_agent/tui/tools/labels.py +135 -0
  157. coding_agent/tui/tools/modal.py +137 -0
  158. coding_agent/tui/tools/partial_args.py +19 -0
  159. coding_agent/tui/tools/snapshots.py +382 -0
  160. coding_agent/tui/transcript/__init__.py +36 -0
  161. coding_agent/tui/transcript/messages.py +408 -0
  162. coding_agent/tui/transcript/process.py +504 -0
  163. coding_agent/tui/transcript/surface.py +345 -0
  164. coding_agent/tui/transcript/thinking_markdown.py +314 -0
  165. symphony_code-0.0.1.dist-info/METADATA +66 -0
  166. symphony_code-0.0.1.dist-info/RECORD +169 -0
  167. symphony_code-0.0.1.dist-info/WHEEL +4 -0
  168. symphony_code-0.0.1.dist-info/entry_points.txt +5 -0
  169. symphony_code-0.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,133 @@
1
+ """Session-local content-addressed images; remote URLs are never fetched."""
2
+ from __future__ import annotations
3
+
4
+ import base64
5
+ import binascii
6
+ import hashlib
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from core_ai.content import IMAGE_MIME_BY_SUFFIX, normalize_content
11
+ from coding_agent.addons.persistence.artifacts import publish, safe_path
12
+
13
+
14
+ _IMAGE_TYPES = {"image", "image_url", "input_image"}
15
+ # Inline image parts only. A local path is read when the user attached it.
16
+ MAX_IMAGE_BYTES = 8 * 1024 * 1024
17
+
18
+
19
+ def archive(value: Any, directory: Path) -> Any:
20
+ """Copy embedded image parts to disk without mutating caller data."""
21
+ if isinstance(value, list):
22
+ return [archive(item, directory) for item in value]
23
+ if not isinstance(value, dict):
24
+ return value
25
+ if value.get("type") in _IMAGE_TYPES or any(
26
+ key in value for key in ("inlineData", "inline_data", "fileData", "file_data")
27
+ ):
28
+ if value.get("archive_path"):
29
+ try:
30
+ _image_path(value["archive_path"], directory)
31
+ except ValueError:
32
+ return _unavailable(value, "invalid")
33
+ return dict(value)
34
+ parts = normalize_content([value])
35
+ if parts and parts[0].get("type") == "image":
36
+ part = parts[0]
37
+ payload = _payload(value, part)
38
+ if payload is not None:
39
+ digest = hashlib.sha256(payload).hexdigest()
40
+ relative = f"images/{digest}"
41
+ path = _image_path(relative, directory)
42
+ if not path.exists():
43
+ publish(path, payload)
44
+ return {
45
+ "type": "image",
46
+ "media_type": part.get("media_type", "image/png"),
47
+ **({"filename": part["filename"]} if part.get("filename") else {}),
48
+ "archive_path": relative,
49
+ }
50
+ return {key: archive(item, directory) for key, item in value.items()}
51
+
52
+
53
+ def hydrate(value: Any, directory: Path) -> Any:
54
+ """Restore image bytes. A bad or missing blob does not fail the caller."""
55
+ if isinstance(value, list):
56
+ return [hydrate(item, directory) for item in value]
57
+ if not isinstance(value, dict):
58
+ return value
59
+ reference = value.get("archive_path")
60
+ if reference is not None:
61
+ try:
62
+ path = _image_path(reference, directory)
63
+ size = path.stat().st_size
64
+ if size > MAX_IMAGE_BYTES:
65
+ return _unavailable(value, "too_large")
66
+ payload = path.read_bytes()
67
+ except (OSError, ValueError):
68
+ return _unavailable(value, "missing")
69
+ digest = hashlib.sha256(payload).hexdigest()
70
+ if f"images/{digest}" != str(reference):
71
+ return _unavailable(value, "mismatch")
72
+ return {
73
+ "type": "image",
74
+ "media_type": value.get("media_type", "image/png"),
75
+ **({"filename": value["filename"]} if value.get("filename") else {}),
76
+ "data": base64.b64encode(payload).decode("ascii"),
77
+ "url": path.as_uri(),
78
+ }
79
+ return {key: hydrate(item, directory) for key, item in value.items()}
80
+
81
+
82
+ def _payload(value: dict[str, Any], part: dict[str, Any]) -> bytes | None:
83
+ data = part.get("data")
84
+ if data:
85
+ try:
86
+ payload = base64.b64decode("".join(str(data).split()), validate=True)
87
+ except (ValueError, binascii.Error):
88
+ return None
89
+ if len(payload) > MAX_IMAGE_BYTES:
90
+ return None
91
+ return payload
92
+ return _attached_file(value)
93
+
94
+
95
+ def _attached_file(value: dict[str, Any]) -> bytes | None:
96
+ """Read only a path the user attached. Arbitrary file URLs stay untouched."""
97
+ if value.get("user_attached") is not True:
98
+ return None
99
+ raw = value.get("attached_path")
100
+ if not isinstance(raw, str) or not raw:
101
+ return None
102
+ path = Path(raw).expanduser()
103
+ try:
104
+ if not path.is_absolute() or path.is_symlink() or not path.is_file():
105
+ return None
106
+ if path.suffix.lower() not in IMAGE_MIME_BY_SUFFIX:
107
+ return None
108
+ if path.stat().st_size > MAX_IMAGE_BYTES:
109
+ return None
110
+ return path.read_bytes()
111
+ except OSError:
112
+ return None
113
+
114
+
115
+ def _unavailable(value: dict[str, Any], reason: str) -> dict[str, Any]:
116
+ kept = {
117
+ key: value[key]
118
+ for key in ("type", "media_type", "filename", "archive_path")
119
+ if key in value
120
+ }
121
+ kept.setdefault("type", "image")
122
+ kept["unavailable"] = reason
123
+ return kept
124
+
125
+
126
+ def _image_path(reference: Any, directory: Path) -> Path:
127
+ reference = str(reference)
128
+ digest = reference.removeprefix("images/")
129
+ if reference != f"images/{digest}" or len(digest) != 64 or any(
130
+ char not in "0123456789abcdef" for char in digest
131
+ ):
132
+ raise ValueError(f"invalid image archive reference: {reference!r}")
133
+ return safe_path(directory, reference)