Skip to content

Commit 3d8d9ac

Browse files
committed
feat(permission-groups): add agent default
1 parent 6df74d6 commit 3d8d9ac

26 files changed

Lines changed: 399 additions & 56 deletions

File tree

‎.agents/skills/ship/SKILL.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ When the user runs `/ship`:
7777
}
7878
# Runs every audit CI runs, concurrently, and replays the output of any that fail.
7979
# The audit list is derived in scripts/run-audits.ts — do not hand-list audits here.
80+
# Run the current "Lint workflows" block from .github/workflows/checks.yml locally too,
81+
# using its pinned actionlint version and checksum in a temporary directory. Preserve
82+
# its -shellcheck= -pyflakes= flags; lint all workflows and abort ship if it fails.
8083
bun run check:audits || { echo "❌ audit(s) failed — do not ship"; exit 1; }
8184
bun run type-check || { echo "❌ type-check failed — do not ship"; exit 1; }
8285
# CI's "Verify docs manifest is in sync" step is not a `check:*` script, so the runner above

‎apps/docs/content/docs/cli/permission-groups.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Create Permission Group (OAuth login or personal API key required)
119119
| `--organization <value>` | Yes | Organization identifier. |
120120
| `--name <value>` | Yes | Group name, unique within the organization. |
121121
| `--description <value>` | No | Optional group description. |
122-
| `--config <json\|@file>` | No | Permission restrictions to set. Omitted keys use the default permission configuration. (JSON, or @path / @- to read a file or stdin). |
122+
| `--config <json\|@file>` | No | Group settings to set. Omitted keys use the default permission configuration. (JSON, or @path / @- to read a file or stdin). |
123123
| `--default` | No | Whether the group is the organization default. Only one group can be the default. |
124124
| `--no-default` | No | Send --default as false. |
125125
| `--workspace-ids <json\|@file>` | No | Workspace IDs targeted by a non-default group. Required when creating a non-default group; omit for a default group. (JSON, or @path / @- to read a file or stdin). |
@@ -232,7 +232,7 @@ Update Permission Group (OAuth login or personal API key required)
232232
| `--organization <value>` | Yes | Organization identifier. |
233233
| `--name <value>` | No | Group name, unique within the organization. |
234234
| `--description <value>` | No | Group description. Null or an empty string clears it; omission leaves it unchanged. (--description null sends the word, not JSON null). |
235-
| `--config <json\|@file>` | No | Patch of permission restrictions. Omitted keys remain unchanged; each supplied array replaces that entire list. (JSON, or @path / @- to read a file or stdin). |
235+
| `--config <json\|@file>` | No | Patch of group settings. Omitted keys remain unchanged; each supplied array replaces that entire list. (JSON, or @path / @- to read a file or stdin). |
236236
| `--default` | No | Whether the group is the organization default. Only one group can be the default. |
237237
| `--no-default` | No | Send --default as false. |
238238
| `--workspace-ids <json\|@file>` | No | Workspace identifiers for a non-default group. Required on creation; an empty update makes the group inactive. (JSON, or @path / @- to read a file or stdin). |

‎apps/docs/content/docs/cli/reference.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,7 +3794,7 @@ sim permission-groups create [options]
37943794
| `--organization <value>` | Yes | Organization identifier. |
37953795
| `--name <value>` | Yes | Group name, unique within the organization. |
37963796
| `--description <value>` | No | Optional group description. |
3797-
| `--config <json\|@file>` | No | Permission restrictions to set. Omitted keys use the default permission configuration. (JSON, or @path / @- to read a file or stdin). |
3797+
| `--config <json\|@file>` | No | Group settings to set. Omitted keys use the default permission configuration. (JSON, or @path / @- to read a file or stdin). |
37983798
| `--default` | No | Whether the group is the organization default. Only one group can be the default. |
37993799
| `--no-default` | No | Send --default as false. |
38003800
| `--workspace-ids <json\|@file>` | No | Workspace IDs targeted by a non-default group. Required when creating a non-default group; omit for a default group. (JSON, or @path / @- to read a file or stdin). |
@@ -3907,7 +3907,7 @@ sim permission-groups update <groupId> [options]
39073907
| `--organization <value>` | Yes | Organization identifier. |
39083908
| `--name <value>` | No | Group name, unique within the organization. |
39093909
| `--description <value>` | No | Group description. Null or an empty string clears it; omission leaves it unchanged. (--description null sends the word, not JSON null). |
3910-
| `--config <json\|@file>` | No | Patch of permission restrictions. Omitted keys remain unchanged; each supplied array replaces that entire list. (JSON, or @path / @- to read a file or stdin). |
3910+
| `--config <json\|@file>` | No | Patch of group settings. Omitted keys remain unchanged; each supplied array replaces that entire list. (JSON, or @path / @- to read a file or stdin). |
39113911
| `--default` | No | Whether the group is the organization default. Only one group can be the default. |
39123912
| `--no-default` | No | Send --default as false. |
39133913
| `--workspace-ids <json\|@file>` | No | Workspace identifiers for a non-default group. Required on creation; an empty update makes the group inactive. (JSON, or @path / @- to read a file or stdin). |

