adk-code-mode 1.1.0__tar.gz → 1.2.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.
Files changed (76) hide show
  1. adk_code_mode-1.2.0/.release-please-manifest.json +3 -0
  2. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/CHANGELOG.md +7 -0
  3. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/PKG-INFO +1 -1
  4. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/__about__.py +1 -1
  5. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/__about__.py +1 -1
  6. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/_artifact_tools.py +4 -1
  7. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_artifact_tools.py +42 -8
  8. adk_code_mode-1.1.0/.release-please-manifest.json +0 -3
  9. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.githooks/pre-commit +0 -0
  10. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.githooks/pre-push +0 -0
  11. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.github/workflows/ci.yml +0 -0
  12. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.github/workflows/release-please.yml +0 -0
  13. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.gitignore +0 -0
  14. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.prettierrc +0 -0
  15. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.vscode/settings.json +0 -0
  16. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/.zed/settings.json +0 -0
  17. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/AGENTS.md +0 -0
  18. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/CLAUDE.md +0 -0
  19. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/LICENSE +0 -0
  20. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/Makefile +0 -0
  21. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/README.md +0 -0
  22. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/docker/Dockerfile +0 -0
  23. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/pyproject.toml +0 -0
  24. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/release-please-config.json +0 -0
  25. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/README.md +0 -0
  26. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/pyproject.toml +0 -0
  27. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/__init__.py +0 -0
  28. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/__main__.py +0 -0
  29. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/_entry.py +0 -0
  30. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/_http_server.py +0 -0
  31. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/_rpc_client.py +0 -0
  32. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/sandbox-wheel/src/adk_code_mode_sandbox/protocol.py +0 -0
  33. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/scripts/install-git-hooks.sh +0 -0
  34. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/__init__.py +0 -0
  35. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/output.py +0 -0
  36. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/py.typed +0 -0
  37. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/runtime/__init__.py +0 -0
  38. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/runtime/base.py +0 -0
  39. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/runtime/docker.py +0 -0
  40. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/runtime/protocol.py +0 -0
  41. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/runtime/remote.py +0 -0
  42. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tool.py +0 -0
  43. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tool_result_artifacts.py +0 -0
  44. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/__init__.py +0 -0
  45. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/catalog.py +0 -0
  46. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/dispatcher.py +0 -0
  47. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/namespacing.py +0 -0
  48. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/normaliser.py +0 -0
  49. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/tools/stubs.py +0 -0
  50. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/workspace/__init__.py +0 -0
  51. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/src/adk_code_mode/workspace/files.py +0 -0
  52. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/__init__.py +0 -0
  53. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/_docker_helpers.py +0 -0
  54. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/_fake_runtime.py +0 -0
  55. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/conftest.py +0 -0
  56. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_agent_with_fake_llm.py +0 -0
  57. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_catalog.py +0 -0
  58. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_dispatcher.py +0 -0
  59. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_docker_image.py +0 -0
  60. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_docker_integration.py +0 -0
  61. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_host_loop.py +0 -0
  62. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_integration.py +0 -0
  63. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_namespacing.py +0 -0
  64. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_normaliser.py +0 -0
  65. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_output.py +0 -0
  66. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_protocol.py +0 -0
  67. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_remote_backend.py +0 -0
  68. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_remote_integration.py +0 -0
  69. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_runtime_docker.py +0 -0
  70. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_sandbox_rpc_client.py +0 -0
  71. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_stubs.py +0 -0
  72. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_tool.py +0 -0
  73. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_tool_result_artifacts.py +0 -0
  74. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_version.py +0 -0
  75. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/tests/test_workspace_files.py +0 -0
  76. {adk_code_mode-1.1.0 → adk_code_mode-1.2.0}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "1.2.0"
