Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/src/components/chat/chat-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
result={part.output}
className="my-2"
state={part.state}
input={part.input}
/>
);
}
Expand Down Expand Up @@ -269,6 +270,7 @@ const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
toolName={part.type}
result={part.output}
state={part.state}
input={part.input}
className="my-2"
/>
);
Expand Down
72 changes: 52 additions & 20 deletions frontend/src/components/chat/tool-call-accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ const PrettySuccessResult: React.FC<{ data: SuccessResult }> = ({ data }) => {
} = data;

return (
<div className="py-1 flex flex-col gap-1">
{/* Status */}
<div className="flex items-center gap-2">
<span className="text-xs font-medium text-[var(--grass-11)] capitalize">
{status}
</span>
{auth_required && (
<span className="text-xs px-2 py-0.5 bg-[var(--amber-2)] text-[var(--amber-11)] rounded-full">
Auth Required
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between">
<h3 className="text-xs font-semibold text-muted-foreground">
Tool Result
</h3>
<div className="flex items-center gap-2">
<span className="text-xs px-2 py-0.5 bg-[var(--grass-2)] text-[var(--grass-11)] rounded-full font-medium capitalize">
{status}
</span>
)}
{auth_required && (
<span className="text-xs px-2 py-0.5 bg-[var(--amber-2)] text-[var(--amber-11)] rounded-full">
Auth Required
</span>
)}
</div>
</div>

{/* Message */}
Expand All @@ -68,17 +72,18 @@ const PrettySuccessResult: React.FC<{ data: SuccessResult }> = ({ data }) => {

{/* Data */}
{rest && (
<div className="flex flex-col gap-1">
<div className="space-y-3">
{Object.entries(rest).map(([key, value]) => {
if (isEmpty(value)) {
return null;
}
return (
<div key={key}>
<div className="text-xs font-medium text-muted-foreground mb-1 capitalize">
{key}:
<div key={key} className="space-y-1.5">
<div className="text-xs font-medium text-muted-foreground capitalize flex items-center gap-2">
<div className="w-1.5 h-1.5 bg-[var(--blue-9)] rounded-full" />
{key}
</div>
<pre className="bg-[var(--slate-2)] p-1 text-muted-foreground border border-[var(--slate-4)] rounded text-xs overflow-auto scrollbar-thin max-h-64">
<pre className="bg-[var(--slate-2)] p-2 text-muted-foreground border border-[var(--slate-4)] rounded text-xs overflow-auto scrollbar-thin max-h-64">
{JSON.stringify(value, null, 2)}
</pre>
</div>
Expand Down Expand Up @@ -107,13 +112,37 @@ const ResultRenderer: React.FC<{ result: unknown }> = ({ result }) => {
);
};

const ToolArgsRenderer: React.FC<{ input: unknown }> = ({ input }) => {
const hasinput = input && input !== null;

if (!hasinput) {
return null;
}

const isObject =
typeof input === "object" &&
Object.keys(input as Record<string, unknown>).length > 0;

return (
<div className="space-y-2">
<h3 className="text-xs font-semibold text-muted-foreground">
Tool Request
</h3>
<pre className="bg-[var(--slate-2)] p-2 text-muted-foreground border border-[var(--slate-4)] rounded text-xs overflow-auto scrollbar-thin max-h-64">
{isObject ? JSON.stringify(input, null, 2) : String(input)}
</pre>
</div>
);
};

interface ToolCallAccordionProps {
toolName: string;
result: unknown;
error?: string;
index?: number;
state?: ToolUIPart["state"];
className?: string;
input?: unknown;
}

export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
Expand All @@ -123,6 +152,7 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
index = 0,
state,
className,
input,
}) => {
const hasResult = state === "output-available" && (result || error);
const status = error ? "error" : hasResult ? "success" : "loading";
Expand Down Expand Up @@ -176,21 +206,23 @@ export const ToolCallAccordion: React.FC<ToolCallAccordionProps> = ({
</code>
</span>
</AccordionTrigger>
<AccordionContent className="pb-2 px-2">
<AccordionContent className="py-2 px-2">
{/* Only show content when tool is complete */}
{hasResult && (
<div className="space-y-3">
<ToolArgsRenderer input={input} />
{result !== undefined && result !== null && (
<ResultRenderer result={result} />
)}

{/* Error */}
{error && (
<div>
<div className="text-xs font-medium text-[var(--red-11)] mb-1">
Error:
<div className="bg-[var(--red-2)] border border-[var(--red-6)] rounded-lg p-3">
<div className="text-xs font-semibold text-[var(--red-11)] mb-2 flex items-center gap-2">
<div className="w-1.5 h-1.5 bg-[var(--red-9)] rounded-full" />
Error
</div>
<div className="bg-[var(--red-2)] border border-[var(--red-6)] rounded-md p-3 text-sm text-[var(--red-11)]">
<div className="text-sm text-[var(--red-11)] leading-relaxed">
{error}
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions marimo/_ai/_tools/tools/datasource.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ class GetDatabaseTables(
ToolBase[GetDatabaseTablesArgs, GetDatabaseTablesOutput]
):
"""
Get information about tables in a database.
Get information about tables in a database. Use the query parameter to search by name. Use regex for complex searches.

Args:
session_id: The session id.
query (optional): The query to match the database, schemas, and tables. Regex is supported.
query (optional): The query to match the database, schemas, and tables.

If a query is provided, it will fuzzy match the query to the database, schemas, and tables available. If no query is provided, all tables are returned. Don't provide a query if you need to see the entire schema view.

Expand Down
1 change: 1 addition & 0 deletions marimo/_ai/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def __post_init__(self) -> None:
self.parts = parts

def _convert_part(self, part: Any) -> Optional[ChatPart]:
PartType = None
for PartType in PART_TYPES:
try:
if dataclasses.is_dataclass(part):
Expand Down
Loading