Skip to content

Commit 6330ff8

Browse files
committed
fix(subagents): hide thinking text
1 parent d3dfbd8 commit 6330ff8

6 files changed

Lines changed: 73 additions & 0 deletions

File tree

apps/sim/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ BETTER_AUTH_URL=http://localhost:3000
1717

1818
# NextJS (Required)
1919
NEXT_PUBLIC_APP_URL=http://localhost:3000
20+
# MOTHERSHIP_SUBAGENT_NARRATION=true # Optional: show free-form Workflow/Research/etc. agent narration; defaults to false.
2021
# INTERNAL_API_BASE_URL=http://sim-app.default.svc.cluster.local:3000 # Optional: internal URL for server-side /api self-calls; defaults to NEXT_PUBLIC_APP_URL
2122
# TRUSTED_ORIGINS=https://www.example.com,https://app.example.com # Optional: comma-separated additional public origins to trust for auth (apex+www, alias domains). Merged into Better Auth trustedOrigins.
2223

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it, vi } from 'vitest'
5+
6+
const { mockIsFeatureEnabled, mockIsCustomBlocksEligible } = vi.hoisted(() => ({
7+
mockIsFeatureEnabled: vi.fn(),
8+
mockIsCustomBlocksEligible: vi.fn(),
9+
}))
10+
11+
vi.mock('@/lib/core/config/feature-flags', () => ({
12+
isFeatureEnabled: mockIsFeatureEnabled,
13+
}))
14+
15+
vi.mock('@/lib/workflows/custom-blocks/operations', () => ({
16+
isCustomBlocksEligible: mockIsCustomBlocksEligible,
17+
}))
18+
19+
import {
20+
computeWorkspaceEntitlements,
21+
SUBAGENT_NARRATION_ENTITLEMENT,
22+
} from '@/lib/copilot/entitlements'
23+
24+
describe('computeWorkspaceEntitlements', () => {
25+
it('includes subagent narration only when its feature flag is enabled', async () => {
26+
mockIsCustomBlocksEligible.mockResolvedValue(false)
27+
mockIsFeatureEnabled.mockImplementation(
28+
async (_flag: string, context: { userId?: string }) => context.userId === 'enabled-user'
29+
)
30+
31+
await expect(computeWorkspaceEntitlements('workspace-1', 'disabled-user')).resolves.toEqual([])
32+
await expect(computeWorkspaceEntitlements('workspace-1', 'enabled-user')).resolves.toEqual([
33+
SUBAGENT_NARRATION_ENTITLEMENT,
34+
])
35+
36+
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('mothership-subagent-narration', {
37+
userId: 'enabled-user',
38+
})
39+
})
40+
})

apps/sim/lib/copilot/entitlements.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { getErrorMessage } from '@sim/utils/errors'
33
import { LRUCache } from 'lru-cache'
4+
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
45
import { isCustomBlocksEligible } from '@/lib/workflows/custom-blocks/operations'
56

67
const logger = createLogger('CopilotEntitlements')
@@ -10,6 +11,11 @@ const logger = createLogger('CopilotEntitlements')
1011
* its `core.Entitlement*` constants to gate agent surfaces.
1112
*/
1213
export const CUSTOM_BLOCKS_ENTITLEMENT = 'custom-blocks'
14+
export const SUBAGENT_NARRATION_ENTITLEMENT = 'mothership-subagent-narration'
15+
16+
function isSubagentNarrationEnabled(_workspaceId: string, userId?: string): Promise<boolean> {
17+
return isFeatureEnabled('mothership-subagent-narration', { userId })
18+
}
1319

