feat: update version to 0.0.4 and add formatToolLabel utility for tool call label overrides
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@evoscientist/webui",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@evoscientist/webui",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@langchain/core": "1.1.19",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@evoscientist/webui",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"description": "Web UI for EvoScientist — a self-evolving AI scientist built on DeepAgents/LangGraph.",
|
||||
"author": "Xi Zhang <zacharyzhang2022@gmail.com>",
|
||||
"type": "module",
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ToolCall, ActionRequest, ReviewConfig } from "@/app/types/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui";
|
||||
import { ToolApprovalInterrupt } from "@/app/components/ToolApprovalInterrupt";
|
||||
import { formatToolLabel } from "@/lib/toolLabel";
|
||||
|
||||
interface ToolCallBoxProps {
|
||||
toolCall: ToolCall;
|
||||
@@ -70,9 +71,19 @@ export const ToolCallBox = React.memo<ToolCallBoxProps>(
|
||||
}, [actionRequest, autoApprove]);
|
||||
|
||||
const { name, args, result, status } = useMemo(() => {
|
||||
// Streaming can deliver args as a (possibly partial) JSON string, not an
|
||||
// object — treat it as `unknown` and only expose a real object to the
|
||||
// args view, so Object.keys/entries never run on a string.
|
||||
const rawArgs: unknown = toolCall.args;
|
||||
return {
|
||||
name: toolCall.name || "Unknown Tool",
|
||||
args: toolCall.args || {},
|
||||
// Targeted label overrides only (read_file/write_file/edit_file on
|
||||
// /memories → "Reading memory"/"Updating memory", think_tool →
|
||||
// "Reflection"); every other tool keeps its raw name.
|
||||
name: formatToolLabel(toolCall.name, rawArgs),
|
||||
args:
|
||||
rawArgs && typeof rawArgs === "object"
|
||||
? (rawArgs as Record<string, unknown>)
|
||||
: {},
|
||||
result: toolCall.result,
|
||||
status: toolCall.status || "completed",
|
||||
};
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Targeted tool-call label overrides.
|
||||
*
|
||||
* We deliberately do NOT reformat tool calls in general (no `ls(path)` /
|
||||
* `execute(cmd)` argument summaries). Only a few specific names are remapped;
|
||||
* every other tool keeps its raw name.
|
||||
*
|
||||
* Overrides:
|
||||
* - read_file / write_file / edit_file on a `/memories/...` path →
|
||||
* "Reading memory" / "Updating memory".
|
||||
* - read_file on a `/skills/<name>/...` path → "Skill: <name>".
|
||||
* - think_tool → "Reflection".
|
||||
* - the tool-selector's internal ToolSelectionResponse → "Adaptive tool
|
||||
* selection".
|
||||
*/
|
||||
|
||||
/** True when a virtual path targets the global memories directory. */
|
||||
function isMemoryPath(path: string): boolean {
|
||||
const p = (path || "").trim();
|
||||
return p === "/memories" || p.startsWith("/memories/");
|
||||
}
|
||||
|
||||
/** If a virtual path targets a skill (`/skills/<name>/...`), return `<name>`.
|
||||
* An empty first segment (e.g. `/skills//x`) is treated as no match. */
|
||||
function skillNameFromPath(path: string): string {
|
||||
const p = (path || "").trim();
|
||||
if (!p.startsWith("/skills/")) return "";
|
||||
const [skill] = p.slice("/skills/".length).split("/");
|
||||
return skill || "";
|
||||
}
|
||||
|
||||
/** Coerce tool args to an object — they may stream in as a JSON string. */
|
||||
function asArgsObject(args: unknown): Record<string, unknown> {
|
||||
if (args && typeof args === "object") return args as Record<string, unknown>;
|
||||
if (typeof args === "string") {
|
||||
try {
|
||||
const parsed = JSON.parse(args);
|
||||
if (parsed && typeof parsed === "object") {
|
||||
return parsed as Record<string, unknown>;
|
||||
}
|
||||
} catch {
|
||||
// Partial / non-JSON args while still streaming — treat as empty.
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export function formatToolLabel(name: string, args?: unknown): string {
|
||||
if (!name) return "Unknown Tool";
|
||||
|
||||
// The tool-selector middleware's internal structured-output call.
|
||||
if (name === "ToolSelectionResponse") return "Adaptive tool selection";
|
||||
|
||||
const nameLower = name.toLowerCase();
|
||||
|
||||
if (nameLower === "think_tool") return "Reflection";
|
||||
|
||||
if (
|
||||
nameLower === "read_file" ||
|
||||
nameLower === "write_file" ||
|
||||
nameLower === "edit_file"
|
||||
) {
|
||||
const a = asArgsObject(args);
|
||||
const path = String(a.path ?? a.file_path ?? "");
|
||||
if (isMemoryPath(path)) {
|
||||
return nameLower === "read_file" ? "Reading memory" : "Updating memory";
|
||||
}
|
||||
if (nameLower === "read_file") {
|
||||
const skill = skillNameFromPath(path);
|
||||
if (skill) return `Skill: ${skill}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else keeps its raw tool name.
|
||||
return name;
|
||||
}
|
||||
Reference in New Issue
Block a user