‎apps/docs/openapi-v2-resources.json‎

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5017,7 +5017,7 @@
50175017
"get": {
50185018
"operationId": "getPermissionGroup",
50195019
"summary": "Get Permission Group",
5020-
"description": "Get a permission group and its resolved restrictions. Requires organization admin or owner access and active Access Control. Workspace API keys return `403`; use a personal API key or scoped OAuth token.\n\nOAuth scope: `api:read`.",
5020+
"description": "Get a permission group and its resolved settings. Requires organization admin or owner access and active Access Control. Workspace API keys return `403`; use a personal API key or scoped OAuth token.\n\nOAuth scope: `api:read`.",
50215021
"x-sim-operation": "permission_groups.read",
50225022
"x-oauth-scope": "api:read",
50235023
"tags": ["Permission Groups"],
@@ -16026,6 +16026,20 @@
1602616026
"maxLength": 255
1602716027
},
1602816028
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
16029+
},
16030+
"defaultAgentModel": {
16031+
"default": null,
16032+
"anyOf": [
16033+
{
16034+
"type": "string",
16035+
"minLength": 1,
16036+
"maxLength": 255
16037+
},
16038+
{
16039+
"type": "null"
16040+
}
16041+
],
16042+
"description": "Default model for new Agent blocks. Null uses the platform default."
1602916043
}
1603016044
},
1603116045
"required": [
@@ -16071,10 +16085,11 @@
1607116085
"hideSandboxesTab",
1607216086
"disableOAuthAppAccess",
1607316087
"disableKnowledgeBaseExport",
16074-
"deniedPartialAccessProjectIssues"
16088+
"deniedPartialAccessProjectIssues",
16089+
"defaultAgentModel"
1607516090
],
1607616091
"additionalProperties": false,
16077-
"description": "Resolved restrictions. True disables a boolean capability; null allowlists permit every value and empty allowlists permit none."
16092+
"description": "Resolved group settings. True disables a boolean capability; null allowlists permit every value and empty allowlists permit none. defaultAgentModel selects the default for new Agent blocks without restricting model selection."
1607816093
},
1607916094
"isDefault": {
1608016095
"type": "boolean",
@@ -16123,7 +16138,7 @@
1612316138
],
1612416139
"additionalProperties": false,
1612516140
"title": "Permission group",
16126-
"description": "An organization permission group and its resolved restrictions."
16141+
"description": "An organization permission group and its resolved settings."
1612716142
},
1612816143
"ListPermissionGroupsResponse": {
1612916144
"type": "object",
@@ -16202,7 +16217,8 @@
1620216217
"hideSandboxesTab": false,
1620316218
"disableOAuthAppAccess": false,
1620416219
"disableKnowledgeBaseExport": false,
16205-
"deniedPartialAccessProjectIssues": []
16220+
"deniedPartialAccessProjectIssues": [],
16221+
"defaultAgentModel": null
1620616222
},
1620716223
"isDefault": false,
1620816224
"membershipMode": "inherit",
@@ -16278,7 +16294,8 @@
1627816294
"hideSandboxesTab": false,
1627916295
"disableOAuthAppAccess": false,
1628016296
"disableKnowledgeBaseExport": false,
16281-
"deniedPartialAccessProjectIssues": []
16297+
"deniedPartialAccessProjectIssues": [],
16298+
"defaultAgentModel": null
1628216299
},
1628316300
"isDefault": false,
1628416301
"membershipMode": "inherit",
@@ -16541,10 +16558,23 @@
1654116558
"maxLength": 255
1654216559
},
1654316560
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
16561+
},
16562+
"defaultAgentModel": {
16563+
"anyOf": [
16564+
{
16565+
"type": "string",
16566+
"minLength": 1,
16567+
"maxLength": 255
16568+
},
16569+
{
16570+
"type": "null"
16571+
}
16572+
],
16573+
"description": "Default model for new Agent blocks. Null uses the platform default."
1654416574
}
1654516575
},
1654616576
"additionalProperties": false,
16547-
"description": "Permission restrictions to set. Omitted keys use the default permission configuration."
16577+
"description": "Group settings to set. Omitted keys use the default permission configuration."
1654816578
},
1654916579
"isDefault": {
1655016580
"description": "Whether the group is the organization default. Only one group can be the default.",
@@ -16633,7 +16663,8 @@
1663316663
"hideSandboxesTab": false,
1663416664
"disableOAuthAppAccess": false,
1663516665
"disableKnowledgeBaseExport": false,
16636-
"deniedPartialAccessProjectIssues": []
16666+
"deniedPartialAccessProjectIssues": [],
16667+
"defaultAgentModel": null
1663716668
},
1663816669
"isDefault": false,
1663916670
"membershipMode": "inherit",
@@ -16707,7 +16738,8 @@
1670716738
"hideSandboxesTab": false,
1670816739
"disableOAuthAppAccess": false,
1670916740
"disableKnowledgeBaseExport": false,
16710-
"deniedPartialAccessProjectIssues": []
16741+
"deniedPartialAccessProjectIssues": [],
16742+
"defaultAgentModel": null
1671116743
},
1671216744
"isDefault": false,
1671316745
"membershipMode": "inherit",
@@ -16977,10 +17009,23 @@
1697717009
"maxLength": 255
1697817010
},
1697917011
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
17012+
},
17013+
"defaultAgentModel": {
17014+
"anyOf": [
17015+
{
17016+
"type": "string",
17017+
"minLength": 1,
17018+
"maxLength": 255
17019+
},
17020+
{
17021+
"type": "null"
17022+
}
17023+
],
17024+
"description": "Default model for new Agent blocks. Null uses the platform default."
1698017025
}
1698117026
},
1698217027
"additionalProperties": false,
16983-
"description": "Patch of permission restrictions. Omitted keys remain unchanged; each supplied array replaces that entire list."
17028+
"description": "Patch of group settings. Omitted keys remain unchanged; each supplied array replaces that entire list."
1698417029
},
1698517030
"isDefault": {
1698617031
"description": "Whether the group is the organization default. Only one group can be the default.",
@@ -18263,6 +18308,20 @@
1826318308
"maxLength": 255
1826418309
},
1826518310
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
18311+
},
18312+
"defaultAgentModel": {
18313+
"default": null,
18314+
"anyOf": [
18315+
{
18316+
"type": "string",
18317+
"minLength": 1,
18318+
"maxLength": 255
18319+
},
18320+
{
18321+
"type": "null"
18322+
}
18323+
],
18324+
"description": "Default model for new Agent blocks. Null uses the platform default."
1826618325
}
1826718326
},
1826818327
"required": [
@@ -18308,15 +18367,16 @@
1830818367
"hideSandboxesTab",
1830918368
"disableOAuthAppAccess",
1831018369
"disableKnowledgeBaseExport",
18311-
"deniedPartialAccessProjectIssues"
18370+
"deniedPartialAccessProjectIssues",
18371+
"defaultAgentModel"
1831218372
],
1831318373
"additionalProperties": false
1831418374
},
1831518375
{
1831618376
"type": "null"
1831718377
}
1831818378
],
18319-
"description": "Effective group restrictions. True disables a boolean capability; null allowlists allow all values and empty allowlists allow none. Null config means no group applies."
18379+
"description": "Effective group settings. True disables a boolean capability; null allowlists allow all values and empty allowlists allow none. Null config means no group applies."
1832018380
},
1832118381
"entitled": {
1832218382
"type": "boolean",

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Combobox, type ComboboxOption, cn } from '@sim/emcn'
33
import { Plus } from '@sim/emcn/icons'
44
import { useReactFlow } from '@xyflow/react'
55
import { useDeploymentShape } from '@/lib/core/config/deployment-shape'
6+
import { resolveAgentDefaultModel } from '@/lib/permission-groups/model-access'
67
import type { SelectorKey } from '@/lib/selectors/manifest'
78
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
89
import { getDependsOnFields } from '@/lib/workflows/subblocks/dependencies'
@@ -21,6 +22,7 @@ import { useDebounce } from '@/hooks/use-debounce'
2122
import { usePermissionConfig } from '@/hooks/use-permission-config'
2223
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
2324
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
25+
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
2426