3
+ }
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0](https://github.com/a2anet/adk-code-mode/compare/adk-code-mode-v1.1.0...adk-code-mode-v1.2.0) (2026-07-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * add `custom_metadata` to the `save_artifact` tool ([dfd9a59](https://github.com/a2anet/adk-code-mode/commit/dfd9a59bf1718084a1d5c02cc1ea453269223f16))
9
+
3
10
  ## [1.1.0](https://github.com/a2anet/adk-code-mode/compare/adk-code-mode-v1.0.0...adk-code-mode-v1.1.0) (2026-07-15)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adk-code-mode
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: A "Code Mode" sandboxed code-execution tool for ADK agents to interact with tools, files, and custom packages with Python
5
5
  Project-URL: Documentation, https://github.com/A2ANet/adk-code-mode#readme
6
6
  Project-URL: Issues, https://github.com/A2ANet/adk-code-mode/issues
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present A2A Net <hello@a2anet.com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- __version__ = "1.1.0" # x-release-please-version
4
+ __version__ = "1.2.0" # x-release-please-version
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present A2A Net <hello@a2anet.com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- __version__ = "1.1.0" # x-release-please-version
4
+ __version__ = "1.2.0" # x-release-please-version
@@ -43,6 +43,7 @@ async def save_artifact(
43
43
  filename: str,
44
44
  content: str,
45
45
  mime_type: str | None = None,
46
+ custom_metadata: dict[str, Any] | None = None,
46
47
  tool_context: ToolContext,
47
48
  ) -> int:
48
49
  """Save an artifact to the session. Returns the new version number.
@@ -62,6 +63,8 @@ async def save_artifact(
62
63
  content=base64.b64encode(image_bytes).decode("ascii"),
63
64
  mime_type="image/png",
64
65
  )
66
+
67
+ ``custom_metadata`` is custom metadata to associate with the artifact.
65
68
  """
66
69
  if _is_text_mime(mime_type):
67
70
  part = genai_types.Part(
@@ -77,7 +80,7 @@ async def save_artifact(
77
80
  mime_type=mime_type or "application/octet-stream",
78
81
  )
79
82
  )
80
- return await tool_context.save_artifact(filename, part)
83
+ return await tool_context.save_artifact(filename, part, custom_metadata=custom_metadata)
81
84
 
82
85
 
83
86
  async def load_artifact(
@@ -34,12 +34,17 @@ class _StubToolContext:
34
34
  ) -> None:
35
35
  self._load_result = load_result
36
36
  self._list_result = list_result or []
37
- self.saved: list[tuple[str, genai_types.Part]] = []
37
+ self.saved: list[tuple[str, genai_types.Part, dict[str, Any] | None]] = []
38
38
  self.loaded: list[tuple[str, int | None]] = []
39
39
  self.listed = 0
40
40
 
41
- async def save_artifact(self, filename: str, part: genai_types.Part) -> int:
42
- self.saved.append((filename, part))
41
+ async def save_artifact(
42
+ self,
43
+ filename: str,
44
+ part: genai_types.Part,
45
+ custom_metadata: dict[str, Any] | None = None,
46
+ ) -> int:
47
+ self.saved.append((filename, part, custom_metadata))
43
48
  return len(self.saved)
44
49
 
45
50
  async def load_artifact(
@@ -65,7 +70,7 @@ async def test_save_artifact_encodes_text_mime_as_utf8() -> None:
65
70
 
66
71
  assert version == 1
67
72
  assert len(ctx.saved) == 1
68
- name, part = ctx.saved[0]
73
+ name, part, _ = ctx.saved[0]
69
74
  assert name == "report.json"
70
75
  assert part.inline_data is not None
71
76
  assert part.inline_data.mime_type == "application/json"
@@ -82,7 +87,7 @@ async def test_save_artifact_treats_text_plus_subtype_as_text() -> None:
82
87
  tool_context=ctx, # type: ignore[arg-type]
83
88
  )
84
89
 
85
- _, part = ctx.saved[0]
90
+ _, part, _ = ctx.saved[0]
86
91
  assert part.inline_data is not None
87
92
  assert part.inline_data.data == b"<svg/>"
88
93
 
@@ -98,7 +103,7 @@ async def test_save_artifact_decodes_base64_for_binary_mime() -> None:
98
103
  tool_context=ctx, # type: ignore[arg-type]
99
104
  )
100
105
 
101
- _, part = ctx.saved[0]
106
+ _, part, _ = ctx.saved[0]
102
107
  assert part.inline_data is not None
103
108
  assert part.inline_data.data == raw
104
109
  assert part.inline_data.mime_type == "application/octet-stream"
@@ -114,12 +119,41 @@ async def test_save_artifact_defaults_mime_when_none() -> None:
114
119
  tool_context=ctx, # type: ignore[arg-type]
115
120
  )
116
121
 
117
- _, part = ctx.saved[0]
122
+ _, part, _ = ctx.saved[0]
118
123
  assert part.inline_data is not None
119
124
  assert part.inline_data.mime_type == "application/octet-stream"
120
125
  assert part.inline_data.data == raw
121
126
 
122
127
 
128
+ @pytest.mark.asyncio
129
+ async def test_save_artifact_forwards_custom_metadata() -> None:
130
+ ctx = _StubToolContext()
131
+ await save_artifact(
132
+ filename="report.md",
133
+ content="# Report",
134
+ mime_type="text/markdown",
135
+ custom_metadata={"a2anet_agent_run.send_as_a2a_artifact": "true"},
136
+ tool_context=ctx, # type: ignore[arg-type]
137
+ )
138
+
139
+ _, _, custom_metadata = ctx.saved[0]
140
+ assert custom_metadata == {"a2anet_agent_run.send_as_a2a_artifact": "true"}
141
+
142
+
143
+ @pytest.mark.asyncio
144
+ async def test_save_artifact_defaults_custom_metadata_to_none() -> None:
145
+ ctx = _StubToolContext()
146
+ await save_artifact(
147
+ filename="scratch.txt",
148
+ content="notes",
149
+ mime_type="text/plain",
150
+ tool_context=ctx, # type: ignore[arg-type]
151
+ )
152
+
153
+ _, _, custom_metadata = ctx.saved[0]
154
+ assert custom_metadata is None
155
+
156
+
123
157
  @pytest.mark.asyncio
124
158
  async def test_load_artifact_returns_text_kind_for_text_mime() -> None:
125
159
  part = genai_types.Part(
@@ -196,4 +230,4 @@ def test_artifact_tools_declarations_omit_tool_context_param() -> None:
196
230
  assert save_decl is not None
197
231
  properties: dict[str, Any] = save_decl.parameters.properties or {} # type: ignore[union-attr]
198
232
  assert "tool_context" not in properties
199
- assert {"filename", "content"}.issubset(properties.keys())
233
+ assert {"filename", "content", "custom_metadata"}.issubset(properties.keys())
@@ -1,3 +0,0 @@
1
- {
2
- ".": "1.1.0"
3
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes