virtuai-cli 0.2.2__tar.gz → 0.3.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 (21) hide show
  1. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/PKG-INFO +1 -1
  2. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/pyproject.toml +1 -1
  3. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/__init__.py +1 -1
  4. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/chat/command.py +2 -1
  5. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/chat/tui.py +64 -8
  6. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/PKG-INFO +1 -1
  7. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/README.md +0 -0
  8. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/setup.cfg +0 -0
  9. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/chat/__init__.py +0 -0
  10. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/chat/sse.py +0 -0
  11. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/chat/widgets.py +0 -0
  12. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/config.py +0 -0
  13. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/executor.py +0 -0
  14. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/main.py +0 -0
  15. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/runner.py +0 -0
  16. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli/security.py +0 -0
  17. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/SOURCES.txt +0 -0
  18. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/dependency_links.txt +0 -0
  19. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/entry_points.txt +0 -0
  20. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/requires.txt +0 -0
  21. {virtuai_cli-0.2.2 → virtuai_cli-0.3.0}/src/virtuai_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: virtuai-cli
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Run VirtuAI deep agents on your local machine
5
5
  Author-email: uCloudStore <lmoreno@ucloudstore.com>
6
6
  License: Proprietary
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "virtuai-cli"
7
- version = "0.2.2"
7
+ version = "0.3.0"
8
8
  description = "Run VirtuAI deep agents on your local machine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,2 +1,2 @@
1
1
  """VirtuAI local CLI."""
2
- __version__ = "0.2.2"
2
+ __version__ = "0.3.0"
@@ -92,6 +92,7 @@ def run_chat(
92
92
  agent_id=picked["agent_id"],
93
93
  agent_name=picked["name"],
94
94
  workspace_name=info["workspace_name"],
95
- default_model_id=picked.get("default_model_id"),
95
+ default_model_id=picked.get("default_model_id") or None,
96
+ allowed_models=picked.get("allowed_models") or [],
96
97
  )
97
98
  app.run()
@@ -64,6 +64,7 @@ class ChatApp(App):
64
64
  agent_name: str,
65
65
  workspace_name: str,
66
66
  default_model_id: Optional[str] = None,
67
+ allowed_models: Optional[list[dict]] = None,
67
68
  ) -> None:
68
69
  super().__init__()
69
70
  self.server_url = server_url
@@ -73,6 +74,8 @@ class ChatApp(App):
73
74
  self.agent_name = agent_name
74
75
  self.workspace_name = workspace_name
75
76
  self.default_model_id = default_model_id
77
+ self.current_model_id = default_model_id
78
+ self.allowed_models = list(allowed_models or [])
76
79
 
77
80
  self.session_id: Optional[str] = None
78
81
  self._stream_task: Optional[asyncio.Task] = None
@@ -94,7 +97,7 @@ class ChatApp(App):
94
97
  yield Footer()
95
98
 
96
99
  def _initial_status(self) -> str:
97
- model = f" · {self.default_model_id}" if self.default_model_id else ""
100
+ model = f" · {self.current_model_id}" if self.current_model_id else ""
98
101
  return f"{self.workspace_name} · {self.agent_name}{model} · connecting…"
99
102
 
100
103
  # ── Mount: start the WS runner in the background ──────────────────────
@@ -119,9 +122,10 @@ class ChatApp(App):
119
122
  def _set_status(self, text: str) -> None:
120
123
  # The status widget may have been torn down during app shutdown —
121
124
  # swallow the lookup error so we don't surface a NoMatches on exit.
125
+ model = f" · {self.current_model_id}" if self.current_model_id else ""
122
126
  try:
123
127
  self.query_one("#status", Static).update(
124
- f"{self.workspace_name} · {self.agent_name} · {text}"
128
+ f"{self.workspace_name} · {self.agent_name}{model} · {text}"
125
129
  )
126
130
  except Exception:
127
131
  pass
@@ -160,20 +164,72 @@ class ChatApp(App):
160
164
  async def _handle_slash(self, cmd: str) -> None:
161
165
  parts = cmd.split(None, 1)
