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.
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/PKG-INFO +1 -1
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/chat.py +35 -14
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/widgets.py +9 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/pyproject.toml +1 -1
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/README.md +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/__init__.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/__main__.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/batch/__init__.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/batch/format.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/batch/run.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/batch/utils.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/run.py +0 -0
- {padwan_cli-0.3.0 → padwan_cli-0.4.0}/padwan_cli/utils.py +0 -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
|
|
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=
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
widget
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
212
|
-
|
|
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
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|