2527
/**
2628
* Constants for ComboBox component behavior
@@ -106,6 +108,7 @@ export const ComboBox = memo(function ComboBox({
106108
const activeSearchTarget = useActiveSearchTarget()
107109
// Hooks and context
108110
const [storeValue, setStoreValue] = useSubBlockValue<string>(blockId, subBlockId)
111+
const blockType = useWorkflowStore((state) => state.blocks[blockId]?.type)
109112
const accessiblePrefixes = useAccessibleReferencePrefixes(blockId)
110113
const reactFlowInstance = useReactFlow()
111114

@@ -116,7 +119,11 @@ export const ComboBox = memo(function ComboBox({
116119
const value = isPreview ? previewValue : propValue !== undefined ? propValue : storeValue
117120

118121
// Permission-based filtering for model dropdowns
119-
const { isModelUsable, isLoading: isPermissionLoading } = usePermissionConfig()
122+
const {
123+
config: permissionConfig,
124+
isModelUsable,
125+
isLoading: isPermissionLoading,
126+
} = usePermissionConfig()
120127

121128
// Evaluate static options if provided as a function
122129
// Derived option lists read the block's own values (a model's valid reasoning efforts);
@@ -296,9 +303,19 @@ export const ComboBox = memo(function ComboBox({
296303

297304
/**
298305
* Determines the default option value to use.
299-
* Priority: explicit defaultValue > DEFAULT_MODEL for model field > first option
306+
* Priority: group Agent default > explicit defaultValue > DEFAULT_MODEL > first option.
300307
*/
301308
const defaultOptionValue = useMemo(() => {
309+
const agentDefault =
310+
config.id === 'model' && blockType === 'agent'
311+
? resolveAgentDefaultModel(permissionConfig)
312+
: null
313+
if (
314+
agentDefault &&
315+
evaluatedOptions.some((option) => getOptionValue(option) === agentDefault)
316+
) {
317+
return agentDefault
318+
}
302319
if (defaultValue !== undefined) {
303320
// Validate that the default value exists in the available (filtered) options
304321
const defaultInOptions = evaluatedOptions.find((opt) => getOptionValue(opt) === defaultValue)
@@ -330,7 +347,16 @@ export const ComboBox = memo(function ComboBox({
330347
}
331348

332349
return undefined
333-
}, [defaultValue, evaluatedOptions, subBlockId, getOptionValue, config.emptyIsValid])
350+
}, [
351+
defaultValue,
352+
evaluatedOptions,
353+
subBlockId,
354+
getOptionValue,
355+
config.emptyIsValid,
356+
config.id,
357+
blockType,
358+
permissionConfig,
359+
])
334360

335361
/**
336362
* Resolve the user-facing text for the current stored value.

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ const WorkflowContent = React.memo(
898898
*/
899899
const pendingFocusBlockIdRef = useRef<string | null>(null)
900900

901-
const { resolveSeedGate } = useOperationAccess()
901+
const { resolveSeedGate, agentDefaultModel } = useOperationAccess()
902902

903903
const addBlock = useCallback(
904904
(
@@ -933,6 +933,7 @@ const WorkflowContent = React.memo(
933933
extent,
934934
triggerMode,
935935
isSeededValueAllowed: seedGate,
936+
agentDefaultModel,
936937
})
937938

938939
const subBlockValues: Record<string, Record<string, unknown>> = {}
@@ -976,7 +977,13 @@ const WorkflowContent = React.memo(
976977
)
977978
usePanelEditorStore.getState().setCurrentBlockId(id)
978979
},
979-
[collaborativeBatchAddBlocks, setSelectedEdges, setPendingSelection, resolveSeedGate]
980+
[
981+
collaborativeBatchAddBlocks,
982+
setSelectedEdges,
983+
setPendingSelection,
984+
resolveSeedGate,
985+
agentDefaultModel,
986+
]
980987
)
981988

982989
const { activeBlockIds, pendingBlocks, isDebugging, isExecuting } = useExecutionStore(

0 commit comments

Comments
 (0)