Skip to content

Commit 961ea0d

Browse files
authored
fix: resolve issue for hidden config cloud_provider in agentkit.yaml (#61)
2 parents 761e491 + 9f64211 commit 961ea0d

6 files changed

Lines changed: 251 additions & 8 deletions

File tree

agentkit/toolkit/cli/cli_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ def _interactive_config(config_file: Optional[str] = None):
372372
)
373373

374374
common_config = create_common_config_interactively(
375-
config.get_common_config().to_dict()
375+
(config.get_raw_data() or {}).get("common", {})
376376
)
377377
config.update_common_config(common_config)
378378

agentkit/toolkit/cli/interactive_config.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,20 @@ def generate_config(
178178
dataclass_type: type,
179179
existing_config: Optional[Dict[str, Any]] = None,
180180
context: Optional[Dict[str, Any]] = None,
181+
carry_over_config: Optional[Dict[str, Any]] = None,
181182
) -> Dict[str, Any]:
182183
self.current_dataclass_type = dataclass_type
183184
if not is_dataclass(dataclass_type):
184185
raise ValueError(f"{dataclass_type} must be a dataclass")
185186

186187
config = {}
187188
existing_config = existing_config or {}
189+
if carry_over_config is not None and not isinstance(carry_over_config, dict):
190+
raise TypeError(
191+
"carry_over_config must be a dict when provided; "
192+
f"got {type(carry_over_config).__name__}"
193+
)
194+
carry_over = existing_config if carry_over_config is None else carry_over_config
188195