1420
/**
1521
* Workspace entitlements — plan/flag-gated org capabilities sent to the
@@ -33,6 +39,7 @@ const ENTITLEMENT_EVALUATORS: Record<
3339
(workspaceId: string, userId?: string) => Promise<boolean>
3440
> = {
3541
[CUSTOM_BLOCKS_ENTITLEMENT]: isCustomBlocksEligible,
42+
[SUBAGENT_NARRATION_ENTITLEMENT]: isSubagentNarrationEnabled,
3643
}
3744

3845
const entitlementsCache = new LRUCache<string, Promise<string[]>>({

apps/sim/lib/core/config/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ export const env = createEnv({
451451
DISABLE_INVITATIONS: z.boolean().optional(), // Disable workspace invitations globally (for self-hosted deployments)
452452
DISABLE_PUBLIC_API: z.boolean().optional(), // Disable public API access globally (for self-hosted deployments)
453453
MOTHERSHIP_BETA_FEATURES: z.boolean().optional(), // Enable beta Mothership planning/changelog artifact surfaces
454+
MOTHERSHIP_SUBAGENT_NARRATION: z.boolean().optional(), // Show and stream subagent narration in Mothership chat (defaults to false)
454455

455456
// Development Tools
456457
REACT_GRAB_ENABLED: z.boolean().optional(), // Enable React Grab for UI element debugging in Cursor/AI agents (dev only)

apps/sim/lib/core/config/feature-flags.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const { mockFetch, mockIsPlatformAdmin, envRef, flagRef } = vi.hoisted(() => ({
1212
APPCONFIG_ENVIRONMENT: 'staging' as string | undefined,
1313
FORKING_ENABLED: undefined as boolean | undefined,
1414
DEPLOY_AS_BLOCK: undefined as boolean | undefined,
15+
MOTHERSHIP_SUBAGENT_NARRATION: undefined as boolean | undefined,
1516
},
1617
flagRef: { isAppConfigEnabled: false },
1718
}))
@@ -63,6 +64,7 @@ describe('getFeatureFlags', () => {
6364
const flags = await getFeatureFlags()
6465
// All registered flags should be present, disabled (env vars unset in test env)
6566
expect(flags['mothership-beta']).toEqual({ enabled: false })
67+
expect(flags['mothership-subagent-narration']).toEqual({ enabled: false })
6668
expect(flags['pii-redaction']).toEqual({ enabled: false })
6769
expect(flags['pii-granular-redaction']).toEqual({ enabled: false })
6870
expect(flags['trigger-eu-region']).toEqual({ enabled: false })
@@ -110,6 +112,7 @@ describe('isFeatureEnabled', () => {
110112
flagRef.isAppConfigEnabled = false
111113
envRef.FORKING_ENABLED = undefined
112114
envRef.DEPLOY_AS_BLOCK = undefined
115+
envRef.MOTHERSHIP_SUBAGENT_NARRATION = undefined
113116
})
114117

115118
describe('workspace-forking flag', () => {
@@ -148,6 +151,21 @@ describe('isFeatureEnabled', () => {
148151
})
149152
})
150153

154+
describe('mothership-subagent-narration flag', () => {
155+
it('defaults off and uses its fallback only when explicitly enabled', async () => {
156+
expect(await isFeatureEnabled('mothership-subagent-narration', { userId: 'u1' })).toBe(false)
157+
158+
envRef.MOTHERSHIP_SUBAGENT_NARRATION = true
159+
expect(await isFeatureEnabled('mothership-subagent-narration', { userId: 'u1' })).toBe(true)
160+
})
161+
162+
it('supports targeted rollout through AppConfig', async () => {
163+
withAppConfig({ 'mothership-subagent-narration': { userIds: ['u1'] } })
164+
expect(await isFeatureEnabled('mothership-subagent-narration', { userId: 'u1' })).toBe(true)
165+
expect(await isFeatureEnabled('mothership-subagent-narration', { userId: 'u2' })).toBe(false)
166+
})
167+
})
168+
151169
it('returns false for an unknown flag', async () => {
152170
withAppConfig({})
153171
expect(await enabled('missing', { userId: 'u1' })).toBe(false)

apps/sim/lib/core/config/feature-flags.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ const FEATURE_FLAGS = {
6464
'user context — use enabled:true for global rollout rather than per-user targeting.',
6565
fallback: 'MOTHERSHIP_BETA_FEATURES',
6666
},
67+
'mothership-subagent-narration': {
68+
description:
69+
'Stream and render free-form assistant narration from Mothership subagents such as ' +
70+
'Workflow Agent. Disabled by default so only subagent lifecycle and tool activity are shown.',
71+
fallback: 'MOTHERSHIP_SUBAGENT_NARRATION',
72+
},
6773
'table-snapshot-cache': {
6874
description:
6975
'Mount Sim tables into code sandboxes by reference via a version-keyed CSV snapshot in ' +

0 commit comments

Comments
 (0)