@townco/ui 0.1.67 → 0.1.69
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.
- package/dist/core/hooks/use-chat-messages.d.ts +5 -0
- package/dist/core/hooks/use-tool-calls.d.ts +5 -0
- package/dist/core/hooks/use-tool-calls.js +2 -1
- package/dist/core/schemas/chat.d.ts +10 -0
- package/dist/core/schemas/tool-call.d.ts +96 -0
- package/dist/core/schemas/tool-call.js +12 -0
- package/dist/core/utils/tool-call-state.d.ts +30 -0
- package/dist/core/utils/tool-call-state.js +73 -0
- package/dist/core/utils/tool-summary.d.ts +13 -0
- package/dist/core/utils/tool-summary.js +172 -0
- package/dist/core/utils/tool-verbiage.d.ts +28 -0
- package/dist/core/utils/tool-verbiage.js +185 -0
- package/dist/gui/components/AppSidebar.d.ts +22 -0
- package/dist/gui/components/AppSidebar.js +22 -0
- package/dist/gui/components/ChatLayout.d.ts +5 -0
- package/dist/gui/components/ChatLayout.js +239 -132
- package/dist/gui/components/ChatView.js +42 -118
- package/dist/gui/components/MessageContent.js +199 -49
- package/dist/gui/components/SessionHistory.d.ts +10 -0
- package/dist/gui/components/SessionHistory.js +101 -0
- package/dist/gui/components/SessionHistoryItem.d.ts +11 -0
- package/dist/gui/components/SessionHistoryItem.js +24 -0
- package/dist/gui/components/Sheet.d.ts +25 -0
- package/dist/gui/components/Sheet.js +36 -0
- package/dist/gui/components/Sidebar.d.ts +65 -0
- package/dist/gui/components/Sidebar.js +231 -0
- package/dist/gui/components/SidebarToggle.d.ts +3 -0
- package/dist/gui/components/SidebarToggle.js +9 -0
- package/dist/gui/components/SubAgentDetails.d.ts +13 -6
- package/dist/gui/components/SubAgentDetails.js +29 -14
- package/dist/gui/components/ToolCallList.js +3 -3
- package/dist/gui/components/ToolOperation.d.ts +11 -0
- package/dist/gui/components/ToolOperation.js +289 -0
- package/dist/gui/components/WorkProgress.d.ts +20 -0
- package/dist/gui/components/WorkProgress.js +79 -0
- package/dist/gui/components/index.d.ts +8 -1
- package/dist/gui/components/index.js +9 -1
- package/dist/gui/hooks/index.d.ts +1 -0
- package/dist/gui/hooks/index.js +1 -0
- package/dist/gui/hooks/use-mobile.d.ts +1 -0
- package/dist/gui/hooks/use-mobile.js +15 -0
- package/dist/gui/index.d.ts +1 -0
- package/dist/gui/index.js +2 -0
- package/dist/gui/lib/motion.d.ts +55 -0
- package/dist/gui/lib/motion.js +217 -0
- package/dist/sdk/schemas/session.d.ts +102 -6
- package/dist/sdk/transports/http.js +105 -37
- package/dist/sdk/transports/types.d.ts +5 -0
- package/package.json +8 -7
- package/src/styles/global.css +128 -1
- package/dist/gui/components/InvokingGroup.d.ts +0 -9
- package/dist/gui/components/InvokingGroup.js +0 -16
- package/dist/gui/components/ToolCall.d.ts +0 -8
- package/dist/gui/components/ToolCall.js +0 -226
- package/dist/gui/components/ToolCallGroup.d.ts +0 -8
- package/dist/gui/components/ToolCallGroup.js +0 -29
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapping of tool names to their verbiage templates
|
|
3
|
+
*
|
|
4
|
+
* NOTE: Built-in Town SDK tools now include verbiage metadata in their definitions.
|
|
5
|
+
* This map is kept as a fallback for:
|
|
6
|
+
* - Legacy/external tools (e.g., Cursor IDE tools)
|
|
7
|
+
* - Custom tools without verbiage metadata
|
|
8
|
+
* - Backward compatibility
|
|
9
|
+
*/
|
|
10
|
+
export const TOOL_VERBIAGE_MAP = {
|
|
11
|
+
// Town SDK filesystem tools (actual names: "Grep", "Read", "Write")
|
|
12
|
+
Read: {
|
|
13
|
+
active: "Reading {file}",
|
|
14
|
+
past: "Read {file}",
|
|
15
|
+
paramKey: "file_path",
|
|
16
|
+
},
|
|
17
|
+
Write: {
|
|
18
|
+
active: "Writing {file}",
|
|
19
|
+
past: "Wrote {file}",
|
|
20
|
+
paramKey: "file_path",
|
|
21
|
+
},
|
|
22
|
+
Grep: {
|
|
23
|
+
active: "Searching for {query}",
|
|
24
|
+
past: "Searched for {query}",
|
|
25
|
+
paramKey: "pattern",
|
|
26
|
+
},
|
|
27
|
+
// Town SDK web tools (actual names: "WebSearch", "WebFetch")
|
|
28
|
+
WebSearch: {
|
|
29
|
+
active: "Searching the web for {query}",
|
|
30
|
+
past: "Searched the web for {query}",
|
|
31
|
+
paramKey: "query",
|
|
32
|
+
},
|
|
33
|
+
WebFetch: {
|
|
34
|
+
active: "Fetching {url}",
|
|
35
|
+
past: "Fetched {url}",
|
|
36
|
+
paramKey: "url",
|
|
37
|
+
},
|
|
38
|
+
// Legacy/external tool names (for backward compatibility)
|
|
39
|
+
read_file: {
|
|
40
|
+
active: "Reading {file}",
|
|
41
|
+
past: "Read {file}",
|
|
42
|
+
paramKey: "target_file",
|
|
43
|
+
},
|
|
44
|
+
write: {
|
|
45
|
+
active: "Writing {file}",
|
|
46
|
+
past: "Wrote {file}",
|
|
47
|
+
paramKey: "file_path",
|
|
48
|
+
},
|
|
49
|
+
grep: {
|
|
50
|
+
active: "Searching for {query}",
|
|
51
|
+
past: "Searched for {query}",
|
|
52
|
+
paramKey: "pattern",
|
|
53
|
+
},
|
|
54
|
+
web_search: {
|
|
55
|
+
active: "Searching the web for {query}",
|
|
56
|
+
past: "Searched the web for {query}",
|
|
57
|
+
paramKey: "search_term",
|
|
58
|
+
},
|
|
59
|
+
search_replace: {
|
|
60
|
+
active: "Editing {file}",
|
|
61
|
+
past: "Edited {file}",
|
|
62
|
+
paramKey: "file_path",
|
|
63
|
+
},
|
|
64
|
+
delete_file: {
|
|
65
|
+
active: "Deleting {file}",
|
|
66
|
+
past: "Deleted {file}",
|
|
67
|
+
paramKey: "target_file",
|
|
68
|
+
},
|
|
69
|
+
codebase_search: {
|
|
70
|
+
active: "Searching codebase for {query}",
|
|
71
|
+
past: "Searched codebase for {query}",
|
|
72
|
+
paramKey: "query",
|
|
73
|
+
},
|
|
74
|
+
glob_file_search: {
|
|
75
|
+
active: "Finding files matching {pattern}",
|
|
76
|
+
past: "Found files matching {pattern}",
|
|
77
|
+
paramKey: "glob_pattern",
|
|
78
|
+
},
|
|
79
|
+
run_terminal_cmd: {
|
|
80
|
+
active: "Running {command}",
|
|
81
|
+
past: "Ran {command}",
|
|
82
|
+
paramKey: "command",
|
|
83
|
+
},
|
|
84
|
+
list_dir: {
|
|
85
|
+
active: "Listing {directory}",
|
|
86
|
+
past: "Listed {directory}",
|
|
87
|
+
paramKey: "target_directory",
|
|
88
|
+
},
|
|
89
|
+
edit_notebook: {
|
|
90
|
+
active: "Editing notebook",
|
|
91
|
+
past: "Edited notebook",
|
|
92
|
+
},
|
|
93
|
+
read_lints: {
|
|
94
|
+
active: "Reading linter errors",
|
|
95
|
+
past: "Read linter errors",
|
|
96
|
+
},
|
|
97
|
+
// Town SDK todo tool
|
|
98
|
+
todo_write: {
|
|
99
|
+
active: "Updating to-do's",
|
|
100
|
+
past: "Updated to-do's",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Extract parameter value from tool call
|
|
105
|
+
*/
|
|
106
|
+
function extractParameter(toolCall, paramKey) {
|
|
107
|
+
if (!paramKey || !toolCall.rawInput)
|
|
108
|
+
return null;
|
|
109
|
+
const value = toolCall.rawInput[paramKey];
|
|
110
|
+
if (typeof value === "string") {
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Format verbiage template with parameter values
|
|
117
|
+
*/
|
|
118
|
+
function formatVerbiage(template, params) {
|
|
119
|
+
let result = template;
|
|
120
|
+
for (const [key, value] of Object.entries(params)) {
|
|
121
|
+
result = result.replace(`{${key}}`, value);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Truncate text to a maximum length with ellipsis
|
|
127
|
+
*/
|
|
128
|
+
function truncate(text, maxLength) {
|
|
129
|
+
if (text.length <= maxLength)
|
|
130
|
+
return text;
|
|
131
|
+
return text.substring(0, maxLength - 1) + "…";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get display verbiage for a tool call
|
|
135
|
+
*/
|
|
136
|
+
export function getToolCallVerbiage(toolCall, tense) {
|
|
137
|
+
// First check if the tool has verbiage metadata
|
|
138
|
+
const template = toolCall.verbiage || TOOL_VERBIAGE_MAP[toolCall.title];
|
|
139
|
+
// If no template, fall back to pretty name or title
|
|
140
|
+
if (!template) {
|
|
141
|
+
const baseName = toolCall.prettyName || toolCall.title;
|
|
142
|
+
return tense === "active" ? `Using ${baseName}` : `Used ${baseName}`;
|
|
143
|
+
}
|
|
144
|
+
const verbiageTemplate = tense === "active" ? template.active : template.past;
|
|
145
|
+
// Extract parameter if specified
|
|
146
|
+
if (template.paramKey) {
|
|
147
|
+
const paramValue = extractParameter(toolCall, template.paramKey);
|
|
148
|
+
if (paramValue) {
|
|
149
|
+
// Truncate long parameter values
|
|
150
|
+
const truncatedValue = truncate(paramValue, 50);
|
|
151
|
+
// Determine the placeholder name based on param key
|
|
152
|
+
let placeholderName = "value";
|
|
153
|
+
if (template.paramKey.includes("file") ||
|
|
154
|
+
template.paramKey.includes("path")) {
|
|
155
|
+
placeholderName = "file";
|
|
156
|
+
}
|
|
157
|
+
else if (template.paramKey.includes("query") ||
|
|
158
|
+
template.paramKey.includes("pattern")) {
|
|
159
|
+
placeholderName = "query";
|
|
160
|
+
}
|
|
161
|
+
else if (template.paramKey.includes("command")) {
|
|
162
|
+
placeholderName = "command";
|
|
163
|
+
}
|
|
164
|
+
else if (template.paramKey.includes("directory")) {
|
|
165
|
+
placeholderName = "directory";
|
|
166
|
+
}
|
|
167
|
+
return formatVerbiage(verbiageTemplate, {
|
|
168
|
+
[placeholderName]: truncatedValue,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// If subline exists, use it as context
|
|
173
|
+
if (toolCall.subline) {
|
|
174
|
+
const prefix = verbiageTemplate.split("{")[0];
|
|
175
|
+
return prefix ? `${prefix.trim()} ${toolCall.subline}` : toolCall.subline;
|
|
176
|
+
}
|
|
177
|
+
// Return template without parameters
|
|
178
|
+
return verbiageTemplate.replace(/\s*\{[^}]+\}/g, "");
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get a short display name for a tool (for grouping)
|
|
182
|
+
*/
|
|
183
|
+
export function getToolDisplayName(toolCall) {
|
|
184
|
+
return toolCall.prettyName || toolCall.title;
|
|
185
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/index.js";
|
|
2
|
+
export interface AppSidebarProps {
|
|
3
|
+
/** The ACP client for fetching sessions */
|
|
4
|
+
client: AcpClient | null;
|
|
5
|
+
/** The current session ID */
|
|
6
|
+
currentSessionId: string | null;
|
|
7
|
+
/** Callback when a session is selected */
|
|
8
|
+
onSessionSelect?: (sessionId: string) => void;
|
|
9
|
+
/** Callback when a new session is requested */
|
|
10
|
+
onNewSession?: () => void;
|
|
11
|
+
/** Callback when a session is renamed */
|
|
12
|
+
onRenameSession?: (sessionId: string) => void;
|
|
13
|
+
/** Callback when a session is archived */
|
|
14
|
+
onArchiveSession?: (sessionId: string) => void;
|
|
15
|
+
/** Callback when a session is deleted */
|
|
16
|
+
onDeleteSession?: (sessionId: string) => void;
|
|
17
|
+
/** Optional footer content */
|
|
18
|
+
footer?: React.ReactNode;
|
|
19
|
+
/** Additional className for the sidebar */
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, footer, className, }: AppSidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Plus } from "lucide-react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { IconButton } from "./IconButton.js";
|
|
5
|
+
import { SessionHistory } from "./SessionHistory.js";
|
|
6
|
+
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, useSidebar, } from "./Sidebar.js";
|
|
7
|
+
export function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, footer, className, }) {
|
|
8
|
+
const { setOpenMobile } = useSidebar();
|
|
9
|
+
const handleNewSession = () => {
|
|
10
|
+
if (onNewSession) {
|
|
11
|
+
onNewSession();
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
// Default behavior: clear session from URL and reload
|
|
15
|
+
const url = new URL(window.location.href);
|
|
16
|
+
url.searchParams.delete("session");
|
|
17
|
+
window.location.href = url.toString();
|
|
18
|
+
}
|
|
19
|
+
setOpenMobile(false);
|
|
20
|
+
};
|
|
21
|
+
return (_jsxs(Sidebar, { className: cn("group-data-[side=left]:border-r-0", className), children: [_jsx(SidebarHeader, { className: "h-16 py-5 pl-6 pr-4", children: _jsxs("div", { className: "flex flex-row items-center justify-between w-full", children: [_jsx("span", { className: "font-semibold text-lg", children: "Sessions" }), _jsx(IconButton, { onClick: handleNewSession, "aria-label": "New Chat", children: _jsx(Plus, { className: "size-4 text-muted-foreground" }) })] }) }), _jsx(SidebarContent, { children: _jsx(SessionHistory, { client: client, currentSessionId: currentSessionId, onSessionSelect: onSessionSelect, onRenameSession: onRenameSession, onArchiveSession: onArchiveSession, onDeleteSession: onDeleteSession }) }), footer && _jsx(SidebarFooter, { children: footer })] }));
|
|
22
|
+
}
|
|
@@ -8,6 +8,9 @@ interface ChatLayoutContextValue {
|
|
|
8
8
|
setPanelSize: (size: PanelSize) => void;
|
|
9
9
|
activeTab: PanelTabType;
|
|
10
10
|
setActiveTab: (tab: PanelTabType) => void;
|
|
11
|
+
panelOpen: boolean;
|
|
12
|
+
setPanelOpen: (open: boolean) => void;
|
|
13
|
+
togglePanel: () => void;
|
|
11
14
|
}
|
|
12
15
|
declare const ChatLayoutContext: React.Context<ChatLayoutContextValue | undefined>;
|
|
13
16
|
declare const useChatLayoutContext: () => ChatLayoutContextValue;
|
|
@@ -36,6 +39,8 @@ export interface ChatLayoutMessagesProps extends React.HTMLAttributes<HTMLDivEle
|
|
|
36
39
|
onScrollChange?: (isAtBottom: boolean) => void;
|
|
37
40
|
/** Whether to show scroll to bottom button */
|
|
38
41
|
showScrollToBottom?: boolean;
|
|
42
|
+
/** Whether to scroll to bottom on initial mount (default: true) */
|
|
43
|
+
initialScrollToBottom?: boolean;
|
|
39
44
|
}
|
|
40
45
|
declare const ChatLayoutMessages: React.ForwardRefExoticComponent<ChatLayoutMessagesProps & React.RefAttributes<HTMLDivElement>>;
|
|
41
46
|
export interface ChatLayoutFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|