Skip to content

Commit 8d2759c

Browse files
committed
fix(mothership): scope tool side-effect resources inside handleResourceSideEffects
1 parent 6bfce16 commit 8d2759c

3 files changed

Lines changed: 36 additions & 29 deletions

File tree

‎apps/sim/lib/mothership/request/tools/executor.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,9 +1040,10 @@ async function executeToolAndReportInner(
10401040
execContext.chatId,
10411041
options?.onEvent,
10421042
() => abortRequested(context, execContext, options),
1043-
execContext.organizationId
1044-
? (toolCall.targetWorkspaceId ?? execContext.workspaceId)
1045-
: undefined,
1043+
{
1044+
organizationId: execContext.organizationId,
1045+
workspaceId: toolCall.targetWorkspaceId ?? execContext.workspaceId,
1046+
},
10461047
execContext.userId
10471048
)
10481049
}

‎apps/sim/lib/mothership/request/tools/resources.test.ts‎

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,31 +97,35 @@ describe('handleResourceSideEffects', () => {
9797
})
9898
}
9999
)
100-
it.each(['workspace-a'])('addresses extracted exports to admitted %s', async (workspaceId) => {
101-
const resource = { type: 'file' as const, id: 'export', title: 'decisions.csv' }
102-
mocks.extractResourcesFromToolResult.mockReturnValue([resource])
103-
const onEvent = vi.fn()
104-
await handleResourceSideEffects(
105-
'run_function',
106-
undefined,
107-
{ success: true, output: {} },
108-
{ success: true, output: {} },
109-
'org-chat',
110-
onEvent,
111-
() => false,
112-
workspaceId
113-
)
114-
expect(mocks.persistChatResources).toHaveBeenCalledWith('org-chat', [
115-
{ ...resource, workspaceId },
116-
])
117-
expect(onEvent).toHaveBeenCalledWith({
118-
type: 'resource',
119-
payload: {
120-
op: 'upsert',
121-
resource: { ...resource, workspaceId },
122-
},
123-
})
124-
})
100+
it.each([
101+
{ chat: 'organization', organizationId: 'org', expected: { workspaceId: 'workspace-a' } },
102+
{ chat: 'workspace', organizationId: undefined, expected: {} },
103+
])(
104+
'addresses extracted exports in a $chat chat like its open tabs',
105+
async ({ organizationId, expected }) => {
106+
const resource = { type: 'file' as const, id: 'export', title: 'decisions.csv' }
107+
mocks.extractResourcesFromToolResult.mockReturnValue([resource])
108+
mocks.persistChatResources.mockClear()
109+
const onEvent = vi.fn()
110+
await handleResourceSideEffects(
111+
'run_function',
112+
undefined,
113+
{ success: true, output: {} },
114+
{ success: true, output: {} },
115+
'chat',
116+
onEvent,
117+
() => false,
118+
{ organizationId, workspaceId: 'workspace-a' }
119+
)
120+
expect(mocks.persistChatResources).toHaveBeenCalledWith('chat', [
121+
{ ...resource, ...expected },
122+
])
123+
expect(onEvent).toHaveBeenCalledWith({
124+
type: 'resource',
125+
payload: { op: 'upsert', resource: { ...resource, ...expected } },
126+
})
127+
}
128+
)
125129
})
126130

127131
it('emits authorized Search results beside the persisted address, never inside it', async () => {

‎apps/sim/lib/mothership/request/tools/resources.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ export async function handleResourceSideEffects(
3636
chatId: string,
3737
onEvent: ((event: StreamEvent) => void | Promise<void>) | undefined,
3838
isAborted: () => boolean,
39-
workspaceId?: string,
39+
owner?: { organizationId?: string; workspaceId?: string },
4040
actorUserId?: string
4141
): Promise<void> {
42+
// Only organization chats address a workspace; a workspace chat's resources leave it implicit.
43+
const workspaceId = owner?.organizationId ? owner.workspaceId : undefined
4244
// Cheap early exit so we don't emit a span for tools that can never
4345
// produce resources (most of them). The span only shows up for tools
4446
// that might actually do resource work.

0 commit comments

Comments
 (0)