Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
06fbc29
v0
Sg312 Jan 30, 2026
cb3618a
v1
Sg312 Jan 30, 2026
8b7b331
Basic ss tes
Sg312 Jan 31, 2026
301e25c
Ss tests
Sg312 Jan 31, 2026
4c821d0
Stuff
Sg312 Jan 31, 2026
6cd8f1d
Add mcp
Sg312 Jan 31, 2026
793c877
mcp v1
Sg312 Jan 31, 2026
e04f379
Improvement
Sg312 Feb 1, 2026
4d84c54
Fix
Sg312 Feb 3, 2026
8f17bc4
BROKEN
Sg312 Feb 3, 2026
2d9a7c6
Checkpoint
Sg312 Feb 4, 2026
addc760
Streaming
Sg312 Feb 4, 2026
a58a61b
Fix abort
Sg312 Feb 4, 2026
be7fb8f
Things are broken
Sg312 Feb 4, 2026
b034b1c
Streaming seems to work but copilot is dumb
Sg312 Feb 4, 2026
8c48cdd
Fix edge issue
Sg312 Feb 4, 2026
d8daf3a
LUAAAA
Sg312 Feb 4, 2026
cbd7bb6
Fix stream buffer
Sg312 Feb 4, 2026
89782f6
Fix lint
Sg312 Feb 4, 2026
9a5a494
Checkpoint
Sg312 Feb 5, 2026
7402b38
Initial temp state, in the middle of a refactor
Sg312 Feb 5, 2026
4faa939
Initial test shows diff store still working
Sg312 Feb 5, 2026
7183448
Tool refactor
Sg312 Feb 5, 2026
b3e74e4
First cleanup pass complete - untested
Sg312 Feb 5, 2026
6b40d4f
Continued cleanup
Sg312 Feb 5, 2026
39968be
Refactor
Sg312 Feb 6, 2026
ba8f39f
Refactor complete - no testing yet
Sg312 Feb 6, 2026
fb4afeb
Fix - cursor makes me sad
Sg312 Feb 6, 2026
dd02395
Fix mcp
Sg312 Feb 6, 2026
08a8e14
Clean up mcp
Sg312 Feb 6, 2026
fd1e61b
Updated mcp
Sg312 Feb 6, 2026
69bdffa
Add respond to subagents
Sg312 Feb 6, 2026
74f863a
Fix definitions
Sg312 Feb 6, 2026
3dcd008
Add tools
Sg312 Feb 6, 2026
0c51ce5
Add tools
Sg312 Feb 6, 2026
df3523e
Add copilot mcp tracking
Sg312 Feb 6, 2026
6cb112e
Fix lint
Sg312 Feb 6, 2026
18e493e
Fix mcp
Sg312 Feb 6, 2026
a73e351
Fix
Sg312 Feb 6, 2026
67c2271
Updates
Sg312 Feb 6, 2026
a220455
Clean up mcp
Sg312 Feb 7, 2026
6735eaa
Fix copilot mcp tool names to be sim prefixed
Sg312 Feb 7, 2026
4d4d002
Add opus 4.6
Sg312 Feb 7, 2026
b07b812
Fix discovery tool
Sg312 Feb 7, 2026
220a540
Fix
Sg312 Feb 7, 2026
ebf4e90
Remove logs
Sg312 Feb 7, 2026
7e592e8
Fix go side tool rendering
Sg312 Feb 7, 2026
25d255a
Update docs
Sg312 Feb 9, 2026
b4361b8
Fix hydration
Sg312 Feb 9, 2026
d2c028f
Fix tool call resolution
Sg312 Feb 9, 2026
ed613c3
Fix
Sg312 Feb 9, 2026
4698f73
Fix lint
Sg312 Feb 9, 2026
79af303
Fix superagent and autoallow integrations
Sg312 Feb 9, 2026
c086912
Fix always allow
Sg312 Feb 9, 2026
9a47033
Update block
Sg312 Feb 9, 2026
7200421
Remove plan docs
Sg312 Feb 9, 2026
ab39a4f
Fix hardcoded ff
Sg312 Feb 9, 2026
dba4e61
Fix dropped provider
Sg312 Feb 9, 2026
b14e844
Fix lint
Sg312 Feb 9, 2026
395f890
Fix tests
Sg312 Feb 9, 2026
7458bbd
Fix dead messages array
Sg312 Feb 9, 2026
48c9a3a
Fix discovery
Sg312 Feb 9, 2026
7153141
Fix run workflow
Sg312 Feb 10, 2026
7670cdf
Fix run block
Sg312 Feb 10, 2026
1beb35c
Fix run from block in copilot
Sg312 Feb 10, 2026
18f1d76
Fix lint
Sg312 Feb 10, 2026
8a2eacf
Fix skip and mtb
Sg312 Feb 10, 2026
bd6a103
Fix typing
Sg312 Feb 10, 2026
ddc5164
Fix tool call
Sg312 Feb 10, 2026
bb4e072
Bump api version
Sg312 Feb 10, 2026
98df298
Fix bun lock
Sg312 Feb 10, 2026
621dd23
Nuke bad files
Sg312 Feb 10, 2026
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
Prev Previous commit
Next Next commit
Fix run from block in copilot
  • Loading branch information