189196
# Get dataclass metadata
190197
# Try to get from class attributes; if not found, create instance to get field values
@@ -267,8 +274,8 @@ def generate_config(
267274
if field.metadata.get("hidden", False) or field.metadata.get(
268275
"system", False
269276
):
270-
if field_name in existing_config:
271-
config[field_name] = existing_config[field_name]
277+
if isinstance(carry_over, dict) and field_name in carry_over:
278+
config[field_name] = carry_over[field_name]
272279

273280
# Filter out MISSING values
274281
filtered_config = {}
@@ -1222,8 +1229,14 @@ def generate_config_from_dataclass(
12221229
dataclass_type: type,
12231230
existing_config: Optional[Dict[str, Any]] = None,
12241231
context: Optional[Dict[str, Any]] = None,
1232+
carry_over_config: Optional[Dict[str, Any]] = None,
12251233
) -> Dict[str, Any]:
1226-
return auto_prompt.generate_config(dataclass_type, existing_config, context=context)
1234+
return auto_prompt.generate_config(
1235+
dataclass_type,
1236+
existing_config,
1237+
context=context,
1238+
carry_over_config=carry_over_config,
1239+
)
12271240

12281241

12291242
def create_common_config_interactively(
@@ -1245,6 +1258,11 @@ def create_common_config_interactively(
12451258
"""
12461259
from agentkit.toolkit.config import CommonConfig
12471260

1248-
existing = CommonConfig.from_dict(existing_config or {})
1249-
config_dict = auto_prompt.generate_config(CommonConfig, existing.to_dict())
1261+
raw_existing_config = existing_config or {}
1262+
existing = CommonConfig.from_dict(raw_existing_config)
1263+
config_dict = auto_prompt.generate_config(
1264+
CommonConfig,
1265+
existing.to_dict(),
1266+
carry_over_config=raw_existing_config,
1267+
)
12501268
return CommonConfig.from_dict(config_dict)

agentkit/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
VERSION = "0.5.4"
15+
VERSION = "0.5.5"

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "agentkit-sdk-python"
3-
version = "0.5.4"
3+
version = "0.5.5"
44
description = "Python SDK for transforming any AI agent into a production-ready application. Framework-agnostic primitives for runtime, memory, authentication, and tools with volcengine-managed infrastructure."
55
readme = "README.md"
66
requires-python = ">=3.10"

tests/toolkit/cli/test_cli_config_interactive_provider_resolution.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,64 @@ def fake_generate_config_from_dataclass(
7373

7474
clear_config_cache()
7575
cli_config._interactive_config(config_file=str(config_path))
76+
77+
78+
def test_interactive_config_common_input_uses_raw_yaml_common(
79+
tmp_path: Path, monkeypatch
80+
) -> None:
81+
from agentkit.toolkit.cli import cli_config
82+
from agentkit.toolkit.config import CommonConfig
83+
from agentkit.toolkit.config.config import clear_config_cache
84+
import agentkit.toolkit.config.global_config as global_cfg_mod
85+
from agentkit.toolkit.config.global_config import GlobalConfig
86+
import agentkit.toolkit.cli.interactive_config as interactive_config
87+
88+
config_path = tmp_path / "agentkit.yaml"
89+
raw_common = {
90+
"agent_name": "demo",
91+
"entry_point": "agent.py",
92+
"launch_type": "cloud",
93+
}
94+
config_path.write_text(
95+
yaml.safe_dump(
96+
{
97+
"common": raw_common,
98+
"launch_types": {"cloud": {}},
99+
"docker_build": {},
100+
},
101+
sort_keys=False,
102+
allow_unicode=True,
103+
),
104+
encoding="utf-8",
105+
)
106+
107+
global_cfg = GlobalConfig()
108+
global_cfg.defaults.cloud_provider = "byteplus"
109+
monkeypatch.setattr(global_cfg_mod, "get_global_config", lambda: global_cfg)
110+
111+
def fake_create_common_config_interactively(existing_config):
112+
assert isinstance(existing_config, dict)
113+
assert "cloud_provider" not in existing_config
114+
for k, v in raw_common.items():
115+
assert existing_config.get(k) == v
116+
return CommonConfig.from_dict(existing_config or {})
117+
118+
def fake_generate_config_from_dataclass(
119+
_dataclass_type, existing_config=None, context=None
120+
):
121+
assert context == {"cloud_provider": "byteplus"}
122+
return {"region": "ap-southeast-1"}
123+
124+
monkeypatch.setattr(
125+
interactive_config,
126+
"create_common_config_interactively",
127+
fake_create_common_config_interactively,
128+
)
129+
monkeypatch.setattr(
130+
interactive_config,
131+
"generate_config_from_dataclass",
132+
fake_generate_config_from_dataclass,
133+
)
134+
135+
clear_config_cache()
136+
cli_config._interactive_config(config_file=str(config_path))
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
6+
def test_generate_config_rejects_non_dict_carry_over_config(monkeypatch) -> None:
7+
from agentkit.toolkit.cli.interactive_config import AutoPromptGenerator
8+
from agentkit.toolkit.config import CommonConfig
9+
10+
monkeypatch.setattr(
11+
AutoPromptGenerator, "_show_welcome_panel", lambda *a, **k: None
12+
)
13+
monkeypatch.setattr(
14+
AutoPromptGenerator, "_show_completion_panel", lambda *a, **k: None
15+
)
16+
monkeypatch.setattr(
17+
AutoPromptGenerator,
18+
"_prompt_for_field",
19+
lambda self,
20+
name,
21+
field_type,
22+
description,
23+
default,
24+
metadata=None,
25+
current=1,
26+
total=1,
27+
current_config=None,
28+
resolver_context=None: default,
29+
)
30+
31+
generator = AutoPromptGenerator()
32+
33+
with pytest.raises(TypeError, match=r"carry_over_config must be a dict"):
34+
generator.generate_config(CommonConfig, {}, carry_over_config=[]) # type: ignore[arg-type]
35+
36+
37+
def test_generate_config_does_not_carry_hidden_fields_from_prefill_when_carry_over_missing(
38+
monkeypatch,
39+
) -> None:
40+
from agentkit.toolkit.cli.interactive_config import AutoPromptGenerator
41+
from agentkit.toolkit.config import CommonConfig
42+
43+
monkeypatch.setattr(
44+
AutoPromptGenerator, "_show_welcome_panel", lambda *a, **k: None
45+
)
46+
monkeypatch.setattr(
47+
AutoPromptGenerator, "_show_completion_panel", lambda *a, **k: None
48+
)
49+
monkeypatch.setattr(
50+
AutoPromptGenerator,
51+
"_prompt_for_field",
52+
lambda self,
53+
name,
54+
field_type,
55+
description,
56+
default,
57+
metadata=None,
58+
current=1,
59+
total=1,
60+
current_config=None,
61+
resolver_context=None: default,
62+
)
63+
64+
generator = AutoPromptGenerator()
65+
66+
prefill = CommonConfig.from_dict({}).to_dict()
67+
carry_over = {
68+
"agent_name": "demo",
69+
"entry_point": "agent.py",
70+
"launch_type": "cloud",
71+
}
72+
73+
result = generator.generate_config(
74+
CommonConfig,
75+
prefill,
76+
carry_over_config=carry_over,
77+
)
78+
79+
assert "cloud_provider" not in result
80+
81+
82+
def test_generate_config_carries_hidden_fields_from_carry_over(monkeypatch) -> None:
83+
from agentkit.toolkit.cli.interactive_config import AutoPromptGenerator
84+
from agentkit.toolkit.config import CommonConfig
85+
86+
monkeypatch.setattr(
87+
AutoPromptGenerator, "_show_welcome_panel", lambda *a, **k: None
88+
)
89+
monkeypatch.setattr(
90+
AutoPromptGenerator, "_show_completion_panel", lambda *a, **k: None
91+
)
92+
monkeypatch.setattr(
93+
AutoPromptGenerator,
94+
"_prompt_for_field",
95+
lambda self,
96+
name,
97+
field_type,
98+
description,
99+
default,
100+
metadata=None,
101+
current=1,
102+
total=1,
103+
current_config=None,
104+
resolver_context=None: default,
105+
)
106+
107+
generator = AutoPromptGenerator()
108+
109+
prefill = CommonConfig.from_dict({}).to_dict()
110+
carry_over = {
111+
"agent_name": "demo",
112+
"entry_point": "agent.py",
113+
"launch_type": "cloud",
114+
"cloud_provider": "byteplus",
115+
}
116+
117+
result = generator.generate_config(
118+
CommonConfig,
119+
prefill,
120+
carry_over_config=carry_over,
121+
)
122+
123+
assert result["cloud_provider"] == "byteplus"
124+
125+
126+
def test_generate_config_default_behavior_carries_hidden_fields_from_existing_config(
127+
monkeypatch,
128+
) -> None:
129+
from agentkit.toolkit.cli.interactive_config import AutoPromptGenerator
130+
from agentkit.toolkit.config import CommonConfig
131+
132+
monkeypatch.setattr(
133+
AutoPromptGenerator, "_show_welcome_panel", lambda *a, **k: None
134+
)
135+
monkeypatch.setattr(
136+
AutoPromptGenerator, "_show_completion_panel", lambda *a, **k: None
137+
)
138+
monkeypatch.setattr(
139+
AutoPromptGenerator,
140+
"_prompt_for_field",
141+
lambda self,
142+
name,
143+
field_type,
144+
description,
145+
default,
146+
metadata=None,
147+
current=1,
148+
total=1,
149+
current_config=None,
150+
resolver_context=None: default,
151+
)
152+
153+
generator = AutoPromptGenerator()
154+
155+
existing_config = {
156+
"agent_name": "demo",
157+
"entry_point": "agent.py",
158+
"launch_type": "cloud",
159+
"cloud_provider": "byteplus",
160+
}
161+
162+
result = generator.generate_config(CommonConfig, existing_config)
163+
164+
assert result["cloud_provider"] == "byteplus"

0 commit comments

Comments
 (0)