agentstack-cli 0.4.0__tar.gz → 0.4.1__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.
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/PKG-INFO +1 -1
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/pyproject.toml +1 -1
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/auth_manager.py +14 -3
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/agent.py +1 -67
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/server.py +45 -5
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/configuration.py +4 -2
- agentstack_cli-0.4.1/src/agentstack_cli/data/helm-chart.tgz +0 -0
- agentstack_cli-0.4.0/src/agentstack_cli/data/helm-chart.tgz +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/README.md +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/__init__.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/api.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/async_typer.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/__init__.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/build.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/mcp.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/model.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/__init__.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/base_driver.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/istio.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/lima_driver.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/wsl_driver.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/self.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/console.py +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/data/.gitignore +0 -0
- {agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/utils.py +0 -0
|
@@ -18,6 +18,8 @@ class AuthToken(BaseModel):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class AuthServer(BaseModel):
|
|
21
|
+
client_id: str = "df82a687-d647-4247-838b-7080d7d83f6c" # Backwards compatibility default
|
|
22
|
+
client_secret: str | None = None
|
|
21
23
|
token: AuthToken | None = None
|
|
22
24
|
|
|
23
25
|
|
|
@@ -48,9 +50,18 @@ class AuthManager:
|
|
|
48
50
|
def _save(self) -> None:
|
|
49
51
|
self._auth_path.write_text(self._auth.model_dump_json(indent=2))
|
|
50
52
|
|
|
51
|
-
def save_auth_token(
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
def save_auth_token(
|
|
54
|
+
self,
|
|
55
|
+
server: str,
|
|
56
|
+
auth_server: str | None = None,
|
|
57
|
+
client_id: str | None = None,
|
|
58
|
+
client_secret: str | None = None,
|
|
59
|
+
token: dict[str, Any] | None = None,
|
|
60
|
+
) -> None:
|
|
61
|
+
if auth_server is not None and client_id is not None and token is not None:
|
|
62
|
+
self._auth.servers[server].authorization_servers[auth_server] = AuthServer(
|
|
63
|
+
client_id=client_id, client_secret=client_secret, token=AuthToken(**token)
|
|
64
|
+
)
|
|
54
65
|
else:
|
|
55
66
|
self._auth.servers[server] # touch
|
|
56
67
|
self._save()
|
|
@@ -68,7 +68,6 @@ from pydantic import BaseModel
|
|
|
68
68
|
from rich.box import HORIZONTALS
|
|
69
69
|
from rich.console import ConsoleRenderable, Group, NewLine
|
|
70
70
|
from rich.panel import Panel
|
|
71
|
-
from rich.rule import Rule
|
|
72
71
|
from rich.text import Text
|
|
73
72
|
|
|
74
73
|
from agentstack_cli.commands.build import build
|
|
@@ -721,54 +720,6 @@ def _create_input_handler(
|
|
|
721
720
|
return handler
|
|
722
721
|
|
|
723
722
|
|
|
724
|
-
def _setup_sequential_workflow(providers: list[Provider], splash_screen: ConsoleRenderable | None = None):
|
|
725
|
-
prompt_agents = {
|
|
726
|
-
provider.agent_card.name: provider
|
|
727
|
-
for provider in providers
|
|
728
|
-
if (ProviderUtils.detail(provider) or {}).get("interaction_mode") == InteractionMode.SINGLE_TURN
|
|
729
|
-
}
|
|
730
|
-
steps = []
|
|
731
|
-
|
|
732
|
-
console.print(Rule(title="Configure Workflow", style="white"))
|
|
733
|
-
|
|
734
|
-
handle_input = _create_input_handler(
|
|
735
|
-
[], prompt="Agent: ", choice=list(prompt_agents), placeholder="Select agent", splash_screen=splash_screen
|
|
736
|
-
)
|
|
737
|
-
handle_instruction_input = _create_input_handler(
|
|
738
|
-
[], prompt="Instruction: ", placeholder="Enter agent instruction", splash_screen=splash_screen
|
|
739
|
-
)
|
|
740
|
-
i = 0
|
|
741
|
-
|
|
742
|
-
while True:
|
|
743
|
-
if not (agent := handle_input()):
|
|
744
|
-
console.print(Rule(style="white"))
|
|
745
|
-
break
|
|
746
|
-
instruction = handle_instruction_input()
|
|
747
|
-
|
|
748
|
-
if not steps:
|
|
749
|
-
# change prompt for other passes
|
|
750
|
-
handle_input = _create_input_handler(
|
|
751
|
-
[],
|
|
752
|
-
prompt="Agent: ",
|
|
753
|
-
placeholder="Select agent (Leave empty to execute)",
|
|
754
|
-
choice=list(prompt_agents),
|
|
755
|
-
optional=True,
|
|
756
|
-
splash_screen=splash_screen,
|
|
757
|
-
)
|
|
758
|
-
handle_instruction_input = _create_input_handler(
|
|
759
|
-
[],
|
|
760
|
-
prompt="Instruction: ",
|
|
761
|
-
placeholder="Enter agent instruction (leave empty to pass raw output from previous agent)",
|
|
762
|
-
optional=True,
|
|
763
|
-
splash_screen=splash_screen,
|
|
764
|
-
)
|
|
765
|
-
console.print(Rule(style="dim", characters="·"))
|
|
766
|
-
i += 1
|
|
767
|
-
steps.append({"provider_id": prompt_agents[agent].id, "instruction": instruction})
|
|
768
|
-
|
|
769
|
-
return steps
|
|
770
|
-
|
|
771
|
-
|
|
772
723
|
@app.command("run")
|
|
773
724
|
async def run_agent(
|
|
774
725
|
search_path: typing.Annotated[
|
|
@@ -810,7 +761,6 @@ async def run_agent(
|
|
|
810
761
|
|
|
811
762
|
ui_annotations = ProviderUtils.detail(provider) or {}
|
|
812
763
|
interaction_mode = ui_annotations.get("interaction_mode")
|
|
813
|
-
is_sequential_workflow = agent.name in {"sequential_workflow"}
|
|
814
764
|
|
|
815
765
|
user_greeting = ui_annotations.get("user_greeting", None) or "How can I help you?"
|
|
816
766
|
|
|
@@ -818,10 +768,7 @@ async def run_agent(
|
|
|
818
768
|
handle_input = _create_input_handler([], splash_screen=splash_screen)
|
|
819
769
|
|
|
820
770
|
if not input:
|
|
821
|
-
if
|
|
822
|
-
interaction_mode not in {InteractionMode.MULTI_TURN, InteractionMode.SINGLE_TURN}
|
|
823
|
-
and not is_sequential_workflow
|
|
824
|
-
):
|
|
771
|
+
if interaction_mode not in {InteractionMode.MULTI_TURN, InteractionMode.SINGLE_TURN}:
|
|
825
772
|
err_console.error(
|
|
826
773
|
f"Agent {agent.name} does not use any supported UIs.\n"
|
|
827
774
|
+ "Please use the agent according to the following examples and schema:"
|
|
@@ -867,19 +814,6 @@ async def run_agent(
|
|
|
867
814
|
dump_files_path=dump_files,
|
|
868
815
|
handle_input=handle_input,
|
|
869
816
|
)
|
|
870
|
-
elif is_sequential_workflow:
|
|
871
|
-
workflow_steps = _setup_sequential_workflow(providers, splash_screen=splash_screen)
|
|
872
|
-
console.print()
|
|
873
|
-
message_part = DataPart(data={"steps": workflow_steps}, metadata={"kind": "configuration"})
|
|
874
|
-
async with a2a_client(provider.agent_card) as client:
|
|
875
|
-
await _run_agent(
|
|
876
|
-
client,
|
|
877
|
-
message_part,
|
|
878
|
-
agent_card=agent,
|
|
879
|
-
context_token=context_token,
|
|
880
|
-
dump_files_path=dump_files,
|
|
881
|
-
handle_input=handle_input,
|
|
882
|
-
)
|
|
883
817
|
|
|
884
818
|
else:
|
|
885
819
|
async with a2a_client(provider.agent_card) as client:
|
|
@@ -91,7 +91,7 @@ async def server_login(server: typing.Annotated[str | None, typer.Argument()] =
|
|
|
91
91
|
)
|
|
92
92
|
server = server or await inquirer.text(message="Enter server URL:").execute_async() # type: ignore
|
|
93
93
|
|
|
94
|
-
if server
|
|
94
|
+
if not server:
|
|
95
95
|
raise RuntimeError("No server selected. Action cancelled.")
|
|
96
96
|
|
|
97
97
|
if "://" not in server:
|
|
@@ -134,6 +134,10 @@ async def server_login(server: typing.Annotated[str | None, typer.Argument()] =
|
|
|
134
134
|
auth_servers = metadata.get("authorization_servers", [])
|
|
135
135
|
auth_server = None
|
|
136
136
|
token = None
|
|
137
|
+
|
|
138
|
+
client_id = config.client_id
|
|
139
|
+
client_secret = config.client_secret
|
|
140
|
+
|
|
137
141
|
if auth_servers:
|
|
138
142
|
if len(auth_servers) == 1:
|
|
139
143
|
auth_server = auth_servers[0]
|
|
@@ -154,15 +158,44 @@ async def server_login(server: typing.Annotated[str | None, typer.Argument()] =
|
|
|
154
158
|
except Exception as e:
|
|
155
159
|
raise RuntimeError(f"OIDC discovery failed: {e}") from e
|
|
156
160
|
|
|
161
|
+
registration_endpoint = oidc["registration_endpoint"]
|
|
162
|
+
if not client_id and registration_endpoint:
|
|
163
|
+
async with httpx.AsyncClient() as client:
|
|
164
|
+
try:
|
|
165
|
+
resp = await client.post(
|
|
166
|
+
registration_endpoint,
|
|
167
|
+
json={"client_name": "Agent Stack CLI", "redirect_uris": [REDIRECT_URI]},
|
|
168
|
+
)
|
|
169
|
+
resp.raise_for_status()
|
|
170
|
+
data = resp.json()
|
|
171
|
+
client_id = data["client_id"]
|
|
172
|
+
client_secret = data["client_secret"]
|
|
173
|
+
except Exception:
|
|
174
|
+
console.warning("Dynamic client registration failed. Proceed with manual input.")
|
|
175
|
+
|
|
176
|
+
if not client_id:
|
|
177
|
+
client_id = await inquirer.text( # type: ignore
|
|
178
|
+
message="Enter Client ID:",
|
|
179
|
+
instruction=f"(Redirect URI: {REDIRECT_URI})",
|
|
180
|
+
).execute_async()
|
|
181
|
+
if not client_id:
|
|
182
|
+
raise RuntimeError("Client ID is mandatory. Action cancelled.")
|
|
183
|
+
client_secret = (
|
|
184
|
+
await inquirer.text( # type: ignore
|
|
185
|
+
message="Enter Client Secret (optional):"
|
|
186
|
+
).execute_async()
|
|
187
|
+
or None
|
|
188
|
+
)
|
|
189
|
+
|
|
157
190
|
code_verifier = generate_token(64)
|
|
158
191
|
|
|
159
192
|
auth_url = f"{oidc['authorization_endpoint']}?{
|
|
160
193
|
urlencode(
|
|
161
194
|
{
|
|
162
|
-
'client_id':
|
|
195
|
+
'client_id': client_id,
|
|
163
196
|
'response_type': 'code',
|
|
164
197
|
'redirect_uri': REDIRECT_URI,
|
|
165
|
-
'scope': ' '.join(metadata.get('scopes_supported', ['openid'])),
|
|
198
|
+
'scope': ' '.join(metadata.get('scopes_supported', ['openid', 'email', 'profile'])),
|
|
166
199
|
'code_challenge': typing.cast(str, create_s256_code_challenge(code_verifier)),
|
|
167
200
|
'code_challenge_method': 'S256',
|
|
168
201
|
}
|
|
@@ -182,7 +215,8 @@ async def server_login(server: typing.Annotated[str | None, typer.Argument()] =
|
|
|
182
215
|
"grant_type": "authorization_code",
|
|
183
216
|
"code": code,
|
|
184
217
|
"redirect_uri": REDIRECT_URI,
|
|
185
|
-
"client_id":
|
|
218
|
+
"client_id": client_id,
|
|
219
|
+
"client_secret": client_secret,
|
|
186
220
|
"code_verifier": code_verifier,
|
|
187
221
|
},
|
|
188
222
|
)
|
|
@@ -194,7 +228,13 @@ async def server_login(server: typing.Annotated[str | None, typer.Argument()] =
|
|
|
194
228
|
if not token:
|
|
195
229
|
raise RuntimeError("Login timed out or not successful.")
|
|
196
230
|
|
|
197
|
-
config.auth_manager.save_auth_token(
|
|
231
|
+
config.auth_manager.save_auth_token(
|
|
232
|
+
server=server,
|
|
233
|
+
auth_server=auth_server,
|
|
234
|
+
client_id=client_id,
|
|
235
|
+
client_secret=client_secret,
|
|
236
|
+
token=token,
|
|
237
|
+
)
|
|
198
238
|
|
|
199
239
|
config.auth_manager.active_server = server
|
|
200
240
|
config.auth_manager.active_auth_server = auth_server
|
|
@@ -36,9 +36,11 @@ class Configuration(pydantic_settings.BaseSettings):
|
|
|
36
36
|
f"https://github.com/i-am-bee/agentstack@v{version()}#path=agent-registry.yaml"
|
|
37
37
|
)
|
|
38
38
|
admin_password: SecretStr | None = None
|
|
39
|
-
oidc_enabled: bool = False
|
|
40
39
|
server_metadata_ttl: int = 86400
|
|
41
|
-
|
|
40
|
+
|
|
41
|
+
oidc_enabled: bool = False
|
|
42
|
+
client_id: str | None = None
|
|
43
|
+
client_secret: str | None = None
|
|
42
44
|
|
|
43
45
|
@property
|
|
44
46
|
def lima_home(self) -> pathlib.Path:
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/__init__.py
RENAMED
|
File without changes
|
{agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/base_driver.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/lima_driver.py
RENAMED
|
File without changes
|
{agentstack_cli-0.4.0 → agentstack_cli-0.4.1}/src/agentstack_cli/commands/platform/wsl_driver.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|