162
166
  head = parts[0].lower()
167
+ arg = parts[1].strip() if len(parts) > 1 else ""
163
168
  if head in ("/exit", "/quit"):
164
169
  self.exit()
165
170
  elif head in ("/clear", "/new"):
166
171
  await self.action_clear_conversation()
172
+ elif head == "/models":
173
+ await self._show_models()
174
+ elif head == "/model":
175
+ await self._set_model(arg)
167
176
  elif head == "/help":
168
177
  await self._append(Static(
169
178
  "[b]Commands[/b]\n"
170
- " /help this list\n"
171
- " /clear, /new start a fresh conversation\n"
172
- " /exit, /quit close the TUI\n"
173
- " Esc cancel current response\n"
179
+ " /help this list\n"
180
+ " /clear, /new start a fresh conversation\n"
181
+ " /models list models available for this agent\n"
182
+ " /model <id> switch the model for the next message\n"
183
+ " /exit, /quit close the TUI\n"
184
+ " Esc cancel current response\n"
174
185
  ))
175
186
  else:
176
- await self._append(Static(f"[red]Unknown command: {head}[/red]"))
187
+ await self._append(Static(f"[red]Unknown command: {head}[/red] (try /help)"))
188
+
189
+ async def _show_models(self) -> None:
190
+ if not self.allowed_models:
191
+ await self._append(Static(
192
+ "[yellow]No model catalog available for this agent.[/yellow]"
193
+ ))
194
+ return
195
+ lines = ["[b]Available models[/b]"]
196
+ for m in self.allowed_models:
197
+ marker = "•" if m["id"] != self.current_model_id else "[green]✓[/green]"
198
+ label = m.get("label") or m["id"]
199
+ provider = f" [dim]({m['provider']})[/dim]" if m.get("provider") else ""
200
+ lines.append(f" {marker} [bold]{m['id']}[/bold] — {label}{provider}")
201
+ lines.append("\n[dim]Use [/dim][b]/model <id>[/b][dim] to switch.[/dim]")
202
+ await self._append(Static("\n".join(lines)))
203
+
204
+ async def _set_model(self, requested: str) -> None:
205
+ if not requested:
206
+ current = self.current_model_id or "(none)"
207
+ await self._append(Static(
208
+ f"Current model: [b]{current}[/b]\n"
209
+ f"Usage: [b]/model <id>[/b] (see [b]/models[/b] for the list)"
210
+ ))
211
+ return
212
+ if self._stream_task and not self._stream_task.done():
213
+ await self._append(Static(
214
+ "[yellow]Cancel the in-flight response (Esc) before switching models.[/yellow]"
215
+ ))
216
+ return
217
+ if self.allowed_models:
218
+ valid_ids = {m["id"] for m in self.allowed_models}
219
+ if requested not in valid_ids:
220
+ # Loose match by label too
221
+ by_label = {m.get("label", ""): m["id"] for m in self.allowed_models}
222
+ if requested in by_label:
223
+ requested = by_label[requested]
224
+ else:
225
+ await self._append(Static(
226
+ f"[red]'{requested}' is not in this agent's catalog.[/red] "
227
+ f"Run [b]/models[/b] to see valid IDs."
228
+ ))
229
+ return
230
+ self.current_model_id = requested
231
+ self._set_status(f"model set to {requested}")
232
+ await self._append(Static(f"[green]✓[/green] Model switched to [b]{requested}[/b]."))
177
233
 
178
234
  async def action_clear_conversation(self) -> None:
179
235
  self.session_id = None
@@ -200,7 +256,7 @@ class ChatApp(App):
200
256
  self.agent_id,
201
257
  message,
202
258
  session_id=self.session_id,
203
- model_id=self.default_model_id,
259
+ model_id=self.current_model_id,
204
260
  ):
205
261
  await self._handle_event(event, turn)
206
262
  except asyncio.CancelledError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: virtuai-cli
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Run VirtuAI deep agents on your local machine
5
5
  Author-email: uCloudStore <lmoreno@ucloudstore.com>
6
6
  License: Proprietary
File without changes
File without changes