padwan-cli 0.3.0__tar.gz → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: padwan-cli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: CLI and TUI for padwan-llm
5
5
  Author-email: julien.brayere@polarsen.com
6
6
  Requires-Dist: padwan-llm>=0.6.0
@@ -20,7 +20,13 @@ from padwan_llm import (
20
20
  from padwan_llm.gemini import GeminiClient
21
21
  from padwan_llm.gemini.models import ThinkingConfig
22
22
  from .utils import ALL_MODELS, console
23
- from .widgets import StreamingMessage, ThoughtMessage, ToolCallMessage, UserMessage
23
+ from .widgets import (
24
+ ErrorMessage,
25
+ StreamingMessage,
26
+ ThoughtMessage,
27
+ ToolCallMessage,
28
+ UserMessage,
29
+ )
24
30
 
25
31
  chat_group = CommandGroup(name="chat", help="Chat with an LLM")
26
32
 
@@ -95,6 +101,11 @@ async def chat_send_fn(
95
101
  "--extra-params",
96
102
  help="Extra JSON object merged into every request body (e.g. '{\"temperature\": 0}')",
97
103
  ),
104
+ mcp_urls: list[str] | None = Option(
105
+ None,
106
+ "--mcp",
107
+ help=f"Streamable-HTTP MCP server URL(s) to expose as tools (e.g. {DATAGOUV_MCP_URL})",
108
+ ),
98
109
  ctx: TuiContext = TuiOption(),
99
110
  ) -> None:
100
111
  """Start a conversation. Use Ctrl+C to exit."""
@@ -170,7 +181,7 @@ async def chat_send_fn(
170
181
  # the first turn under a new id lands in the store via `session.save()`.
171
182
  session = AgentSession.load(
172
183
  client=client,
173
- mcp_tools=[McpStreamable(url=DATAGOUV_MCP_URL)],
184
+ mcp_tools=[McpStreamable(url=url) for url in mcp_urls or ()],
174
185
  on_tool=_on_tool,
175
186
  on_mcp_connect=_on_mcp_connect,
176
187
  store=_store,
@@ -193,23 +204,33 @@ async def chat_send_fn(
193
204
  ctx.set_silent_queue(True)
194
205
  needs_new_text_widget = True
195
206
  widget: StreamingMessage | None = None
196
- async for chunk in session.stream(user_input):
197
- if needs_new_text_widget:
198
- widget = StreamingMessage()
199
- ctx.mount_widget(widget)
200
- needs_new_text_widget = False
201
- current_thought = None
202
- assert widget is not None
203
- widget.append(chunk)
204
- if (n := ctx.pending_count) > 0:
205
- ctx.set_hint(f"Responding... ({n} queued)")
207
+ try:
208
+ async for chunk in session.stream(user_input):
209
+ if needs_new_text_widget or widget is None:
210
+ widget = StreamingMessage()
211
+ ctx.mount_widget(widget)
212
+ needs_new_text_widget = False
213
+ current_thought = None
214
+ widget.append(chunk)
215
+ if (n := ctx.pending_count) > 0:
216
+ ctx.set_hint(f"Responding... ({n} queued)")
217
+ except Exception as e:
218
+ # Surface the error inline: the outer handler is
219
+ # only reached after session teardown, which can
220
+ # hang on the MCP listener (see padwan-llm mcp.py).
221
+ ctx.mount_widget(ErrorMessage(str(e)))
222
+ needs_new_text_widget = True
206
223
  ctx.set_silent_queue(False)
207
224
  ctx.set_hint("Chat mode - press Ctrl+C to exit")
208
225
  ctx.set_status_above(_format_tokens(session, ctx) or None)
209
226
  user_input = await ctx.prompt()
210
227
  else:
211
- async for chunk in session.stream(user_input):
212
- console.print(chunk, end="")
228
+ try:
229
+ async for chunk in session.stream(user_input):
230
+ console.print(chunk, end="")
231
+ except Exception as e:
232
+ console.print(f"\n[red]✖ {e}[/red]")
233
+ break
213
234
  console.print()
214
235
  if tokens := _format_tokens(session):
215
236
  console.print(f"[dim]{tokens}[/dim]")
@@ -16,6 +16,7 @@ USER_COLOR = "#87ceeb"
16
16
  ASSISTANT_COLOR = "#98fb98"
17
17
  TOOL_CALL_COLOR = "#ffa500"
18
18
  THOUGHT_COLOR = "#9370db"
19
+ ERROR_COLOR = "#ff6b6b"
19
20
 
20
21
  # Colors for batch job states
21
22
  STATE_COLORS = {
@@ -66,6 +67,14 @@ class ToolCallMessage(Static):
66
67
  self.update(text)
67
68
 
68
69
 
70
+ class ErrorMessage(Static):
71
+ """A styled widget for displaying an error inline in the chat."""
72
+
73
+ def __init__(self, content: str, **kwargs) -> None:
74
+ text = Text(f"✖ {content}", style=ERROR_COLOR)
75
+ super().__init__(text, **kwargs)
76
+
77
+
69
78
  class ThoughtMessage(Static):
70
79
  """A styled widget for displaying a model reasoning/thought block.
71
80
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "padwan-cli"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  description = "CLI and TUI for padwan-llm"
5
5
  readme = "README.md"
6
6
  authors = [
File without changes
File without changes