@parallelworks/ui 0.19.0 → 0.19.1
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/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
- package/dist/ai/adapter/mock/index.js +2 -80
- package/dist/ai/adapter/mock/mockAdapter.js +81 -0
- package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
- package/dist/ai/adapter/openai/errors.js +37 -0
- package/dist/ai/adapter/openai/index.js +5 -333
- package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
- package/dist/ai/adapter/openai/responses.js +108 -0
- package/dist/ai/adapter/openai/sse.js +112 -0
- package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
- package/dist/ai/agent/classifier.js +12 -0
- package/dist/ai/agent/diff.js +223 -0
- package/dist/ai/agent/diffHighlight.js +101 -0
- package/dist/ai/agent/permissions.js +29 -0
- package/dist/ai/agent/toolfmt.js +383 -0
- package/dist/ai/agent/transcript.js +127 -0
- package/dist/ai/components/AllocationSelector.js +56 -0
- package/dist/ai/components/AttachmentManager.js +144 -0
- package/dist/ai/components/AttachmentUpload.js +179 -0
- package/dist/ai/components/BlockedGroupBanner.js +29 -0
- package/dist/ai/components/BranchNavigator.js +57 -0
- package/dist/ai/components/ChatEmptyState.js +171 -0
- package/dist/ai/components/ChatInput.js +265 -0
- package/dist/ai/components/ChatLayout.js +15 -0
- package/dist/ai/components/ChatMessage.js +338 -0
- package/dist/ai/components/ChatMessageList.js +301 -0
- package/dist/ai/components/ChatSidebar.js +345 -0
- package/dist/ai/components/ChatThread.js +198 -0
- package/dist/ai/components/ComposerChrome.js +50 -0
- package/dist/ai/components/ComposerFrame.js +33 -0
- package/dist/ai/components/DragOverlay.js +20 -0
- package/dist/ai/components/ModelSelector.js +343 -0
- package/dist/ai/components/ShareDialog.js +260 -0
- package/dist/ai/components/SlashMenu.js +91 -0
- package/dist/ai/components/agent/ActivityLine.js +151 -0
- package/dist/ai/components/agent/AgentMessageParts.js +721 -0
- package/dist/ai/components/agent/PermissionPicker.js +38 -0
- package/dist/ai/components/attachmentKeys.js +10 -0
- package/dist/ai/core/ChatProvider.js +848 -0
- package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
- package/dist/ai/core/chatReducer.js +223 -0
- package/dist/ai/core/config.js +45 -0
- package/dist/ai/core/events.js +4 -0
- package/dist/ai/core/exportConversation.js +42 -0
- package/dist/ai/core/greeting.js +38 -0
- package/dist/ai/core/parts.js +84 -0
- package/dist/ai/core/useDragDrop.js +36 -0
- package/dist/ai/core/useKeyboardShortcuts.js +77 -0
- package/dist/ai/core/useSSEStream.js +98 -0
- package/dist/ai/index.js +43 -6644
- package/dist/ai/strings.js +175 -0
- package/dist/ai/ui/Avatar.js +35 -0
- package/dist/ai/ui/Dropdown.js +110 -0
- package/dist/ai/ui/Markdown.js +79 -0
- package/dist/ai/ui/Notice.js +77 -0
- package/dist/ai/ui/codeBreaks.js +36 -0
- package/dist/ai/ui/prose.js +13 -0
- package/dist/ai/ui/sidebar.js +148 -0
- package/dist/ai/utils.js +23 -0
- package/dist/components/AddMenu.js +46 -0
- package/dist/components/Avatar.js +46 -0
- package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
- package/dist/components/Breadcrumbs.js +83 -0
- package/dist/components/Button.js +83 -0
- package/dist/components/Callout.js +23 -0
- package/dist/components/Card.js +31 -0
- package/dist/components/CollapsiblePanel.js +77 -0
- package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
- package/dist/components/CopyToClipboard.js +81 -0
- package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
- package/dist/components/DescriptionList.js +42 -0
- package/dist/components/Dropdown.js +349 -0
- package/dist/components/EmptyState.js +27 -0
- package/dist/components/Filter.js +32 -0
- package/dist/components/FilterPill.js +13 -0
- package/dist/components/IconButton.js +34 -0
- package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
- package/dist/components/Input.js +88 -0
- package/dist/components/LetterBadge.js +13 -0
- package/dist/components/Listbox.js +123 -0
- package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
- package/dist/components/Markdown.js +15 -0
- package/dist/components/MultiSelect.js +171 -0
- package/dist/components/Overview.js +39 -0
- package/dist/components/PageHeader.js +194 -0
- package/dist/components/Pagination.js +35 -0
- package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +1 -1
- package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
- package/dist/components/SectionHeader.js +11 -0
- package/dist/components/SettingModeOption.js +30 -0
- package/dist/components/SettingRow.js +35 -0
- package/dist/components/SettingsCard.js +31 -0
- package/dist/components/SettingsGroup.js +17 -0
- package/dist/components/Sort.js +42 -0
- package/dist/components/StatusBadge.js +63 -0
- package/dist/components/SwitchToggle.js +59 -0
- package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
- package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
- package/dist/components/Toggle.js +20 -0
- package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
- package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
- package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
- package/dist/components/ghostButton.js +7 -0
- package/dist/components/inputClasses.js +4 -0
- package/dist/components/keys.js +27 -0
- package/dist/components/relativeTime.js +32 -0
- package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
- package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
- package/dist/editor/Editor.js +13 -0
- package/dist/editor/EditorField.js +53 -0
- package/dist/editor/FormCodePanel.js +173 -0
- package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +4 -2
- package/dist/editor/index.js +6 -1
- package/dist/editor/themes.js +91 -0
- package/dist/editor/workers.js +29 -0
- package/dist/editor/yaml.js +15 -0
- package/dist/file-explorer/FileExplorer.js +1402 -0
- package/dist/file-explorer/FileExplorerContext.js +370 -0
- package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
- package/dist/file-explorer/FilePreview/Inline.js +45 -0
- package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
- package/dist/file-explorer/FilePreview/Viewer.js +526 -0
- package/dist/file-explorer/FilePreview/index.js +266 -0
- package/dist/file-explorer/FilePreview/parse.js +63 -0
- package/dist/file-explorer/FilePreview/previewCache.js +98 -0
- package/dist/file-explorer/FilePreview/previewType.js +151 -0
- package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
- package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
- package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
- package/dist/file-explorer/FileRow.js +165 -0
- package/dist/file-explorer/FileRowsWindow.js +92 -0
- package/dist/file-explorer/FileTable.js +172 -0
- package/dist/file-explorer/FileTableHeaders.js +49 -0
- package/dist/file-explorer/LoadMoreRow.js +46 -0
- package/dist/file-explorer/TreeView.js +376 -0
- package/dist/file-explorer/helpers.js +537 -0
- package/dist/file-explorer/index.js +7 -5671
- package/dist/file-explorer/lib/batch.js +39 -0
- package/dist/file-explorer/lib/errors.js +9 -0
- package/dist/file-explorer/lib/paging.js +124 -0
- package/dist/file-explorer/lib/utils.js +322 -0
- package/dist/file-explorer/toasts.js +400 -0
- package/dist/file-explorer/treeRows.js +73 -0
- package/dist/file-explorer/useNearEnd.js +27 -0
- package/dist/form/FieldWrapper.js +54 -0
- package/dist/form/Fields/BooleanField.js +51 -0
- package/dist/form/Fields/CheckboxGroupField.js +72 -0
- package/dist/form/Fields/ColorField.js +33 -0
- package/dist/form/Fields/DropdownField.js +49 -0
- package/dist/form/Fields/DurationField.js +130 -0
- package/dist/form/Fields/LabelField.js +19 -0
- package/dist/form/Fields/MultiDropdownField.js +40 -0
- package/dist/form/Fields/NumberField.js +51 -0
- package/dist/form/Fields/ObjectField.js +54 -0
- package/dist/form/Fields/RadioField.js +49 -0
- package/dist/form/Fields/RangeField.js +58 -0
- package/dist/form/Fields/ResourceOptionIcon.js +21 -0
- package/dist/form/Fields/StepField.js +6 -0
- package/dist/form/Fields/StringField.js +37 -0
- package/dist/form/Fields/TextAreaField.js +31 -0
- package/dist/form/Fields/durationValidity.js +11 -0
- package/dist/form/Form.js +643 -0
- package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
- package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
- package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
- package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
- package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
- package/dist/form/Wizard/WizardContainer.js +138 -0
- package/dist/form/Wizard/WizardNavigation.js +92 -0
- package/dist/form/Wizard/WizardStepContent.js +35 -0
- package/dist/form/Wizard/WizardStepIndicator.js +108 -0
- package/dist/form/Wizard/useWizardState.js +118 -0
- package/dist/form/Wizard/utils.js +34 -0
- package/dist/form/fieldContext.js +26 -0
- package/dist/form/fieldRegistry.js +50 -0
- package/dist/form/index.js +17 -2321
- package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
- package/dist/form/useParsedOpts.js +62 -0
- package/dist/form/usePrevious.js +11 -0
- package/dist/form/utils/checkShowIfObject.js +14 -0
- package/dist/form/utils/duration.js +69 -0
- package/dist/form/utils/getParentValue.js +23 -0
- package/dist/form/utils/getPlaceholder.js +9 -0
- package/dist/form/utils/getValueUsingPath.js +23 -0
- package/dist/form/utils/secondaryField.js +22 -0
- package/dist/graph/AnnotationBanner.js +141 -0
- package/dist/graph/Collapse.js +41 -0
- package/dist/graph/DependencyGraph.js +1398 -0
- package/dist/graph/JobSummary.js +104 -0
- package/dist/graph/MatrixGroup.js +107 -0
- package/dist/graph/Reveal.js +57 -0
- package/dist/graph/TreeView.js +711 -0
- package/dist/graph/index.js +1 -2519
- package/dist/graph/types.js +6 -0
- package/dist/index.js +46 -599
- package/dist/list/ActionToolbar.js +184 -0
- package/dist/list/HoverCard.js +73 -0
- package/dist/list/ListPage.js +145 -0
- package/dist/list/ListPager.js +59 -0
- package/dist/list/ListTable.js +163 -0
- package/dist/list/ListViewControls.js +372 -0
- package/dist/list/RowContextMenu.js +350 -0
- package/dist/list/UserHoverCard.js +117 -0
- package/dist/list/index.js +11 -2
- package/dist/list/listSearch.js +137 -0
- package/dist/list/listView.js +210 -0
- package/dist/list/textEntry.js +10 -0
- package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
- package/dist/logviewer/index.js +2 -1
- package/dist/logviewer/segments.js +80 -0
- package/package.json +1 -1
- package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
- package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
- package/dist/chunks/editor-Dk1rbV75.js +0 -361
- package/dist/chunks/list-CJm875m7.js +0 -1418
- /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
//#region src/ai/agent/toolfmt.ts
|
|
2
|
+
var TOOL_HEADERS = {
|
|
3
|
+
Bash: {
|
|
4
|
+
label: "Bash",
|
|
5
|
+
arg: "command"
|
|
6
|
+
},
|
|
7
|
+
ReadFile: {
|
|
8
|
+
label: "Read",
|
|
9
|
+
arg: "path"
|
|
10
|
+
},
|
|
11
|
+
WriteFile: {
|
|
12
|
+
label: "Write",
|
|
13
|
+
arg: "path"
|
|
14
|
+
},
|
|
15
|
+
EditFile: {
|
|
16
|
+
label: "Update",
|
|
17
|
+
arg: "path"
|
|
18
|
+
},
|
|
19
|
+
GlobSearch: {
|
|
20
|
+
label: "Glob",
|
|
21
|
+
arg: "pattern"
|
|
22
|
+
},
|
|
23
|
+
GrepSearch: {
|
|
24
|
+
label: "Grep",
|
|
25
|
+
arg: "pattern"
|
|
26
|
+
},
|
|
27
|
+
WebFetch: {
|
|
28
|
+
label: "WebFetch",
|
|
29
|
+
arg: "url"
|
|
30
|
+
},
|
|
31
|
+
Task: {
|
|
32
|
+
label: "Task",
|
|
33
|
+
arg: "description"
|
|
34
|
+
},
|
|
35
|
+
Skill: {
|
|
36
|
+
label: "Skill",
|
|
37
|
+
arg: "name"
|
|
38
|
+
},
|
|
39
|
+
SendMessage: {
|
|
40
|
+
label: "SendMessage",
|
|
41
|
+
arg: "to"
|
|
42
|
+
},
|
|
43
|
+
AskUserQuestion: {
|
|
44
|
+
label: "AskUserQuestion",
|
|
45
|
+
arg: "question"
|
|
46
|
+
},
|
|
47
|
+
TodoWrite: { label: "TodoWrite" }
|
|
48
|
+
};
|
|
49
|
+
function toolHeaderFor(name) {
|
|
50
|
+
return TOOL_HEADERS[name] ?? { label: name };
|
|
51
|
+
}
|
|
52
|
+
function clip(s, max) {
|
|
53
|
+
const r = [...s];
|
|
54
|
+
if (r.length <= max) return s;
|
|
55
|
+
if (max <= 3) return r.slice(0, max).join("");
|
|
56
|
+
return r.slice(0, max - 3).join("") + "...";
|
|
57
|
+
}
|
|
58
|
+
function sanitizeLabel(s) {
|
|
59
|
+
let out = "";
|
|
60
|
+
for (const ch of s) {
|
|
61
|
+
const c = ch.codePointAt(0) ?? 0;
|
|
62
|
+
if (ch === "\n" || ch === " ") out += " ";
|
|
63
|
+
else if (c < 32 || c === 127) {} else out += ch;
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
function sanitizePanelText(s) {
|
|
68
|
+
let out = "";
|
|
69
|
+
for (const ch of s) {
|
|
70
|
+
const c = ch.codePointAt(0) ?? 0;
|
|
71
|
+
if (ch === " ") out += " ";
|
|
72
|
+
else if (ch === "\n") out += ch;
|
|
73
|
+
else if (c < 32 || c === 127) {} else out += ch;
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
var SALIENT_ARG_ORDER = [
|
|
78
|
+
"command",
|
|
79
|
+
"pattern",
|
|
80
|
+
"path",
|
|
81
|
+
"file_path",
|
|
82
|
+
"glob",
|
|
83
|
+
"url",
|
|
84
|
+
"query",
|
|
85
|
+
"output_mode",
|
|
86
|
+
"question",
|
|
87
|
+
"header"
|
|
88
|
+
];
|
|
89
|
+
var ELIDED_ARGS = /* @__PURE__ */ new Set([
|
|
90
|
+
"content",
|
|
91
|
+
"new_string",
|
|
92
|
+
"old_string",
|
|
93
|
+
"edits",
|
|
94
|
+
"options"
|
|
95
|
+
]);
|
|
96
|
+
function clipArg(s, style) {
|
|
97
|
+
const flat = s.replaceAll("\n", " ");
|
|
98
|
+
if (style.valueClip <= 0) return flat;
|
|
99
|
+
return clip(flat, style.valueClip);
|
|
100
|
+
}
|
|
101
|
+
function displayArg(v, style) {
|
|
102
|
+
return sanitizeLabel(clipArg((typeof v === "string" ? v : JSON.stringify(v)) ?? "", style));
|
|
103
|
+
}
|
|
104
|
+
function formatToolArgs(primary, argsJSON, style) {
|
|
105
|
+
let m;
|
|
106
|
+
try {
|
|
107
|
+
m = JSON.parse(argsJSON);
|
|
108
|
+
} catch {
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
if (!m || typeof m !== "object" || Object.keys(m).length === 0) return "";
|
|
112
|
+
const seen = /* @__PURE__ */ new Set();
|
|
113
|
+
const parts = [];
|
|
114
|
+
const add = (k) => {
|
|
115
|
+
if (!(k in m) || seen.has(k)) return;
|
|
116
|
+
seen.add(k);
|
|
117
|
+
const v = m[k];
|
|
118
|
+
const rendered = typeof v === "string" ? `${k}: "${clipArg(sanitizeLabel(v), style)}"` : `${k}: ${displayArg(v, style)}`;
|
|
119
|
+
parts.push(rendered);
|
|
120
|
+
};
|
|
121
|
+
if (primary && primary in m) {
|
|
122
|
+
seen.add(primary);
|
|
123
|
+
parts.push(displayArg(m[primary], style));
|
|
124
|
+
}
|
|
125
|
+
for (const k of SALIENT_ARG_ORDER) add(k);
|
|
126
|
+
const rest = Object.keys(m).filter((k) => !ELIDED_ARGS.has(k) && !seen.has(k)).sort();
|
|
127
|
+
for (const k of rest) add(k);
|
|
128
|
+
const joined = parts.join(", ");
|
|
129
|
+
if (style.totalClip <= 0) return joined;
|
|
130
|
+
return clip(joined, style.totalClip);
|
|
131
|
+
}
|
|
132
|
+
function summarizeToolArgs(primary, argsJSON) {
|
|
133
|
+
return formatToolArgs(primary, argsJSON, {
|
|
134
|
+
valueClip: 50,
|
|
135
|
+
totalClip: 100
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function fullToolArgs(primary, argsJSON) {
|
|
139
|
+
return formatToolArgs(primary, argsJSON, {
|
|
140
|
+
valueClip: 0,
|
|
141
|
+
totalClip: 0
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function plural(n, noun) {
|
|
145
|
+
return `${n} ${pluralNoun(n, noun)}`;
|
|
146
|
+
}
|
|
147
|
+
function pluralNoun(n, noun) {
|
|
148
|
+
if (n === 1) return noun;
|
|
149
|
+
if (/(?:s|x|ch|sh)$/.test(noun)) return `${noun}es`;
|
|
150
|
+
return `${noun}s`;
|
|
151
|
+
}
|
|
152
|
+
var TOOL_OUTPUT_TRUNCATION_MARKER = "\n\n... output truncated to ";
|
|
153
|
+
function trimToolOutputNotice(body) {
|
|
154
|
+
const i = body.lastIndexOf(TOOL_OUTPUT_TRUNCATION_MARKER);
|
|
155
|
+
if (i >= 0) return [body.slice(0, i).replace(/\n+$/, ""), true];
|
|
156
|
+
return [body, false];
|
|
157
|
+
}
|
|
158
|
+
function summarizeToolResult(result) {
|
|
159
|
+
const trimmed = result.replace(/\n+$/, "");
|
|
160
|
+
if (trimmed.trim() === "") return "(no output)";
|
|
161
|
+
const lines = trimmed.split("\n");
|
|
162
|
+
const first = clip((lines[0] ?? "").trim(), 100);
|
|
163
|
+
if (lines.length > 1) return `${first} (+${lines.length - 1} lines)`;
|
|
164
|
+
return first;
|
|
165
|
+
}
|
|
166
|
+
function isErrorResult(text) {
|
|
167
|
+
return text.trim().startsWith("Error:");
|
|
168
|
+
}
|
|
169
|
+
var RIPGREP_ERROR_PREFIX = "ripgrep error (exit ";
|
|
170
|
+
function resultFailed(name, result) {
|
|
171
|
+
const body = result.trim();
|
|
172
|
+
switch (name) {
|
|
173
|
+
case "Bash":
|
|
174
|
+
if (bashExitCode(body)[2]) return true;
|
|
175
|
+
return isErrorResult(body) && !body.includes("\n");
|
|
176
|
+
case "WebFetch": return webFetchFailed(body);
|
|
177
|
+
case "GrepSearch": return body.startsWith(RIPGREP_ERROR_PREFIX) || isErrorResult(body);
|
|
178
|
+
default: return isErrorResult(body);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function webFetchFailed(body) {
|
|
182
|
+
if (body.startsWith("Error ")) return true;
|
|
183
|
+
const m = body.match(/^HTTP (\d+)/);
|
|
184
|
+
if (m) return Number(m[1]) >= 400;
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
function trailingNote(body) {
|
|
188
|
+
const i = body.lastIndexOf("\n");
|
|
189
|
+
const last = body.slice(i + 1);
|
|
190
|
+
if (last.startsWith("... (")) return [body.slice(0, Math.max(i, 0)), last];
|
|
191
|
+
return [body, ""];
|
|
192
|
+
}
|
|
193
|
+
function contentLines(body) {
|
|
194
|
+
const [rest, note] = trailingNote(body);
|
|
195
|
+
if (rest === "") return [[], note];
|
|
196
|
+
return [rest.split("\n"), note];
|
|
197
|
+
}
|
|
198
|
+
function readFileSummary(body) {
|
|
199
|
+
if (body === "(empty file)") return "Empty file";
|
|
200
|
+
if (body.startsWith("Read image ")) return "Read image";
|
|
201
|
+
const [lines, note] = contentLines(body);
|
|
202
|
+
let more = 0;
|
|
203
|
+
const m = note.match(/^\.\.\. \(truncated, (\d+) more lines\)/);
|
|
204
|
+
if (m) more = Number(m[1]);
|
|
205
|
+
if (more > 0) return `Read ${plural(lines.length, "line")} (${more} more)`;
|
|
206
|
+
return `Read ${plural(lines.length, "line")}`;
|
|
207
|
+
}
|
|
208
|
+
var GREP_CONTENT_PATH = /^(.+?):\d+:/;
|
|
209
|
+
function grepMatchPath(line, lineNums) {
|
|
210
|
+
if (!lineNums) {
|
|
211
|
+
const i = line.indexOf(":");
|
|
212
|
+
return i >= 0 ? line.slice(0, i) : null;
|
|
213
|
+
}
|
|
214
|
+
const m = GREP_CONTENT_PATH.exec(line);
|
|
215
|
+
return m ? m[1] ?? null : null;
|
|
216
|
+
}
|
|
217
|
+
function grepSearchSummary(argsJSON, body) {
|
|
218
|
+
if (body === "No matches found." || body === "No results after applying offset.") return "No matches";
|
|
219
|
+
if (body.startsWith(RIPGREP_ERROR_PREFIX)) return summarizeToolResult(body);
|
|
220
|
+
const [lines, note] = contentLines(body);
|
|
221
|
+
let outputMode = "";
|
|
222
|
+
let lineNums = true;
|
|
223
|
+
try {
|
|
224
|
+
const a = JSON.parse(argsJSON);
|
|
225
|
+
outputMode = a.output_mode ?? "";
|
|
226
|
+
if (typeof a.n === "boolean") lineNums = a.n;
|
|
227
|
+
} catch {}
|
|
228
|
+
let s;
|
|
229
|
+
if (outputMode === "content") {
|
|
230
|
+
const files = /* @__PURE__ */ new Set();
|
|
231
|
+
let matches = 0;
|
|
232
|
+
for (const l of lines) {
|
|
233
|
+
const path = grepMatchPath(l, lineNums);
|
|
234
|
+
if (path === null) continue;
|
|
235
|
+
matches++;
|
|
236
|
+
files.add(path);
|
|
237
|
+
}
|
|
238
|
+
s = `Found ${plural(matches, "match")} in ${plural(files.size, "file")}`;
|
|
239
|
+
} else if (outputMode === "count") {
|
|
240
|
+
let total = 0;
|
|
241
|
+
for (const l of lines) {
|
|
242
|
+
const i = l.lastIndexOf(":");
|
|
243
|
+
const tail = i >= 0 ? l.slice(i + 1) : l;
|
|
244
|
+
const n = Number.parseInt(tail, 10);
|
|
245
|
+
if (!Number.isNaN(n)) total += n;
|
|
246
|
+
}
|
|
247
|
+
s = `Found ${plural(total, "match")} in ${plural(lines.length, "file")}`;
|
|
248
|
+
} else s = `Found ${plural(lines.length, "file")}`;
|
|
249
|
+
if (note !== "") s += " (truncated)";
|
|
250
|
+
return s;
|
|
251
|
+
}
|
|
252
|
+
function globSearchSummary(body) {
|
|
253
|
+
if (body === "No files matched the pattern.") return "No files matched";
|
|
254
|
+
const [lines, note] = contentLines(body);
|
|
255
|
+
let s = `Found ${plural(lines.length, "file")}`;
|
|
256
|
+
if (note !== "") s += " (truncated)";
|
|
257
|
+
return s;
|
|
258
|
+
}
|
|
259
|
+
function bashExitCode(body) {
|
|
260
|
+
let i = body.lastIndexOf("\nExit code: ");
|
|
261
|
+
if (i < 0) {
|
|
262
|
+
if (!body.startsWith("Exit code: ")) return [
|
|
263
|
+
body,
|
|
264
|
+
0,
|
|
265
|
+
false
|
|
266
|
+
];
|
|
267
|
+
i = 0;
|
|
268
|
+
}
|
|
269
|
+
const m = body.slice(i).replace(/^\n/, "").match(/^Exit code: (\d+)/);
|
|
270
|
+
const code = m ? Number(m[1]) : 0;
|
|
271
|
+
return [
|
|
272
|
+
body.slice(0, i).replace(/\n+$/, ""),
|
|
273
|
+
code,
|
|
274
|
+
true
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
function bashSummary(body) {
|
|
278
|
+
if (body === "(no output)") return "(no output)";
|
|
279
|
+
const [out, code, ok] = bashExitCode(body);
|
|
280
|
+
if (!ok) return summarizeToolResult(body);
|
|
281
|
+
if (out === "") return `Exit ${code}`;
|
|
282
|
+
return `Exit ${code} · ${plural(out.split("\n").length, "line")}`;
|
|
283
|
+
}
|
|
284
|
+
function webFetchSummary(body) {
|
|
285
|
+
const m = body.match(/^HTTP (\d+)/);
|
|
286
|
+
if (!m) return summarizeToolResult(body);
|
|
287
|
+
const status = Number(m[1]);
|
|
288
|
+
const sep = body.indexOf("\n\n");
|
|
289
|
+
if (sep < 0) return clip(body.split("\n")[0] ?? "", 100);
|
|
290
|
+
return `HTTP ${status} · ${plural(body.slice(sep + 2).split("\n").length, "line")}`;
|
|
291
|
+
}
|
|
292
|
+
function toolSummary(name, args, result, isError, editSummaryFn) {
|
|
293
|
+
const [body, spilled] = trimToolOutputNotice(result.replace(/\n+$/, ""));
|
|
294
|
+
if (isError || body.trim() === "" || isErrorResult(body)) return summarizeToolResult(result);
|
|
295
|
+
let s;
|
|
296
|
+
switch (name) {
|
|
297
|
+
case "EditFile":
|
|
298
|
+
case "WriteFile": {
|
|
299
|
+
const e = editSummaryFn?.(name, args) ?? "";
|
|
300
|
+
return e !== "" ? e : summarizeToolResult(result);
|
|
301
|
+
}
|
|
302
|
+
case "ReadFile":
|
|
303
|
+
s = readFileSummary(body);
|
|
304
|
+
break;
|
|
305
|
+
case "GrepSearch":
|
|
306
|
+
s = grepSearchSummary(args, body);
|
|
307
|
+
break;
|
|
308
|
+
case "GlobSearch":
|
|
309
|
+
s = globSearchSummary(body);
|
|
310
|
+
break;
|
|
311
|
+
case "Bash":
|
|
312
|
+
s = bashSummary(body);
|
|
313
|
+
break;
|
|
314
|
+
case "WebFetch":
|
|
315
|
+
s = webFetchSummary(body);
|
|
316
|
+
break;
|
|
317
|
+
default: return summarizeToolResult(result);
|
|
318
|
+
}
|
|
319
|
+
if (spilled) s += " (output truncated)";
|
|
320
|
+
return s;
|
|
321
|
+
}
|
|
322
|
+
var ROLLUP_CATEGORIES = [
|
|
323
|
+
[(n) => n === "GrepSearch" || n === "GlobSearch", (n) => `searched for ${plural(n, "pattern")}`],
|
|
324
|
+
[(n) => n === "ReadFile", (n) => `read ${plural(n, "file")}`],
|
|
325
|
+
[(n) => n === "Bash", (n) => `ran ${plural(n, "shell command")}`],
|
|
326
|
+
[(n) => n === "WebFetch", (n) => `fetched ${plural(n, "URL")}`],
|
|
327
|
+
[(n) => n === "Skill", (n) => `loaded ${plural(n, "skill")}`],
|
|
328
|
+
[(n) => n === "SendMessage", (n) => `sent ${plural(n, "message")}`],
|
|
329
|
+
[(n) => n.startsWith("mcp__"), (n) => `called ${plural(n, "MCP tool")}`],
|
|
330
|
+
[() => true, (n) => `ran ${plural(n, "tool")}`]
|
|
331
|
+
];
|
|
332
|
+
var NON_GROUPABLE_TOOLS = /* @__PURE__ */ new Set([
|
|
333
|
+
"EditFile",
|
|
334
|
+
"WriteFile",
|
|
335
|
+
"TodoWrite",
|
|
336
|
+
"Task"
|
|
337
|
+
]);
|
|
338
|
+
function isGroupableTool(name) {
|
|
339
|
+
return !NON_GROUPABLE_TOOLS.has(name);
|
|
340
|
+
}
|
|
341
|
+
function rollupSentence(names) {
|
|
342
|
+
const counts = ROLLUP_CATEGORIES.map(() => 0);
|
|
343
|
+
for (const name of names) for (let i = 0; i < ROLLUP_CATEGORIES.length; i++) if (ROLLUP_CATEGORIES[i]?.[0](name)) {
|
|
344
|
+
counts[i] = (counts[i] ?? 0) + 1;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
const parts = [];
|
|
348
|
+
for (let i = 0; i < counts.length; i++) {
|
|
349
|
+
const n = counts[i] ?? 0;
|
|
350
|
+
if (n > 0) {
|
|
351
|
+
const cat = ROLLUP_CATEGORIES[i];
|
|
352
|
+
if (cat) parts.push(cat[1](n));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (parts.length === 0) return "";
|
|
356
|
+
const s = parts.join(", ");
|
|
357
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
358
|
+
}
|
|
359
|
+
var AGENT_COLOR_NAMES = [
|
|
360
|
+
"blue",
|
|
361
|
+
"green",
|
|
362
|
+
"yellow",
|
|
363
|
+
"purple",
|
|
364
|
+
"cyan",
|
|
365
|
+
"orange",
|
|
366
|
+
"pink",
|
|
367
|
+
"red"
|
|
368
|
+
];
|
|
369
|
+
var AGENT_COLOR_HEX = {
|
|
370
|
+
red: "#ef4444",
|
|
371
|
+
blue: "#3b82f6",
|
|
372
|
+
green: "#22c55e",
|
|
373
|
+
yellow: "#eab308",
|
|
374
|
+
purple: "#a855f7",
|
|
375
|
+
orange: "#f97316",
|
|
376
|
+
pink: "#ec4899",
|
|
377
|
+
cyan: "#06b6d4"
|
|
378
|
+
};
|
|
379
|
+
function agentColorHex(name) {
|
|
380
|
+
return name ? AGENT_COLOR_HEX[name] ?? null : null;
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
export { AGENT_COLOR_NAMES, agentColorHex, bashExitCode, clip, fullToolArgs, isGroupableTool, plural, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, summarizeToolArgs, toolHeaderFor, toolSummary };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { clip, sanitizeLabel } from "./toolfmt.js";
|
|
2
|
+
//#region src/ai/agent/transcript.ts
|
|
3
|
+
var HIDDEN_TRANSCRIPT_TOOLS = /* @__PURE__ */ new Set([
|
|
4
|
+
"AskUserQuestion",
|
|
5
|
+
"TodoWrite",
|
|
6
|
+
"ExitPlanMode"
|
|
7
|
+
]);
|
|
8
|
+
function hiddenTranscriptTool(name) {
|
|
9
|
+
return HIDDEN_TRANSCRIPT_TOOLS.has(name);
|
|
10
|
+
}
|
|
11
|
+
function parseArgs(argsJSON) {
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(argsJSON);
|
|
14
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
15
|
+
} catch {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function str(v) {
|
|
20
|
+
return typeof v === "string" ? v : "";
|
|
21
|
+
}
|
|
22
|
+
function askQuestionFromArgs(argsJSON) {
|
|
23
|
+
return str(parseArgs(argsJSON)["question"]);
|
|
24
|
+
}
|
|
25
|
+
function planFromArgs(argsJSON) {
|
|
26
|
+
return str(parseArgs(argsJSON)["plan"]);
|
|
27
|
+
}
|
|
28
|
+
/** A Task call's display label the way the tool itself picks it: the
|
|
29
|
+
* description, else the clipped prompt, plus its custom agent type. */
|
|
30
|
+
function taskCallFromArgs(argsJSON) {
|
|
31
|
+
const a = parseArgs(argsJSON);
|
|
32
|
+
const description = str(a["description"]) || clip(str(a["prompt"]), 40);
|
|
33
|
+
return {
|
|
34
|
+
description: sanitizeLabel(description),
|
|
35
|
+
agentType: agentTypeLabel(str(a["subagent_type"]))
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** The built-in "default" type is the same general-purpose agent an untyped
|
|
39
|
+
* Task spawns, so naming it would only add noise. */
|
|
40
|
+
function agentTypeLabel(t) {
|
|
41
|
+
return t === "default" ? "" : sanitizeLabel(t);
|
|
42
|
+
}
|
|
43
|
+
/** The first line when the model wrote it as a heading ("# Title" or
|
|
44
|
+
* "**Title**"), the way reasoning summaries open, so a folded thought says
|
|
45
|
+
* what it was about. Prose gets no label of its own. */
|
|
46
|
+
function thinkingHeading(raw) {
|
|
47
|
+
const first = raw.trim().split("\n")[0]?.trim() ?? "";
|
|
48
|
+
let line;
|
|
49
|
+
if (first.startsWith("#")) line = first.replace(/^#+/, "").trim();
|
|
50
|
+
else if (first.length > 4 && first.startsWith("**") && first.endsWith("**")) line = first.slice(2, -2).trim();
|
|
51
|
+
else return "";
|
|
52
|
+
return clip(sanitizeLabel(line), 60);
|
|
53
|
+
}
|
|
54
|
+
var INTERRUPTED_MARKER = "[Request interrupted by the user.]";
|
|
55
|
+
/** How a turn cut short reads, whether replayed or watched live. */
|
|
56
|
+
var INTERRUPTED_NOTICE = INTERRUPTED_MARKER.slice(1, -1);
|
|
57
|
+
/** The line the daemon files as the assistant's when a turn is cut short;
|
|
58
|
+
* it is a status, not something the model said. */
|
|
59
|
+
function interruptionNotice(text) {
|
|
60
|
+
return text.trim() === INTERRUPTED_MARKER ? INTERRUPTED_NOTICE : null;
|
|
61
|
+
}
|
|
62
|
+
function firstNonEmptyLine(text, max) {
|
|
63
|
+
for (const line of text.split("\n")) {
|
|
64
|
+
const s = line.trim();
|
|
65
|
+
if (s !== "") return clip(s, max);
|
|
66
|
+
}
|
|
67
|
+
return "";
|
|
68
|
+
}
|
|
69
|
+
var SUBAGENT_NOTICE_HEADS = /* @__PURE__ */ new Set(["Background subagent", "Message from subagent"]);
|
|
70
|
+
/** Reads a "[Background subagent <id> (<desc>) completed]" header; null for
|
|
71
|
+
* any other notice, which keeps its full text. */
|
|
72
|
+
function parseSubagentNotice(text) {
|
|
73
|
+
const trimmed = text.trim();
|
|
74
|
+
const nl = trimmed.indexOf("\n");
|
|
75
|
+
let head = nl === -1 ? trimmed : trimmed.slice(0, nl);
|
|
76
|
+
let body = nl === -1 ? "" : trimmed.slice(nl + 1);
|
|
77
|
+
if (!head.startsWith("[") || !head.endsWith("]")) return null;
|
|
78
|
+
head = head.slice(1, -1);
|
|
79
|
+
let shell = false;
|
|
80
|
+
let kind;
|
|
81
|
+
let rest;
|
|
82
|
+
const sub = head.indexOf(" subagent ");
|
|
83
|
+
if (sub !== -1 && SUBAGENT_NOTICE_HEADS.has(`${head.slice(0, sub)} subagent`)) {
|
|
84
|
+
kind = head.slice(0, sub);
|
|
85
|
+
rest = head.slice(sub + 10);
|
|
86
|
+
} else {
|
|
87
|
+
const cmd = head.indexOf(" command ");
|
|
88
|
+
if (cmd === -1 || head.slice(0, cmd) !== "Background") return null;
|
|
89
|
+
kind = "Background";
|
|
90
|
+
rest = head.slice(cmd + 9);
|
|
91
|
+
shell = true;
|
|
92
|
+
}
|
|
93
|
+
const open = rest.indexOf(" (");
|
|
94
|
+
if (open === -1) return null;
|
|
95
|
+
const id = rest.slice(0, open);
|
|
96
|
+
rest = rest.slice(open + 2);
|
|
97
|
+
const end = rest.lastIndexOf(")");
|
|
98
|
+
if (end === -1) return null;
|
|
99
|
+
const tail = rest.slice(end + 1);
|
|
100
|
+
const notice = {
|
|
101
|
+
id,
|
|
102
|
+
description: rest.slice(0, end),
|
|
103
|
+
interim: kind === "Message from",
|
|
104
|
+
silent: tail.includes("was interrupted"),
|
|
105
|
+
preview: "",
|
|
106
|
+
body: ""
|
|
107
|
+
};
|
|
108
|
+
if (shell) {
|
|
109
|
+
notice.preview = tail.trim();
|
|
110
|
+
return notice;
|
|
111
|
+
}
|
|
112
|
+
const lines = body.split("\n");
|
|
113
|
+
const last = lines[lines.length - 1] ?? "";
|
|
114
|
+
if (lines.length > 0 && last.trim().startsWith("(pass ")) body = lines.slice(0, -1).join("\n");
|
|
115
|
+
notice.body = body.trim();
|
|
116
|
+
notice.preview = firstNonEmptyLine(body, 70);
|
|
117
|
+
return notice;
|
|
118
|
+
}
|
|
119
|
+
/** The line that marks a child's report entering the main conversation. */
|
|
120
|
+
function subagentDeliveryLine(n) {
|
|
121
|
+
const name = n.description ? `${n.id} (${n.description})` : n.id;
|
|
122
|
+
let label = n.interim ? `↳ message from ${name}` : `↳ ${name} reported back`;
|
|
123
|
+
if (n.preview) label += `: ${sanitizeLabel(n.preview)}`;
|
|
124
|
+
return label;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { INTERRUPTED_NOTICE, agentTypeLabel, askQuestionFromArgs, firstNonEmptyLine, hiddenTranscriptTool, interruptionNotice, parseSubagentNotice, planFromArgs, subagentDeliveryLine, taskCallFromArgs, thinkingHeading };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useChat } from "../core/ChatProvider.js";
|
|
2
|
+
import Dropdown from "../ui/Dropdown.js";
|
|
3
|
+
import { isOrgModel } from "../utils.js";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import useSWR from "swr";
|
|
7
|
+
//#region src/ai/components/AllocationSelector.tsx
|
|
8
|
+
function AllocationSelector({ variant = "default" } = {}) {
|
|
9
|
+
const bare = variant === "bare";
|
|
10
|
+
const { adapter, selectedProvider, selectedAllocation, setSelectedAllocation } = useChat();
|
|
11
|
+
const isOrgProvider = isOrgModel(selectedProvider);
|
|
12
|
+
const allocationsAdapter = adapter.allocations;
|
|
13
|
+
const { data: allocations } = useSWR(isOrgProvider && allocationsAdapter ? ["ai-chat-allocations"] : null, () => allocationsAdapter.list());
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (isOrgProvider && allocations?.length && !selectedAllocation) setSelectedAllocation(allocations[0].name);
|
|
16
|
+
}, [
|
|
17
|
+
isOrgProvider,
|
|
18
|
+
allocations,
|
|
19
|
+
selectedAllocation,
|
|
20
|
+
setSelectedAllocation
|
|
21
|
+
]);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!isOrgProvider && selectedAllocation) setSelectedAllocation(null);
|
|
24
|
+
}, [
|
|
25
|
+
isOrgProvider,
|
|
26
|
+
selectedAllocation,
|
|
27
|
+
setSelectedAllocation
|
|
28
|
+
]);
|
|
29
|
+
if (!isOrgProvider || !allocations?.length) return null;
|
|
30
|
+
const options = allocations.map((alloc) => ({
|
|
31
|
+
label: alloc.name,
|
|
32
|
+
value: alloc.name
|
|
33
|
+
}));
|
|
34
|
+
const selected = allocations.find((a) => a.name === selectedAllocation);
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
36
|
+
className: "flex items-center gap-2",
|
|
37
|
+
children: [/* @__PURE__ */ jsx(Dropdown, {
|
|
38
|
+
options,
|
|
39
|
+
value: selectedAllocation ?? "",
|
|
40
|
+
onChange: (v) => setSelectedAllocation(v || null),
|
|
41
|
+
variant,
|
|
42
|
+
textBoxClassName: bare ? "rounded-md px-1.5 py-0.5 text-[11px] hover:theme-muted-panel" : "h-8 rounded-lg border theme-border text-xs px-2",
|
|
43
|
+
placeholder: "Select allocation"
|
|
44
|
+
}), selected && /* @__PURE__ */ jsxs("span", {
|
|
45
|
+
className: "text-[10px] theme-muted-text whitespace-nowrap",
|
|
46
|
+
children: [
|
|
47
|
+
"$",
|
|
48
|
+
(selected.used ?? 0).toFixed(2),
|
|
49
|
+
" / $",
|
|
50
|
+
selected.total.toFixed(2)
|
|
51
|
+
]
|
|
52
|
+
})]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { AllocationSelector as default };
|