Skip to content

feat(agent): allow variable tool permission modes - #7538

Draft
j15z wants to merge 5 commits into
stagingfrom
codex/agent-tool-permission-mode
Draft

feat(agent): allow variable tool permission modes#7538
j15z wants to merge 5 commits into
stagingfrom
codex/agent-tool-permission-mode

Conversation

@j15z

@j15z j15z commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Let each agent tool's Permission Mode use a fixed selector or a variable such as <start.toolMode>. Resolve variables before tool filtering and fail invalid modes before calling the provider.

  • Put Permission Mode in the expanded tool parameters with the canonical arrow toggle. Preserve the selected mode and both inputs through collaborative editing, API/CLI edits, export, and workflow search.

  • Gate the editor and workflow writes behind a flag that defaults off, including imports and dry runs. Execution continues honoring previously configured variable permissions if the flag is turned off.

  • Preserve permission modes when API tool arrays change, compare search-replacement values independent of object key order, and report interrupted CLI responses with guidance for uncertain writes.

  • Show existing variable settings read-only when the flag is off and preflight browser imports before creating workflows or folders.

Companion: simstudioai/mothership#488

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • 873 application tests passed across 13 files; all 384 realtime tests passed. Coverage includes invalid values, secret provenance, disabled MCP discovery, repeated tools, removal/reordering, 100-tool arrays, import preflight, and feature-flag guards.
  • Chrome verified fixed/variable switching, dynamic Start inputs, Auto/Force/None execution, empty and mixed tool lists, reload, search replacement, duplicate/export/import, and flag-off execution and authoring behavior. Copilot changed a permission to variable None; a second Chrome tab received it and execution made zero tool calls. Copilot then restored the fixed selector. Locked-workflow permission controls were disabled.
  • Ten real CLI commands against a synthetic fault server covered HTTP errors, timeout, dropped connections, truncated responses, and read-back after uncertain writes. No mutation was automatically retried.
  • Full CLI suite: 990 passed, one skipped, two failures in unchanged update-check process tests because Node emits an experimental proxy warning where those tests require empty stderr. The changed HTTP-client tests pass.
  • Sim, realtime, and CLI type checks; full repository lint; all 46 audits; API validation; block-registry and docs-manifest checks passed.
  • Live authenticated CLI/API and cron checks remain pending. Browser collaboration, cancellation, and network-failure coverage is incomplete. Full production build was not rerun.

Review focus: retaining each tool's permission after array edits, keeping disabled tools out of discovery/execution, and blocking new variable authoring while honoring existing configurations. Browser import preflight prevents known disabled-feature imports from creating resources; the existing multi-request importer is not transactional for arbitrary network failures.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

No screenshots or videos attached.

@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Sep 9, 2026 9:56pm UTC

Request Review

@j15z

j15z commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile

@j15z

j15z commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@j15z I have started the AI code review. It will take a few minutes to complete.

@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds variable-backed Agent tool permission modes, resolves them before provider execution, preserves them across workflow editing and serialization, and introduces a global feature flag intended to gate authoring and persistence.

  • Adds fixed/variable permission-mode controls and disabled-tool presentation to the workflow editor.
  • Resolves auto, force, and none before tool filtering and provider requests.
  • Extends API, CLI, import, search, sanitization, and persistence representations with usageControlExpression.
  • Adds feature-gated validation to application-level workflow write paths, but leaves the independent realtime persistence path unguarded.
  • Introduces two repository-rule violations in the new picker component.

Confidence Score: 4/5

The PR is not safe to merge until variable permission modes are rejected at the realtime persistence boundary and the explicit component rules are satisfied.

Application-level saves enforce the new global flag, but realtime state replacement independently writes the gated fields without validation, allowing disabled configurations to persist; the new picker also violates two mandatory repository UI-structure requirements.

Files Needing Attention: apps/sim/lib/workflows/tool-input/usage-control.server.ts, apps/realtime/src/database/operations.ts, apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/components/tools/usage-control.tsx

Important Files Changed