Sg312 committed Feb 10, 2026
commit 1beb35c225d95ef299c26c458087ee0f660f1d4e
8 changes: 4 additions & 4 deletions apps/sim/lib/copilot/client-sse/subagent-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,10 @@ export const subAgentSSEHandlers: Record<string, SSEHandler> = {
sendAutoAcceptConfirmation(id)
}

// Client-executable run tools: execute on the client for real-time feedback.
// The server defers execution in interactive mode; we execute here and
// report back via mark-complete.
if (CLIENT_EXECUTABLE_RUN_TOOLS.has(name)) {
// Client-executable run tools: if auto-allowed, execute immediately for
// real-time feedback. For non-auto-allowed, the user must click "Allow"
// first — handleRun in tool-call.tsx triggers executeRunToolOnClient.
if (CLIENT_EXECUTABLE_RUN_TOOLS.has(name) && isAutoAllowed) {
executeRunToolOnClient(id, name, args || {})
}
},
Expand Down
17 changes: 17 additions & 0 deletions apps/sim/lib/copilot/orchestrator/sse-handlers/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,23 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
options.timeout || STREAM_TIMEOUT_MS,
options.abortSignal
)
if (completion?.status === 'rejected') {
toolCall.status = 'rejected'
toolCall.endTime = Date.now()
markToolComplete(
toolCall.id,
toolCall.name,
400,
completion.message || 'Tool execution rejected'
).catch((err) => {
logger.error('markToolComplete fire-and-forget failed (subagent run tool rejected)', {
toolCallId: toolCall.id,
error: err instanceof Error ? err.message : String(err),
})
})
markToolResultSeen(toolCallId)
return
}
const success = completion?.status === 'success'
toolCall.status = success ? 'success' : 'error'
toolCall.endTime = Date.now()
Expand Down
18 changes: 12 additions & 6 deletions apps/sim/lib/copilot/orchestrator/sse-handlers/tool-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,12 @@ export async function waitForToolDecision(
}

