Fix MCP tool calls, approval loop, shutdown, and improve web UI

- Fix MCP tool schema deserialization: rename input_schema to match
  protocol's camelCase inputSchema, so models receive actual parameter
  schemas instead of empty defaults
- Fix conversation history: add tool_calls field to ChatMessage and
  include assistant message with tool_calls before tool results, as
  required by OpenAI-compatible APIs
- Fix approval loop: pass resume_after_tool flag to run_agentic_loop
  so the "force tool use" heuristic doesn't re-trigger after approval
- Fix shutdown: add Submission::Quit, Ctrl+C signal handler, and
  graceful shutdown flow
- Fix MCP activate button: auto-attempt auth flow when activation
  fails due to missing authentication
- Add inline approval cards in chat via SSE ApprovalNeeded events
- Add markdown rendering in chat (marked.js) with proper streaming
- Add structured fields to log entries (key=value pairs from tracing)
- Collapse log entries to single line with click-to-expand

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-06 18:04:44 -08:00
co-authored by Claude Opus 4.6
parent 2cdd04a359
commit bf3b8b339f
19 changed files with 958 additions and 148 deletions
+133 -27
View File
@@ -184,7 +184,6 @@ body {
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
white-space: pre-wrap;
}
.message.user {
@@ -192,6 +191,7 @@ body {
background: var(--accent);
color: #fff;
border-bottom-right-radius: 2px;
white-space: pre-wrap;
}
.message.assistant {
@@ -229,6 +229,34 @@ body {
padding: 0;
}
.message p { margin: 0 0 8px 0; }
.message p:last-child { margin-bottom: 0; }
.message ul, .message ol { margin: 4px 0; padding-left: 20px; }
.message li { margin: 2px 0; }
.message blockquote {
margin: 6px 0;
padding: 4px 12px;
border-left: 3px solid var(--border);
color: var(--text-secondary);
}
.message h1, .message h2, .message h3,
.message h4, .message h5, .message h6 {
margin: 8px 0 4px 0;
line-height: 1.3;
}
.message h1 { font-size: 1.3em; }
.message h2 { font-size: 1.2em; }
.message h3 { font-size: 1.1em; }
.message a { color: var(--accent); }
.message hr { border: none; border-top: 1px solid var(--border); margin: 8px 0; }
.message table { border-collapse: collapse; margin: 6px 0; }
.message th, .message td {
border: 1px solid var(--border);
padding: 4px 8px;
font-size: 13px;
}
.message th { background: var(--bg-tertiary); }
/* Status bar */
.chat-status {
padding: 6px 16px;
@@ -255,31 +283,75 @@ body {
to { transform: rotate(360deg); }
}
/* Approval banner */
.approval-banner {
display: none;
padding: 12px 16px;
background: var(--bg-tertiary);
border-top: 1px solid var(--warning);
gap: 8px;
/* Approval card (inline in chat) */
.approval-card {
align-self: flex-start;
max-width: 80%;
background: var(--bg-secondary);
border: 1px solid var(--warning);
border-radius: var(--radius);
padding: 14px;
display: flex;
flex-direction: column;
}
.approval-banner.visible {
display: flex;
}
.approval-banner .approval-info {
font-size: 13px;
color: var(--warning);
}
.approval-banner .approval-actions {
display: flex;
gap: 8px;
}
.approval-banner button {
.approval-header {
font-size: 12px;
font-weight: 600;
color: var(--warning);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.approval-tool-name {
font-size: 14px;
font-weight: 600;
color: var(--text);
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
}
.approval-description {
font-size: 13px;
color: var(--text-secondary);
line-height: 1.4;
}
.approval-params-toggle {
background: none;
border: none;
color: var(--accent);
cursor: pointer;
font-size: 12px;
padding: 0;
text-align: left;
}
.approval-params-toggle:hover {
text-decoration: underline;
}
.approval-params {
background: var(--code-bg);
padding: 8px 12px;
border-radius: var(--radius);
font-size: 12px;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
line-height: 1.4;
overflow-x: auto;
color: var(--text-secondary);
margin: 0;
white-space: pre-wrap;
word-break: break-all;
}
.approval-card .approval-actions {
display: flex;
gap: 8px;
align-items: center;
}
.approval-card .approval-actions button {
padding: 6px 14px;
border: 1px solid var(--border);
border-radius: var(--radius);
@@ -289,24 +361,36 @@ body {
color: var(--text);
}
.approval-banner button.approve {
.approval-card .approval-actions button:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.approval-card .approval-actions button.approve {
background: var(--success);
border-color: var(--success);
color: #fff;
}
.approval-banner button.always {
.approval-card .approval-actions button.always {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.approval-banner button.deny {
.approval-card .approval-actions button.deny {
background: var(--danger);
border-color: var(--danger);
color: #fff;
}
.approval-resolved {
font-size: 12px;
font-weight: 500;
color: var(--text-secondary);
font-style: italic;
}
/* Chat input */
.chat-input {
display: flex;
@@ -736,6 +820,7 @@ body {
gap: 8px;
padding: 1px 12px;
white-space: nowrap;
cursor: pointer;
}
.log-entry:hover {
@@ -764,10 +849,22 @@ body {
.log-msg {
color: var(--text);
white-space: pre-wrap;
word-break: break-all;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.log-entry.expanded {
white-space: normal;
}
.log-entry.expanded .log-msg {
white-space: pre-wrap;
word-break: break-all;
overflow: visible;
text-overflow: unset;
}
/* Log level coloring */
@@ -870,6 +967,15 @@ body {
line-height: 1.4;
}
.ext-url {
font-size: 12px;
color: var(--text-secondary);
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ext-tools {
font-size: 12px;
color: var(--text-secondary);