Filename Overview
apps/sim/lib/workflows/tool-input/usage-control.server.ts Adds the global variable-mode write assertion, but the assertion is not shared with realtime workflow persistence.
apps/realtime/src/database/operations.ts The existing realtime replacement sink remains able to persist mode-bearing block state without the newly introduced feature gate.
apps/sim/executor/handlers/agent/agent-handler.ts Resolves active tool permission expressions before filtering and provider request construction.
apps/sim/lib/workflows/tool-input/usage-control.ts Defines indexed canonical-mode keys and normalizes active permission values.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/components/tools/usage-control.tsx Adds the fixed/variable permission-mode editor but violates component-configuration and canonical picker rules.
apps/sim/lib/workflows/editing/builders.ts Preserves expressions and reconstructs indexed canonical modes while normalizing workflow edits.
apps/sim/lib/api/contracts/v2/workflows.ts Extends all Agent tool contract variants with a bounded permission-mode expression.
apps/sim/lib/workflows/search-replace/indexer.ts Indexes the permission expression only when its advanced canonical mode is active.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Editor[Workflow editor] --> Queue[Realtime operation queue]
  Queue --> Realtime[Realtime replace-state handler]
  Realtime -->|Direct write lacks new gate| DB[(Workflow blocks)]
  API[API / CLI / Copilot edits] --> AppGate[Agent tool permission-mode flag assertion]
  Import[Workflow import] --> AppGate
  AppGate --> Save[Normalized workflow save]
  Save --> DB
  DB --> Executor[Agent executor]
  Executor --> Resolve[Resolve variable permission mode]
  Resolve --> Filter[Remove tools resolving to none]
  Filter --> Provider[Provider request]
Loading

Reviews (1): Last reviewed commit: "fix(agent): gate variable permission mod..." | Re-trigger Greptile

Comment on lines +8 to +29
export async function assertAgentToolPermissionModeEnabled(
blocks: Iterable<Pick<BlockState, 'type' | 'subBlocks' | 'data'>>
): Promise<void> {
for (const block of blocks) {
if (block.type !== 'agent') continue
const tools = block.subBlocks?.tools?.value
if (!Array.isArray(tools)) continue

const hasVariableMode = tools.some(
(tool, index) =>
getAgentToolUsageControlMode(index, block.data?.canonicalModes) === 'advanced' ||
(isRecordLike(tool) && tool.usageControlExpression !== undefined)
)
if (!hasVariableMode) continue

if (!(await isFeatureEnabled('agent-tool-permission-mode'))) {
throw new OrchestrationError(
'validation',
'Variable agent tool permission modes are disabled'
)
}
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Realtime Writes Bypass Gate

This assertion protects the Sim application's workflow-save wrappers, but realtime replace-state writes the same block data and subBlocks directly without applying it. A client can therefore persist usageControlExpression and advanced canonical modes through collaboration while the global flag is disabled. Enforce the same validation at the realtime persistence boundary or move it into a shared boundary used by both services.

Knowledge Base Used:

Comment on lines +20 to +36
const MODE_OPTIONS = [
{
value: 'auto',
label: 'Auto',
suffixElement: <span className='text-[var(--text-tertiary)]'>(model decides)</span>,
},
{
value: 'force',
label: 'Force',
suffixElement: <span className='text-[var(--text-tertiary)]'>(always use)</span>,
},
{
value: 'none',
label: 'None',
suffixElement: <span className='text-[var(--text-tertiary)]'>(disable tool)</span>,
},
] as const

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Component Configuration Is Inline

MODE_OPTIONS defines component properties directly in the rendered component module. This violates the repository directive that component properties must live in a dedicated .ts configuration file while rendered components remain in their component files. This repository requirement must be satisfied before merging.

Rule Used: When defining properties for components, use a ded... (source)

Learned From
simstudioai/sim#367

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +72 to +87
<Combobox
options={MODE_OPTIONS.map((option) => ({
...option,
disabled: option.value === 'force' && !supportsForce,
suffixElement:
option.value === 'force' && !supportsForce ? (
<span className='text-[var(--text-tertiary)]'>(not supported by model)</span>
) : (
option.suffixElement
),
onSelect: () => onFixedChange(option.value),
}))}
value={tool.usageControl ?? 'auto'}
disabled={disabled}
aria-label='Permission Mode'
/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Legacy Picker Used

The new fixed permission-mode picker uses the legacy Combobox. This violates the repository directive to use the chip-family replacement—ChipCombobox, ChipSelect, or ChipDropdown—for new pickers. This repository requirement must be satisfied before merging.

Context Used: EMCN component library patterns with CVA (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@j15z
j15z force-pushed the codex/agent-tool-permission-mode branch from 11c3d58 to 818dca4 Compare September 6, 2026 00:21
@j15z
j15z changed the base branch from codex/canonical-tool-mode-base to staging September 6, 2026 00:22
@j15z
j15z force-pushed the codex/agent-tool-permission-mode branch from 818dca4 to 41af1d3 Compare September 7, 2026 19:00
@j15z
j15z force-pushed the codex/agent-tool-permission-mode branch from 41af1d3 to 661f655 Compare September 9, 2026 20:30
@github-actions github-actions Bot added the requires-mothership-merge Has a companion PR on the mothership/copilot side — merge in lockstep label Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

⚠️ Cross-repo companion check

One or more companion PRs aren't merged into staging yet. Merging this without them will leave copilot and sim out of sync — merge them in lockstep.

  • simstudioai/mothership#488OPEN, not merged (targets staging) — feat(workflow): document variable agent tool permissions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

requires-mothership-merge Has a companion PR on the mothership/copilot side — merge in lockstep

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant