forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexecutionPolicy.ts
More file actions
147 lines (136 loc) · 5.8 KB
/
Copy pathexecutionPolicy.ts
File metadata and controls
147 lines (136 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Execution-policy guards — Windows port of the macOS agent runtime's
// execution-policy.ts (desktop/macos/agent/src/runtime/execution-policy.ts).
//
// Two concerns live here:
// 1. Provider boundaries — a session is pinned to the credential scope of the
// adapter that first ran it, so a locally-authenticated provider can never
// be silently rerouted to a managed one (or vice versa).
// 2. Leaf-role guards — leaf (delegated/background) agents may not use the
// agent-control tools that spawn or message other agents, so a worker
// cannot recursively fan out. (INV-AGENT leaf-role guard.)
//
// AgentExecutionRole and ProviderBoundary are owned by ./types (the store uses
// them), so we import rather than redefine them.
import {
adapterCredentialScopeFor,
isProductionAdapterId,
type AdapterCredentialScope,
type ProductionAdapterId
} from '../codingAgent/interface'
import type { AgentExecutionRole, ProviderBoundary } from './types'
export type { AgentExecutionRole, ProviderBoundary }
/**
* Agent-control tools a leaf worker is forbidden from calling. A leaf agent is
* a terminal executor; only coordinators may spawn or message other agents.
*/
export const LEAF_AGENT_CONTROL_TOOLS = new Set([
'send_agent_message',
'spawn_background_agent',
'spawn_agent',
'run_agent_and_wait'
])
export function providerBoundaryForAdapter(adapterId: string): ProviderBoundary {
// pi-mono is now a registered managed_cloud production adapter (PR-D added its
// ADAPTER_CAPABILITY_MATRIX entry), so `isProductionAdapterId` + credentialScope
// handle it — no special-case set is needed. Non-production (test/dev) adapters
// pin to their own local boundary.
if (isProductionAdapterId(adapterId)) {
return adapterCredentialScopeFor(adapterId) === 'managed_cloud'
? 'managed_cloud'
: `local_user:${adapterId}`
}
return `local_user:${adapterId}`
}
export function credentialScopeForBoundary(boundary: ProviderBoundary): AdapterCredentialScope {
return boundary === 'managed_cloud' ? 'managed_cloud' : 'local_user'
}
export function resolveAdapterWithinBoundary(input: {
providerBoundary: ProviderBoundary
defaultAdapterId: string
requestedAdapterId?: string
}): string {
const requestedAdapterId = input.requestedAdapterId ?? input.defaultAdapterId
if (!isProductionAdapterId(input.defaultAdapterId)) {
// Test/development adapters are deliberately outside the production
// registry. They may only keep their current adapter identity.
if (requestedAdapterId !== input.defaultAdapterId) {
throw new Error(`Adapter ${requestedAdapterId} is outside the owning execution boundary.`)
}
return requestedAdapterId
}
if (!isProductionAdapterId(requestedAdapterId)) {
throw new Error(`Unknown production adapter: ${requestedAdapterId}`)
}
if (requestedAdapterId === 'acp' && input.providerBoundary !== 'local_user:acp') {
throw new Error('Local Claude is available only when the User Claude mode is selected.')
}
if (input.providerBoundary === 'managed_cloud') {
if (adapterCredentialScopeFor(requestedAdapterId) !== 'managed_cloud') {
throw new Error('Managed Omi agents can only use Omi cloud routing.')
}
return requestedAdapterId
}
const pinnedAdapterId = input.providerBoundary.slice('local_user:'.length)
if (requestedAdapterId !== pinnedAdapterId) {
if (requestedAdapterId === 'acp') {
throw new Error('Local Claude is available only when the User Claude mode is selected.')
}
throw new Error(`Local provider mode is pinned to ${pinnedAdapterId}.`)
}
return requestedAdapterId
}
export function assertProductionAdapterScopeDeclared(adapterId: ProductionAdapterId): void {
const scope = adapterCredentialScopeFor(adapterId)
if (scope !== 'managed_cloud' && scope !== 'local_user') {
throw new Error(`Production adapter ${adapterId} is missing credentialScope`)
}
}
export function executionRoleAllowsTool(role: AgentExecutionRole, toolName: string): boolean {
return role !== 'leaf' || !LEAF_AGENT_CONTROL_TOOLS.has(toolName)
}
/**
* INV-AGENT leaf-role guard, enforcement point #1: a leaf worker may not call
* any of LEAF_AGENT_CONTROL_TOOLS.
*
* This is called from the control-tool dispatch boundary (./controlTools
* `handleAgentControlToolCall`) on EVERY tool call, mirroring macOS
* control-tools.ts:561-570. It is the guard that actually stops a background
* agent from recursively spawning or messaging other agents — the
* `executionRoleAllowsTool` predicate alone enforces nothing.
*/
export function assertLeafControlToolsAllowed(
context: { executionRole?: AgentExecutionRole },
name: string
): void {
if (!LEAF_AGENT_CONTROL_TOOLS.has(name)) return
if (!executionRoleAllowsTool(context.executionRole ?? 'coordinator', name)) {
throw new Error(
name === 'send_agent_message'
? 'Leaf workers cannot continue agent sessions.'
: 'Background agents are leaf workers and cannot start additional agents.'
)
}
}
/**
* INV-AGENT leaf-role guard, enforcement point #2: the spawn-specific check the
* three spawning tools run before parsing input. `canSpawnAgents` is the
* deprecated compatibility flag for older direct callers.
*/
export function assertAgentSpawningAllowed(context: {
executionRole?: AgentExecutionRole
canSpawnAgents?: boolean
}): void {
if (context.executionRole === 'leaf' || context.canSpawnAgents === false) {
throw new Error('Background agents are leaf workers and cannot start additional agents.')
}
}
export function executionRoleForSurface(input: {
surfaceKind: string
externalRefKind?: string | null
}): AgentExecutionRole {
return input.surfaceKind === 'delegated_agent' ||
input.surfaceKind === 'background_agent' ||
(input.surfaceKind === 'floating_bar' && input.externalRefKind === 'pill')
? 'leaf'
: 'coordinator'
}