실행 정책¶
ExecutionPolicy는 신뢰된 로컬 side-effect gate입니다.
planning이 관련 mutation을 찾아냈다고 해서 그 mutation이 허가된 것은 아닙니다.
기본 동작¶
기본 policy는 remote capability에 대해 보수적으로 동작합니다:
- 일반 local/manual contract는 실행할 수 있습니다.
- 알려진 OpenAPI mutation은 명시적으로 활성화하지 않으면 차단됩니다.
- destructive operation은 명시적으로 활성화하지 않으면 차단됩니다.
- 분류되지 않은 remote MCP operation은 명시적으로 활성화하지 않으면 차단됩니다.
로컬 authority 설정¶
from schemarouter import ExecutionPolicy, SchemaRouter
router = SchemaRouter(
policy=ExecutionPolicy(
allow_mutations=True,
allow_destructive=False,
allow_unclassified_remote=False,
)
)
이 policy는 신뢰된 application code만 구성해야 합니다.
Operation-scoped rule¶
category-wide switch가 애플리케이션에 필요한 것보다 넓은 authority를 부여한다면 PolicyRule을 사용합니다. rule은 선언 순서대로 평가되며 첫 번째 match가 적용됩니다.
from schemarouter import ExecutionPolicy, PolicyRule, SchemaRouter
router = SchemaRouter(
policy=ExecutionPolicy(
rules=(
PolicyRule(
name="allow-job-create",
operation="jobs.create",
effect="allow",
),
PolicyRule(
name="protect-delete",
operation="jobs.delete*",
effect="deny",
),
PolicyRule(
name="review-refunds",
operation="payments.refund",
effect="require_approval",
),
),
),
approval_callback=approve,
)
operation string은 shell-style wildcard로 tool.endpoint와 match합니다. optional remote, read_only, destructive, unclassified predicate로 rule 범위를 더 좁힐 수 있습니다. unclassified=True는 side-effect classification이 unknown인 endpoint를 명시적으로 match하며 read_only=None은 그 의미를 겸하지 않고 기본 wildcard로 유지됩니다.
scoped allow rule은 해당 operation에만 적용되는 trusted local authority입니다. scoped deny rule은 globally enabled category의 범위를 좁힐 수 있습니다. require_approval은 authority grant가 아니라 추가 gate입니다. 호출은 먼저 해당 allow_mutations, allow_destructive, allow_unclassified_remote category guard 또는 명시적 scoped allow rule을 만족해야 하며, 그 다음 trusted approval callback이 이미 authorize된 호출의 진행 여부를 결정합니다.
어떤 rule도 match하지 않으면 기존 allow_mutations, allow_destructive, allow_unclassified_remote 동작을 그대로 유지합니다.
호출별 approval¶
policy permission과 human/application approval은 서로 별도의 gate입니다.
from schemarouter import ExecutionPolicy, SchemaRouter
async def approve(tool, endpoint, call) -> bool:
return await my_approval_service.check(
tool=tool.key,
endpoint=endpoint.name,
)
router = SchemaRouter(
policy=ExecutionPolicy(
allow_mutations=True,
approval_mode="non_read_only",
),
approval_callback=approve,
)
approval_mode는 다음 값을 받습니다:
never— 호출별 callback 없음, 기본값non_read_only— mutating/unclassified operation에 approval 적용all— 모든 호출 전에 approval 적용
approval이 필요한데 callback이 없으면 호출은 fail-closed됩니다. callback exception도 fail-closed되며 literal boolean True만 호출을 승인합니다. async approval은 run의 남은 elapsed-time budget으로 제한됩니다.
callback은 trusted local code에만 존재합니다. serializable planner input이 아니며 remote metadata나 model이 만들 수 없습니다.
Run별 execution budget¶
from schemarouter import ExecutionBudget, RunConfig
config = RunConfig(
budget=ExecutionBudget(
max_tool_calls=4,
max_attempts=6,
max_remote_attempts=4,
max_elapsed_seconds=15,
max_cost_units=3.0,
per_tool_calls={"materials": 2},
cost_units={
"materials.search": 0.5,
"papers.search": 1.0,
"*": 0.25,
},
)
)
results = await router.ainvoke(request, config=config)
예산 계산 규칙은 결정적입니다:
- logical tool call은 planned call마다 한 번 계산
- retry를 포함한 모든 실제 invoker attempt를 계산
- remote attempt는 별도로 계산
- cost unit은 attempt마다 부과
- operation-specific cost가 tool-specific cost보다 우선하며, tool-specific cost는
"*"보다 우선 - 하나의 plan에 포함된 모든 call이 동일 budget state를 공유
- wall-clock budget이 만료되면 async approval callback, execution hook, invocation, retry backoff를 중단하거나 제한
- synchronous approval/hook은 preempt할 수 없지만 반환 직후 elapsed time을 검사
batch API는 각 input invocation을 자체 budget을 가진 별도 run으로 취급합니다.
budget은 billing이 아니라 local enforcement입니다. cost unit은 애플리케이션이 정의하는 weight입니다.
Retry 상호작용¶
read-only retry가 기본값입니다. 호출을 retry하면 각 retry는 network/tool invocation 전에 attempt, remote, cost budget을 소비합니다.
budget 거부는 retry하지 않습니다.
Remote metadata가 권한을 부여할 수 없는 이유¶
remote server는 자신의 description과 annotation을 제어합니다. 이 field가 local execution authority를 설정하도록 허용하면 capability provider가 자기 자신에게 권한을 부여할 수 있습니다.
SchemaRouter는 일반 remote metadata는 descriptive하게 유지하고 local policy를 authority로 유지합니다.
policy가 사용하는 local/remote classification은 model-visible metadata flag가 아니라 fingerprinted ToolSpec.remote contract입니다. built-in remote adapter가 import 중 해당 field를 local에서 설정합니다.
Runtime approval과 documentation proposal approval¶
documentation-derived tool에는 서로 분리된 gate가 있습니다:
grounded proposal
-> explicit approve_proposal()
-> registered/bound tool
-> ExecutionPolicy
-> optional per-call approval
-> execution budget
-> execute
proposal approval은 추론된 contract가 registry에 들어갈 수 있는지를 결정합니다. runtime approval은 현재 이 특정 호출을 실행할 수 있는지를 결정합니다.
파괴적 작업¶
adapter가 분류할 수 있는 DELETE 계열 operation은 destructive로 표시됩니다. 호스트 애플리케이션에 적절한 권한 부여, 감사, 확인 및 롤백 절차가 갖춰져 있을 때만 allow_destructive=True를 설정합니다.