Skip to content

Commit 0c4e959

Browse files
fix(custom-blocks): correlate agent-tool runs to the real invoking execution
1 parent 1923fe7 commit 0c4e959

3 files changed

Lines changed: 49 additions & 5 deletions

File tree

apps/sim/executor/handlers/workflow/custom-block-tool-runner.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,25 @@ describe('runCustomBlockTool', () => {
107107
expect(mockExecute).not.toHaveBeenCalled()
108108
})
109109
})
110+
111+
describe('buildCustomBlockExecutionContext invoker identity', () => {
112+
it("adopts the invoking run's ids so correlation names a real execution", () => {
113+
const ctx = buildCustomBlockExecutionContext({
114+
workspaceId: 'ws-1',
115+
executionId: 'agent-execution-id',
116+
requestId: 'agent-request-id',
117+
})
118+
119+
expect(ctx.executionId).toBe('agent-execution-id')
120+
expect(ctx.metadata.executionId).toBe('agent-execution-id')
121+
expect(ctx.metadata.requestId).toBe('agent-request-id')
122+
})
123+
124+
it('falls back to generated ids when the caller supplies none', () => {
125+
const ctx = buildCustomBlockExecutionContext({ workspaceId: 'ws-1' })
126+
127+
expect(ctx.executionId).toBeTruthy()
128+
expect(ctx.metadata.requestId).toBeTruthy()
129+
expect(ctx.executionId).not.toBe(ctx.metadata.requestId)
130+
})
131+
})

apps/sim/executor/handlers/workflow/custom-block-tool-runner.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ interface CustomBlockExecutorContext {
1717
callChain?: string[]
1818
isDeployedContext?: boolean
1919
billingAttribution?: BillingAttributionSnapshot
20+
/**
21+
* The INVOKING agent run's execution id. Server-set, never model-supplied.
22+
* Without it the child's correlation would name an id no log row ever has, so
23+
* a publisher could not trace the run back to the consumer execution — and the
24+
* cancellation bridge would subscribe to an id nothing ever cancels.
25+
*/
26+
executionId?: string
27+
/** The invoking run's request id, so both sides share one trace identifier. */
28+
requestId?: string
2029
}
2130

2231
interface CustomBlockToolParams {
@@ -29,8 +38,9 @@ interface CustomBlockToolParams {
2938

3039
/**
3140
* Build a minimal top-level `ExecutionContext` for running a custom block as an
32-
* agent tool. Every value comes from the server-set `_context` (LLM-proof) plus a
33-
* fresh executionId. `WorkflowBlockHandler`'s custom-block path re-derives owner
41+
* agent tool. Every value comes from the server-set `_context` (LLM-proof),
42+
* including the invoking run's execution and request ids so the child's log
43+
* correlation names a real execution. `WorkflowBlockHandler`'s path re-derives owner
3444
* identity, env, and billing from `getCustomBlockAuthority`, so this only needs the
3545
* fields that path reads — `workspaceId` (org-scopes the authority lookup),
3646
* `metadata` (read unconditionally at `executeCore`), and `callChain` (recursion
@@ -40,7 +50,9 @@ interface CustomBlockToolParams {
4050
export function buildCustomBlockExecutionContext(
4151
context: CustomBlockExecutorContext
4252
): ExecutionContext {
43-
const executionId = generateId()
53+
// Prefer the invoking agent run's ids so correlation and cancellation both
54+
// point at a real execution; fall back only when a caller could not supply them.
55+
const executionId = context.executionId ?? generateId()
4456
return {
4557
workflowId: context.workflowId ?? 'custom-block-tool',
4658
workspaceId: context.workspaceId,
@@ -61,7 +73,7 @@ export function buildCustomBlockExecutionContext(
6173
// custom-block path; `duration` is the sole required field on the metadata type.
6274
metadata: {
6375
duration: 0,
64-
requestId: generateId(),
76+
requestId: context.requestId ?? generateId(),
6577
executionId,
6678
workflowId: context.workflowId,
6779
workspaceId: context.workspaceId,

apps/sim/tools/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,17 @@ export async function executeTool(
12781278
const { runCustomBlockTool } = await import(
12791279
'@/executor/handlers/workflow/custom-block-tool-runner'
12801280
)
1281-
const result = await runCustomBlockTool(contextParams)
1281+
// Forward the INVOKING run's identifiers so the child's log correlation
1282+
// names a real execution instead of a freshly-minted phantom id. Taken
1283+
// from the server-resolved scope, never from model-supplied params.
1284+
const result = await runCustomBlockTool({
1285+
...contextParams,
1286+
_context: {
1287+
...(contextParams._context as Record<string, unknown> | undefined),
1288+
...(scope.executionId ? { executionId: scope.executionId } : {}),
1289+
requestId,
1290+
},
1291+
})
12821292
const endTime = new Date()
12831293
return {
12841294
...result,

0 commit comments

Comments
 (0)