/**
* Wait for a tool completion signal (success/error) from the client.
* Unlike waitForToolDecision which returns on any status, this ignores
* intermediate statuses like 'accepted'/'rejected'/'background' and only
* returns when the client reports final completion via success/error.
* Wait for a tool completion signal (success/error/rejected) from the client.
* Unlike waitForToolDecision which returns on any status, this ignores the
* initial 'accepted' status and only returns on terminal statuses:
* - success: client finished executing successfully
* - error: client execution failed
* - rejected: user clicked Skip (subagent run tools where user hasn't auto-allowed)
*
* Used for client-executable run tools: the client executes the workflow
* and posts success/error to /api/copilot/confirm when done. The server
Expand All @@ -166,8 +168,12 @@ export async function waitForToolCompletion(
while (Date.now() - start < timeoutMs) {
if (abortSignal?.aborted) return null
const decision = await getToolConfirmation(toolCallId)
// Only return on completion statuses, not accept/reject decisions
if (decision?.status === 'success' || decision?.status === 'error') {
// Return on completion/terminal statuses, not intermediate 'accepted'
if (
decision?.status === 'success' ||
decision?.status === 'error' ||
decision?.status === 'rejected'
) {
return decision
}
await new Promise((resolve) => setTimeout(resolve, interval))
Expand Down
87 changes: 51 additions & 36 deletions apps/sim/lib/copilot/tools/client/tool-display-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ import {
import { getLatestBlock } from '@/blocks/registry'
import { getCustomTool } from '@/hooks/queries/custom-tools'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'

/** Resolve a block ID to its human-readable name from the workflow store. */
function resolveBlockName(blockId: string | undefined): string | undefined {
if (!blockId) return undefined
try {
const blocks = useWorkflowStore.getState().blocks
return blocks[blockId]?.name || undefined
} catch {
return undefined
}
}

export enum ClientToolCallState {
generating = 'generating',
Expand Down Expand Up @@ -1742,12 +1754,12 @@ const META_generate_api_key: ToolMetadata = {
const META_run_block: ToolMetadata = {
displayNames: {
[ClientToolCallState.generating]: { text: 'Preparing to run block', icon: Loader2 },
[ClientToolCallState.pending]: { text: 'Run this block?', icon: Play },
[ClientToolCallState.pending]: { text: 'Run block?', icon: Play },
[ClientToolCallState.executing]: { text: 'Running block', icon: Loader2 },
[ClientToolCallState.success]: { text: 'Executed block', icon: Play },
[ClientToolCallState.success]: { text: 'Ran block', icon: Play },
[ClientToolCallState.error]: { text: 'Failed to run block', icon: XCircle },
[ClientToolCallState.rejected]: { text: 'Skipped block execution', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted block execution', icon: MinusCircle },
[ClientToolCallState.rejected]: { text: 'Skipped running block', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted running block', icon: MinusCircle },
[ClientToolCallState.background]: { text: 'Running block in background', icon: Play },
},
interrupt: {
Expand Down Expand Up @@ -1775,23 +1787,24 @@ const META_run_block: ToolMetadata = {
getDynamicText: (params, state) => {
const blockId = params?.blockId || params?.block_id
if (blockId && typeof blockId === 'string') {
const name = resolveBlockName(blockId) || blockId
switch (state) {
case ClientToolCallState.success:
return `Executed block ${blockId}`
return `Ran ${name}`
case ClientToolCallState.executing:
return `Running block ${blockId}`
return `Running ${name}`
case ClientToolCallState.generating:
return `Preparing to run block ${blockId}`
return `Preparing to run ${name}`
case ClientToolCallState.pending:
return `Run block ${blockId}?`
return `Run ${name}?`
case ClientToolCallState.error:
return `Failed to run block ${blockId}`
return `Failed to run ${name}`
case ClientToolCallState.rejected:
return `Skipped running block ${blockId}`
return `Skipped running ${name}`
case ClientToolCallState.aborted:
return `Aborted running block ${blockId}`
return `Aborted running ${name}`
case ClientToolCallState.background:
return `Running block ${blockId} in background`
return `Running ${name} in background`
}
}
return undefined
Expand All @@ -1801,12 +1814,12 @@ const META_run_block: ToolMetadata = {
const META_run_from_block: ToolMetadata = {
displayNames: {
[ClientToolCallState.generating]: { text: 'Preparing to run from block', icon: Loader2 },
[ClientToolCallState.pending]: { text: 'Run from this block?', icon: Play },
[ClientToolCallState.pending]: { text: 'Run from block?', icon: Play },
[ClientToolCallState.executing]: { text: 'Running from block', icon: Loader2 },
[ClientToolCallState.success]: { text: 'Executed from block', icon: Play },
[ClientToolCallState.success]: { text: 'Ran from block', icon: Play },
[ClientToolCallState.error]: { text: 'Failed to run from block', icon: XCircle },
[ClientToolCallState.rejected]: { text: 'Skipped run from block', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted run from block', icon: MinusCircle },
[ClientToolCallState.rejected]: { text: 'Skipped running from block', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted running from block', icon: MinusCircle },
[ClientToolCallState.background]: { text: 'Running from block in background', icon: Play },
},
interrupt: {
Expand Down Expand Up @@ -1834,23 +1847,24 @@ const META_run_from_block: ToolMetadata = {
getDynamicText: (params, state) => {
const blockId = params?.startBlockId || params?.start_block_id
if (blockId && typeof blockId === 'string') {
const name = resolveBlockName(blockId) || blockId
switch (state) {
case ClientToolCallState.success:
return `Executed from block ${blockId}`
return `Ran from ${name}`
case ClientToolCallState.executing:
return `Running from block ${blockId}`
return `Running from ${name}`
case ClientToolCallState.generating:
return `Preparing to run from block ${blockId}`
return `Preparing to run from ${name}`
case ClientToolCallState.pending:
return `Run from block ${blockId}?`
return `Run from ${name}?`
case ClientToolCallState.error:
return `Failed to run from block ${blockId}`
return `Failed to run from ${name}`
case ClientToolCallState.rejected:
return `Skipped running from block ${blockId}`
return `Skipped running from ${name}`
case ClientToolCallState.aborted:
return `Aborted running from block ${blockId}`
return `Aborted running from ${name}`
case ClientToolCallState.background:
return `Running from block ${blockId} in background`
return `Running from ${name} in background`
}
}
return undefined
Expand All @@ -1860,12 +1874,12 @@ const META_run_from_block: ToolMetadata = {
const META_run_workflow_until_block: ToolMetadata = {
displayNames: {
[ClientToolCallState.generating]: { text: 'Preparing to run until block', icon: Loader2 },
[ClientToolCallState.pending]: { text: 'Run until this block?', icon: Play },
[ClientToolCallState.pending]: { text: 'Run until block?', icon: Play },
[ClientToolCallState.executing]: { text: 'Running until block', icon: Loader2 },
[ClientToolCallState.success]: { text: 'Executed until block', icon: Play },
[ClientToolCallState.success]: { text: 'Ran until block', icon: Play },
[ClientToolCallState.error]: { text: 'Failed to run until block', icon: XCircle },
[ClientToolCallState.rejected]: { text: 'Skipped run until block', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted run until block', icon: MinusCircle },
[ClientToolCallState.rejected]: { text: 'Skipped running until block', icon: MinusCircle },
[ClientToolCallState.aborted]: { text: 'Aborted running until block', icon: MinusCircle },
[ClientToolCallState.background]: { text: 'Running until block in background', icon: Play },
},
interrupt: {
Expand Down Expand Up @@ -1893,23 +1907,24 @@ const META_run_workflow_until_block: ToolMetadata = {
getDynamicText: (params, state) => {
const blockId = params?.stopAfterBlockId || params?.stop_after_block_id
if (blockId && typeof blockId === 'string') {
const name = resolveBlockName(blockId) || blockId
switch (state) {
case ClientToolCallState.success:
return `Executed until block ${blockId}`
return `Ran until ${name}`
case ClientToolCallState.executing:
return `Running until block ${blockId}`
return `Running until ${name}`
case ClientToolCallState.generating:
return `Preparing to run until block ${blockId}`
return `Preparing to run until ${name}`
case ClientToolCallState.pending:
return `Run until block ${blockId}?`
return `Run until ${name}?`
case ClientToolCallState.error:
return `Failed to run until block ${blockId}`
return `Failed to run until ${name}`
case ClientToolCallState.rejected:
return `Skipped running until block ${blockId}`
return `Skipped running until ${name}`
case ClientToolCallState.aborted:
return `Aborted running until block ${blockId}`
return `Aborted running until ${name}`
case ClientToolCallState.background:
return `Running until block ${blockId} in background`
return `Running until ${name} in background`
}
}
return undefined
Expand Down
Loading