mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-27 20:29:44 +02:00
Tool mentions (#239)
* disable click for invalid tools * handle variables as mentions in the editor * delete tools persist immediately * deleting tools in live view shows the same warning and option to switch to draft
This commit is contained in:
parent
158777b045
commit
5efdee18eb
3 changed files with 51 additions and 9 deletions
|
|
@ -105,8 +105,6 @@ export default function MarkdownContent({
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="inline-block bg-[#e0f2fe] text-[red] px-1.5 py-0.5 rounded whitespace-nowrap cursor-pointer"
|
className="inline-block bg-[#e0f2fe] text-[red] px-1.5 py-0.5 rounded whitespace-nowrap cursor-pointer"
|
||||||
onClick={handleMentionClick}
|
|
||||||
title={onMentionNavigate ? 'Click to open' : undefined}
|
|
||||||
>
|
>
|
||||||
{displayLabel} (!)
|
{displayLabel} (!)
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ Quill.register('modules/mention', Mention);
|
||||||
|
|
||||||
function markdownToParts(markdown: string, atValues: Match[]): (string | Match)[] {
|
function markdownToParts(markdown: string, atValues: Match[]): (string | Match)[] {
|
||||||
// Regex match for pattern [@type:name](#type:something) where type is tool/prompt/agent
|
// Regex match for pattern [@type:name](#type:something) where type is tool/prompt/agent
|
||||||
const mentionRegex = /\[@(tool|prompt|agent):([^\]]+)\]\(#mention\)/g;
|
const mentionRegex = /\[@(tool|prompt|agent|variable):([^\]]+)\]\(#mention\)/g;
|
||||||
const parts: (string | Match)[] = [];
|
const parts: (string | Match)[] = [];
|
||||||
|
|
||||||
let lastIndex = 0;
|
let lastIndex = 0;
|
||||||
|
|
|
||||||
|
|
@ -1254,9 +1254,27 @@ export function WorkflowEditor({
|
||||||
dispatch({ type: "update_pipeline", name, pipeline });
|
dispatch({ type: "update_pipeline", name, pipeline });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeleteAgent(name: string) {
|
async function handleDeleteAgent(name: string) {
|
||||||
if (window.confirm(`Are you sure you want to delete the agent "${name}"?`)) {
|
if (window.confirm(`Are you sure you want to delete the agent "${name}"?`)) {
|
||||||
dispatch({ type: "delete_agent", name });
|
// Optimistically update UI (guard will show modal in live mode)
|
||||||
|
dispatchGuarded({ type: "delete_agent", name });
|
||||||
|
// Persist immediately to avoid debounce races overwriting local state
|
||||||
|
if (!isLive) {
|
||||||
|
try {
|
||||||
|
const remainingAgents = state.present.workflow.agents.filter(a => a.name !== name);
|
||||||
|
const toSave = {
|
||||||
|
...state.present.workflow,
|
||||||
|
agents: remainingAgents,
|
||||||
|
// If startAgent was deleted, set to first remaining or ''
|
||||||
|
startAgent: state.present.workflow.startAgent === name
|
||||||
|
? (remainingAgents[0]?.name || '')
|
||||||
|
: state.present.workflow.startAgent,
|
||||||
|
} as z.infer<typeof Workflow>;
|
||||||
|
await saveWorkflow(projectId, toSave);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to persist agent deletion', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1264,9 +1282,22 @@ export function WorkflowEditor({
|
||||||
dispatch({ type: "update_tool", name, tool });
|
dispatch({ type: "update_tool", name, tool });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeleteTool(name: string) {
|
async function handleDeleteTool(name: string) {
|
||||||
if (window.confirm(`Are you sure you want to delete the tool "${name}"?`)) {
|
if (window.confirm(`Are you sure you want to delete the tool "${name}"?`)) {
|
||||||
dispatch({ type: "delete_tool", name });
|
// Optimistically update UI (guard will show modal in live mode)
|
||||||
|
dispatchGuarded({ type: "delete_tool", name });
|
||||||
|
// Persist immediately to avoid debounce races that can re-add the tool
|
||||||
|
if (!isLive) {
|
||||||
|
try {
|
||||||
|
const toSave = {
|
||||||
|
...state.present.workflow,
|
||||||
|
tools: state.present.workflow.tools.filter(t => t.name !== name),
|
||||||
|
} as z.infer<typeof Workflow>;
|
||||||
|
await saveWorkflow(projectId, toSave);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to persist tool deletion', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1283,9 +1314,22 @@ export function WorkflowEditor({
|
||||||
dispatch({ type: "update_prompt_no_select", name, prompt });
|
dispatch({ type: "update_prompt_no_select", name, prompt });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeletePrompt(name: string) {
|
async function handleDeletePrompt(name: string) {
|
||||||
if (window.confirm(`Are you sure you want to delete the prompt "${name}"?`)) {
|
if (window.confirm(`Are you sure you want to delete the prompt "${name}"?`)) {
|
||||||
dispatch({ type: "delete_prompt", name });
|
// Optimistically update UI (guard will show modal in live mode)
|
||||||
|
dispatchGuarded({ type: "delete_prompt", name });
|
||||||
|
// Persist immediately to avoid debounce races overwriting local state
|
||||||
|
if (!isLive) {
|
||||||
|
try {
|
||||||
|
const toSave = {
|
||||||
|
...state.present.workflow,
|
||||||
|
prompts: state.present.workflow.prompts.filter(p => p.name !== name),
|
||||||
|
} as z.infer<typeof Workflow>;
|
||||||
|
await saveWorkflow(projectId, toSave);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to persist prompt deletion', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue