diff --git a/packages/paperclip-runner/docs/capability-semantic-tools.md b/packages/paperclip-runner/docs/capability-semantic-tools.md index 8a320f06ab9..9c3af0bbdae 100644 --- a/packages/paperclip-runner/docs/capability-semantic-tools.md +++ b/packages/paperclip-runner/docs/capability-semantic-tools.md @@ -5,13 +5,15 @@ is a frozen set of JSON-schema descriptors — no HTTP method, path, or provider detail. Provider-specific shapes are produced only by *bindings*, so every provider sees the same operation set. -The operation list, placement, required claims, and task-mode policy are -single-sourced from `src/catalog/canonical-operations.ts` -(`CAPABILITY_CANONICAL_OPERATIONS`); this catalog is a projection of it that adds -the scenario presentation (titles, descriptions, input schemas, mock mappings, -and redaction). See [catalog reconciliation](../spec/capability/catalog-reconciliation.md). +Each protocol action is single-sourced in its own module under +`src/protocol-actions/`. That module owns the action's policy metadata, +documentation, examples, and its live and scenario JSON-schema presentations. +`src/catalog/canonical-operations.ts`, `src/semantic-tools/catalog.ts`, and +`src/tools/capability-semantic-tool-catalog.ts` are compatibility projections; +do not add action definitions to them. See +[catalog reconciliation](../spec/capability/catalog-reconciliation.md). -Sources: `src/catalog/canonical-operations.ts`, +Sources: `src/protocol-actions/`, `src/catalog/canonical-operations.ts`, `src/tools/capability-semantic-tool-catalog.ts`, `src/tools/capability-semantic-tool-types.ts`, `src/tools/capability-tool-bindings.ts`, barrel `src/tools/index.ts`. diff --git a/packages/paperclip-runner/src/catalog/canonical-operations.ts b/packages/paperclip-runner/src/catalog/canonical-operations.ts index 74c7e1757f2..67464f25a16 100644 --- a/packages/paperclip-runner/src/catalog/canonical-operations.ts +++ b/packages/paperclip-runner/src/catalog/canonical-operations.ts @@ -1,272 +1,26 @@ -/** - * Canonical semantic-operation registry — the single source of truth. - * - * The runner historically carried two independently hand-maintained semantic - * catalogs: - * - * - `src/tools/` — the rich scenario/eval descriptor (placement, side-effect - * class, idempotency, redaction, mock mapping) consumed by the scenario and - * conformance layers and exported as the package-root default. - * - `src/semantic-tools/` — the live runtime engine (catalog + policy + - * dispatcher) that drives live Codex, the issue-thread projection, and the - * generated provider-neutral contracts. - * - * PAP-17025 froze a machine-readable authority over the union of both surfaces. - * PAP-17039 performs the physical collapse: this module hand-authors the - * 41-operation union exactly once, and **both** catalog modules now derive - * their operation list, placement, required claims, and task-mode policy from - * it. Neither catalog declares an independent operation list or an independent - * claim/mode policy any longer — they only supply per-surface presentation - * (title, description, input/output schema, and the scenario-only mock mapping - * and redaction rules). - * - * Divergences the collapse resolved (see `spec/capability/catalog-reconciliation.md`): - * - * 1. `generic_api_request` now carries a single claim, `test:generic_api_request`. - * 2. Task modes follow one canonical policy: the live runtime exposure policy - * unioned with `skill_test`, so every operation the eval harness must drive - * is drivable while the live runtime keeps its intended per-mode exposure. - * 3. Placement (`always`/`optional`), required claims, and allowed roles are - * single-sourced here; the two catalogs can no longer disagree on them. - * - * The only surviving cross-surface difference is input-schema *shape*: the live - * provider schema threads `idempotencyKey` in-band with provider bounds for the - * model, while the observable scenario runtime threads idempotency out-of-band. - * That is a single reviewed projection of one contract, not two independent - * schemas — recorded as an intentional disposition in the reconciliation ledger. - */ +/** Stable aggregate API over the per-action definitions in `src/protocol-actions/`. */ +import type { CapabilitySideEffectClass, CapabilityToolDisposition, CapabilityOptionalCatalogGroup, CapabilityToolTaskMode, ScenarioChatdempotencyBehavior } from "../tools/capability-semantic-tool-types.js"; +import { PAPERCLIP_PROTOCOL_ACTIONS } from "../protocol-actions/index.js"; -import type { - CapabilitySideEffectClass, - CapabilityToolDisposition, - CapabilityOptionalCatalogGroup, - CapabilityToolTaskMode, - ScenarioChatdempotencyBehavior, -} from "../tools/capability-semantic-tool-types.js"; - -/** Which catalog surface(s) project this operation. */ export type CapabilityCatalogSurface = "scenario" | "live"; - -/** Where an operation is executable today, before real Paperclip binding. */ export type CapabilityRealBindingStatus = "live_codex" | "scenario_mock" | "test_only"; - export interface CapabilityCanonicalOperation { - readonly operationId: string; - /** Catalog surface(s) that project this operation today. */ - readonly surfaces: readonly CapabilityCatalogSurface[]; - readonly placement: CapabilityToolDisposition; - /** Scenario optional-catalog group; `null` for always tools and live-only ops. */ - readonly optionalGroup: CapabilityOptionalCatalogGroup | null; - readonly requiredClaims: readonly string[]; - readonly taskModes: readonly CapabilityToolTaskMode[]; - readonly allowedRoles?: readonly string[]; - readonly sideEffectClass: CapabilitySideEffectClass; - readonly idempotency: ScenarioChatdempotencyBehavior; - /** Live-only exposure flag; kept off the tool surface until explicitly enabled. */ - readonly disabledByDefault: boolean; - readonly realBindingStatus: CapabilityRealBindingStatus; - /** - * No semantic operation is bound to a real Paperclip service yet; the mock is - * the only backend (real-service binding is deliverable G of PAP-17016). - */ - readonly realServiceBinding: "unbound"; - /** Intended PRP evidence family carrying this operation's effect. */ - readonly prpEvidence: string; - /** The formal PRP expressiveness proof is deliverable C; entries stay pending. */ - readonly prpBindingStatus: "audit_pending"; - /** Legacy MCP alias ids folded into this operation, if any. */ - readonly legacyAliases: readonly string[]; - readonly note?: string; + readonly operationId: string; readonly surfaces: readonly CapabilityCatalogSurface[]; + readonly placement: CapabilityToolDisposition; readonly optionalGroup: CapabilityOptionalCatalogGroup | null; + readonly requiredClaims: readonly string[]; readonly taskModes: readonly CapabilityToolTaskMode[]; + readonly allowedRoles?: readonly string[]; readonly sideEffectClass: CapabilitySideEffectClass; + readonly idempotency: ScenarioChatdempotencyBehavior; readonly disabledByDefault: boolean; + readonly realBindingStatus: CapabilityRealBindingStatus; readonly realServiceBinding: "unbound"; + readonly prpEvidence: string; readonly prpBindingStatus: "audit_pending"; + readonly legacyAliases: readonly string[]; readonly note?: string; } -const ALL_MODES: readonly CapabilityToolTaskMode[] = ["standard", "ask", "planning", "skill_test"]; -const WORK_MODES: readonly CapabilityToolTaskMode[] = ["standard", "planning", "skill_test"]; -const STANDARD_MODES: readonly CapabilityToolTaskMode[] = ["standard", "skill_test"]; -const TEST_MODES: readonly CapabilityToolTaskMode[] = ["skill_test"]; - -function prpEvidenceForSideEffect(sideEffectClass: CapabilitySideEffectClass): string { - switch (sideEffectClass) { - case "read": - return "read projection surfaced via a tool-result item event; no control-plane state diff"; - case "task_write": - return "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events"; - case "company_write": - return "semantic-operation item event plus company-entity state diff and audit record"; - case "governance": - return "approval lifecycle plus governed-wait continuation and audit events"; - case "workspace_control": - return "workspace service lifecycle event"; - case "secret_read": - return "redacted tool-result item event; secret value never reaches the wire"; - case "admin": - return "company admin/portability item event plus audit record"; - case "test_escape_hatch": - return "test-only; excluded from product PRP evidence"; - default: - return "audit_pending"; - } -} - -/** Compact authoring row; the exported catalog fills in derived fields. */ -interface Row { - readonly operationId: string; - readonly surfaces: readonly CapabilityCatalogSurface[]; - readonly placement: CapabilityToolDisposition; - readonly optionalGroup?: CapabilityOptionalCatalogGroup; - readonly requiredClaims?: readonly string[]; - readonly taskModes: readonly CapabilityToolTaskMode[]; - readonly allowedRoles?: readonly string[]; - readonly sideEffectClass: CapabilitySideEffectClass; - readonly idempotency: ScenarioChatdempotencyBehavior; - readonly disabledByDefault?: boolean; - readonly realBindingStatus: CapabilityRealBindingStatus; - readonly legacyAliases?: readonly string[]; - readonly note?: string; -} - -const SHARED: readonly CapabilityCatalogSurface[] = ["scenario", "live"]; -const SCENARIO_ONLY: readonly CapabilityCatalogSurface[] = ["scenario"]; -const LIVE_ONLY: readonly CapabilityCatalogSurface[] = ["live"]; - -// --------------------------------------------------------------------------- -// The single canonical operation list. One row per union operation. Task modes -// follow the canonical policy (live runtime exposure policy ∪ `skill_test`); -// scenario-only and live-only operations keep their single existing policy -// because there is no second surface to reconcile against. -// --------------------------------------------------------------------------- - -const ROWS: readonly Row[] = [ - // --- always-present active-task surface --- - { operationId: "get_task_context", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipMe"] }, - { operationId: "get_task_history", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "list_documents", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "read_document", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "list_document_revisions", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "report_progress", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipAddComment"] }, - { operationId: "answer_status_question", surfaces: SHARED, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "write_document", surfaces: SHARED, placement: "always_agent_tool", taskModes: WORK_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "request_human_input", surfaces: SHARED, placement: "always_agent_tool", taskModes: WORK_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "register_deliverable", surfaces: SHARED, placement: "always_agent_tool", taskModes: WORK_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "finish_task", surfaces: SHARED, placement: "always_agent_tool", taskModes: STANDARD_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "block_task", surfaces: SHARED, placement: "always_agent_tool", taskModes: STANDARD_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "request_review", surfaces: SHARED, placement: "always_agent_tool", taskModes: STANDARD_MODES, sideEffectClass: "task_write", idempotency: "required", realBindingStatus: "live_codex" }, - { - operationId: "inspect_operation_result", surfaces: SCENARIO_ONLY, placement: "always_agent_tool", taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", - realBindingStatus: "scenario_mock", - note: "Scenario/eval-only re-read of a prior operation result; the live dispatcher returns results inline.", - }, - - // --- discovery --- - { operationId: "search_tasks", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "discovery", requiredClaims: ["discovery:tasks:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipListIssues"] }, - { operationId: "list_agents", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "discovery", requiredClaims: ["discovery:agents:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipListAgents"] }, - { - operationId: "get_agent", surfaces: LIVE_ONLY, placement: "optional_agent_tool", requiredClaims: ["discovery:agents:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", - realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipGetAgent"], - note: "Live-only single-actor read; the scenario suite covers actor discovery through list_agents.", - }, - { operationId: "list_projects", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "discovery", requiredClaims: ["discovery:projects:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." }, - { operationId: "list_goals", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "discovery", requiredClaims: ["discovery:goals:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." }, - - // --- delegation & dependencies --- - { operationId: "create_task", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "delegation_dependencies", requiredClaims: ["delegation:tasks:create"], taskModes: STANDARD_MODES, sideEffectClass: "company_write", idempotency: "required", realBindingStatus: "live_codex", legacyAliases: ["mcp:paperclipCreateIssue"] }, - { operationId: "set_dependencies", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "delegation_dependencies", requiredClaims: ["dependencies:write"], taskModes: STANDARD_MODES, sideEffectClass: "company_write", idempotency: "required", realBindingStatus: "live_codex" }, - - // --- governance --- - { operationId: "list_approvals", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "governance", requiredClaims: ["governance:approvals:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "request_approval", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "governance", requiredClaims: ["governance:approvals:request"], taskModes: STANDARD_MODES, sideEffectClass: "governance", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "decide_approval", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "governance", requiredClaims: ["governance:approvals:decide"], taskModes: STANDARD_MODES, allowedRoles: ["board", "approver", "security"], sideEffectClass: "governance", idempotency: "required", realBindingStatus: "live_codex" }, - { operationId: "comment_on_approval", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "governance", requiredClaims: ["governance:approvals:comment"], taskModes: ALL_MODES, sideEffectClass: "governance", idempotency: "required", realBindingStatus: "live_codex" }, - { - operationId: "get_approval", surfaces: LIVE_ONLY, placement: "optional_agent_tool", requiredClaims: ["governance:approvals:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", - realBindingStatus: "live_codex", - note: "Live-only single-approval read; the scenario suite covers approvals through list_approvals.", - }, - { - operationId: "get_approval_context", surfaces: LIVE_ONLY, placement: "optional_agent_tool", requiredClaims: ["governance:approvals:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", - realBindingStatus: "live_codex", - note: "Live-only approval-plus-linked-tasks read; no scenario counterpart.", - }, - - // --- workspace runtime --- - { operationId: "get_workspace_runtime", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "workspace_runtime", requiredClaims: ["workspace:read"], taskModes: ALL_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "live_codex" }, - { operationId: "control_workspace_service", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "workspace_runtime", requiredClaims: ["workspace:control"], taskModes: STANDARD_MODES, sideEffectClass: "workspace_control", idempotency: "required", realBindingStatus: "live_codex" }, - - // --- control-plane wake scheduling (live-only) --- - { - operationId: "schedule_wake", surfaces: LIVE_ONLY, placement: "optional_agent_tool", requiredClaims: ["control_plane:wakes"], taskModes: STANDARD_MODES, sideEffectClass: "task_write", idempotency: "required", - realBindingStatus: "live_codex", - note: "Bounded, deterministic mock wake scheduling; requires the control_plane:wakes claim. Live-only continuation primitive.", - }, - - // --- scenario-only optional surfaces (mock extensions, no live binding) --- - { operationId: "list_cases", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "cases", requiredClaims: ["cases:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "upsert_case", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "cases", requiredClaims: ["cases:write"], taskModes: STANDARD_MODES, sideEffectClass: "company_write", idempotency: "required", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "list_routines", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "routines", requiredClaims: ["routines:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "manage_routine", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "routines", requiredClaims: ["routines:write"], taskModes: STANDARD_MODES, sideEffectClass: "admin", idempotency: "required", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "list_company_skills", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "company_skills", requiredClaims: ["company_skills:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "sync_company_skills", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "company_skills", requiredClaims: ["company_skills:write"], taskModes: STANDARD_MODES, sideEffectClass: "admin", idempotency: "required", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "list_secret_metadata", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "secrets", requiredClaims: ["secrets:metadata:read"], taskModes: STANDARD_MODES, sideEffectClass: "read", idempotency: "none", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension; metadata only." }, - { - operationId: "read_secret_value", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "secrets", requiredClaims: ["secrets:values:read"], taskModes: STANDARD_MODES, sideEffectClass: "secret_read", idempotency: "none", - realBindingStatus: "scenario_mock", - note: "Scenario/eval-only mock extension; secret value redacted from every observable sink.", - }, - { operationId: "export_company", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "portability_admin", requiredClaims: ["portability:export"], taskModes: STANDARD_MODES, sideEffectClass: "admin", idempotency: "required", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - { operationId: "administer_company", surfaces: SCENARIO_ONLY, placement: "optional_agent_tool", optionalGroup: "portability_admin", requiredClaims: ["company:admin"], taskModes: STANDARD_MODES, allowedRoles: ["board", "ceo", "admin"], sideEffectClass: "admin", idempotency: "required", realBindingStatus: "scenario_mock", note: "Scenario/eval-only mock extension." }, - - // --- test-only escape hatch (shared, never product coverage) --- - { - operationId: "generic_api_request", surfaces: SHARED, placement: "optional_agent_tool", optionalGroup: "test_escape_hatch", requiredClaims: ["test:generic_api_request"], taskModes: TEST_MODES, sideEffectClass: "test_escape_hatch", idempotency: "required", disabledByDefault: true, - realBindingStatus: "test_only", - note: "Test-only escape hatch; explicitly cannot count as product capability coverage (PAP-17016 deliverable D). Single unified claim test:generic_api_request.", - }, -]; - -function buildOperation(row: Row): CapabilityCanonicalOperation { - return Object.freeze({ - operationId: row.operationId, - surfaces: Object.freeze([...row.surfaces]), - placement: row.placement, - optionalGroup: row.optionalGroup ?? null, - requiredClaims: Object.freeze([...(row.requiredClaims ?? [])]), - taskModes: Object.freeze([...row.taskModes]), - ...(row.allowedRoles === undefined ? {} : { allowedRoles: Object.freeze([...row.allowedRoles]) }), - sideEffectClass: row.sideEffectClass, - idempotency: row.idempotency, - disabledByDefault: row.disabledByDefault ?? false, - realBindingStatus: row.realBindingStatus, - realServiceBinding: "unbound", - prpEvidence: prpEvidenceForSideEffect(row.sideEffectClass), - prpBindingStatus: "audit_pending", - legacyAliases: Object.freeze([...(row.legacyAliases ?? [])]), - ...(row.note === undefined ? {} : { note: row.note }), - }); -} - -/** The single canonical catalog: the union of both surfaces, sorted by id. */ export const CAPABILITY_CANONICAL_OPERATIONS: readonly CapabilityCanonicalOperation[] = Object.freeze( - [...ROWS].map(buildOperation).sort((left, right) => left.operationId.localeCompare(right.operationId)), + PAPERCLIP_PROTOCOL_ACTIONS.map((action) => action.canonical as unknown as CapabilityCanonicalOperation) + .sort((left, right) => left.operationId.localeCompare(right.operationId)), ); - const byId = new Map(CAPABILITY_CANONICAL_OPERATIONS.map((operation) => [operation.operationId, operation])); -if (byId.size !== CAPABILITY_CANONICAL_OPERATIONS.length) { - throw new Error("duplicate canonical semantic operation id"); -} - -export function capabilityCanonicalOperation( - operationId: string, -): CapabilityCanonicalOperation | undefined { - return byId.get(operationId); -} - -/** Canonical operations projected onto one catalog surface, sorted by id. */ -export function capabilityCanonicalOperationsForSurface( - surface: CapabilityCatalogSurface, -): readonly CapabilityCanonicalOperation[] { - return CAPABILITY_CANONICAL_OPERATIONS.filter((operation) => operation.surfaces.includes(surface)); -} - -/** Convenience for docs/generators: the canonical operation-id list, sorted. */ -export function capabilityCanonicalOperationIds(): readonly string[] { - return CAPABILITY_CANONICAL_OPERATIONS.map((operation) => operation.operationId); -} +if (byId.size !== 41) throw new Error(`expected 41 canonical semantic operations, found ${byId.size}`); +export function capabilityCanonicalOperation(operationId: string): CapabilityCanonicalOperation | undefined { return byId.get(operationId); } +export function capabilityCanonicalOperationsForSurface(surface: CapabilityCatalogSurface): readonly CapabilityCanonicalOperation[] { return CAPABILITY_CANONICAL_OPERATIONS.filter((operation) => operation.surfaces.includes(surface)); } +export function capabilityCanonicalOperationIds(): readonly string[] { return CAPABILITY_CANONICAL_OPERATIONS.map((operation) => operation.operationId); } diff --git a/packages/paperclip-runner/src/live/live-session.ts b/packages/paperclip-runner/src/live/live-session.ts index c1e13710a5c..77f2b35c39a 100644 --- a/packages/paperclip-runner/src/live/live-session.ts +++ b/packages/paperclip-runner/src/live/live-session.ts @@ -17,7 +17,7 @@ import type { } from "../mock-core/capability-control-plane-types.js"; import { CapabilityMockControlPlaneAdapter } from "../mock-core/capability-mock-control-plane-adapter.js"; import { CapabilitySemanticDispatcher } from "../semantic-tools/dispatcher.js"; -import { CAPABILITY_DISCOVERY_NAMESPACES, type CapabilityToolExposureMode } from "../semantic-tools/discovery.js"; +import { CAPABILITY_DISCOVERY_GATEWAY_DEFINITIONS, type CapabilityToolExposureMode } from "../semantic-tools/discovery.js"; import type { CapabilitySemanticAuthorizationRecord, CapabilitySemanticScenarioPolicy, @@ -541,15 +541,9 @@ function dynamicToolSpec(definition: CapabilitySemanticToolDefinition): Record[] { - return [{ - name: DISCOVER_TOOL, - description: `Search authorized optional Paperclip capabilities. Namespaces: ${CAPABILITY_DISCOVERY_NAMESPACES.map((item) => `${item.name} (${item.description})`).join("; ")}`, - inputSchema: { type: "object", properties: { query: { type: "string", minLength: 1, maxLength: 500 }, namespace: { type: "string" }, limit: { type: "integer", minimum: 1, maximum: 8 } }, required: ["query"], additionalProperties: false }, - }, { - name: INVOKE_DISCOVERED_TOOL, - description: "Invoke one optional Paperclip operation returned by discover_capabilities. Authority is rechecked at invocation.", - inputSchema: { type: "object", properties: { operationId: { type: "string" }, input: { type: "object", additionalProperties: true } }, required: ["operationId", "input"], additionalProperties: false }, - }]; + return CAPABILITY_DISCOVERY_GATEWAY_DEFINITIONS.map(({ name, description, inputSchema }) => ({ + name, description, inputSchema, + })); } function userInput(message: string): Record { diff --git a/packages/paperclip-runner/src/protocol-actions/administer-company.ts b/packages/paperclip-runner/src/protocol-actions/administer-company.ts new file mode 100644 index 00000000000..51dd987e55c --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/administer-company.ts @@ -0,0 +1,139 @@ +/** Canonical definition and documentation for `administer_company`. */ +export const administerCompanyAction = { + "id": "administer_company", + "canonical": { + "operationId": "administer_company", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "company:admin" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "allowedRoles": [ + "board", + "ceo", + "admin" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Administer Company", + "description": "Administer Company through the Capability portability admin capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "administer_company", + "input": { + "action": "example" + } + }, + "success": { + "ok": true, + "operationId": "administer_company", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 35, + "descriptor": { + "operationId": "administer_company", + "version": 1, + "title": "Administer Company", + "description": "Administer Company through the Capability portability admin capability set.", + "inputSchema": { + "type": "object", + "properties": { + "action": { + "type": "string", + "minLength": 1 + }, + "payload": {} + }, + "required": [ + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "company:admin" + ], + "allowedRoles": [ + "board", + "ceo", + "admin" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company.admin" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts b/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts new file mode 100644 index 00000000000..19d5a769ca1 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts @@ -0,0 +1,219 @@ +/** Canonical definition and documentation for `answer_status_question`. */ +export const answerStatusQuestionAction = { + "id": "answer_status_question", + "canonical": { + "operationId": "answer_status_question", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Answer status question", + "description": "Append the answer to a status-only wake without changing task disposition.", + "note": null + }, + "examples": { + "call": { + "operationId": "answer_status_question", + "input": { + "idempotencyKey": "example", + "body": "example" + } + }, + "success": { + "ok": true, + "operationId": "answer_status_question", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 6, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "answer_status_question", + "version": 1, + "title": "Answer status question", + "description": "Append the answer to a status-only wake without changing task disposition.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "body": { + "type": "string", + "description": "Concise status answer.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 6, + "descriptor": { + "operationId": "answer_status_question", + "version": 1, + "title": "Answer status question", + "description": "Post an answer to a status question without changing task state.", + "inputSchema": { + "type": "object", + "properties": { + "body": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "report_progress" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/block-task.ts b/packages/paperclip-runner/src/protocol-actions/block-task.ts new file mode 100644 index 00000000000..ed441aeb8fd --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/block-task.ts @@ -0,0 +1,230 @@ +/** Canonical definition and documentation for `block_task`. */ +export const blockTaskAction = { + "id": "block_task", + "canonical": { + "operationId": "block_task", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Block active task", + "description": "Block the active mock task with a durable reason and optional first-class dependencies.", + "note": null + }, + "examples": { + "call": { + "operationId": "block_task", + "input": { + "idempotencyKey": "example", + "reason": "example" + } + }, + "success": { + "ok": true, + "operationId": "block_task", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 11, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "block_task", + "version": 1, + "title": "Block active task", + "description": "Block the active mock task with a durable reason and optional first-class dependencies.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "reason": { + "type": "string", + "description": "Block reason.", + "minLength": 1, + "maxLength": 20000 + }, + "blockedByTaskIds": { + "type": "array", + "description": "Internal mock task ids that block this task.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "idempotencyKey", + "reason" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 8, + "descriptor": { + "operationId": "block_task", + "version": 1, + "title": "Block task", + "description": "Block the active task with a reason and optional first-class dependencies.", + "inputSchema": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "minLength": 1 + }, + "blockedByTaskIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "required": [ + "reason" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "block_task" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts b/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts new file mode 100644 index 00000000000..9d2c9c27e4f --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts @@ -0,0 +1,238 @@ +/** Canonical definition and documentation for `comment_on_approval`. */ +export const commentOnApprovalAction = { + "id": "comment_on_approval", + "canonical": { + "operationId": "comment_on_approval", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:comment" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "approval lifecycle plus governed-wait continuation and audit events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Comment on approval", + "description": "Add a durable comment to a mock approval.", + "note": null + }, + "examples": { + "call": { + "operationId": "comment_on_approval", + "input": { + "idempotencyKey": "example", + "approvalId": "example", + "body": "example" + } + }, + "success": { + "ok": true, + "operationId": "comment_on_approval", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 25, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "comment_on_approval", + "version": 1, + "title": "Comment on approval", + "description": "Add a durable comment to a mock approval.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:comment" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "approvalId": { + "type": "string", + "description": "Mock approval id.", + "minLength": 1, + "maxLength": 200 + }, + "body": { + "type": "string", + "description": "Approval comment.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "approvalId", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 23, + "descriptor": { + "operationId": "comment_on_approval", + "version": 1, + "title": "Comment On Approval", + "description": "Comment On Approval through the Capability governance capability set.", + "inputSchema": { + "type": "object", + "properties": { + "approvalId": { + "type": "string", + "minLength": 1 + }, + "body": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "approvalId", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:comment" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "comment_on_approval" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts b/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts new file mode 100644 index 00000000000..b64abff2ebe --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts @@ -0,0 +1,248 @@ +/** Canonical definition and documentation for `control_workspace_service`. */ +export const controlWorkspaceServiceAction = { + "id": "control_workspace_service", + "canonical": { + "operationId": "control_workspace_service", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:control" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "workspace_control", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "workspace service lifecycle event", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Control workspace service", + "description": "Start, stop, or fault one active-task mock workspace service.", + "note": null + }, + "examples": { + "call": { + "operationId": "control_workspace_service", + "input": { + "idempotencyKey": "example", + "serviceId": "example", + "action": "start" + } + }, + "success": { + "ok": true, + "operationId": "control_workspace_service", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 20, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "control_workspace_service", + "version": 1, + "title": "Control workspace service", + "description": "Start, stop, or fault one active-task mock workspace service.", + "exposure": "optional", + "requiredClaims": [ + "workspace:control" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "serviceId": { + "type": "string", + "description": "Mock workspace service id.", + "minLength": 1, + "maxLength": 200 + }, + "action": { + "enum": [ + "start", + "stop", + "fail" + ] + }, + "url": { + "type": [ + "string", + "null" + ], + "description": "Optional mock service URL.", + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "serviceId", + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 27, + "descriptor": { + "operationId": "control_workspace_service", + "version": 1, + "title": "Control Workspace Service", + "description": "Control Workspace Service through the Capability workspace runtime capability set.", + "inputSchema": { + "type": "object", + "properties": { + "serviceId": { + "type": "string", + "minLength": 1 + }, + "action": { + "type": "string", + "enum": [ + "start", + "stop", + "fail" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "serviceId", + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:control" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "workspace_control", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "control_workspace_service" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/create-task.ts b/packages/paperclip-runner/src/protocol-actions/create-task.ts new file mode 100644 index 00000000000..f6e95e6673a --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/create-task.ts @@ -0,0 +1,270 @@ +/** Canonical definition and documentation for `create_task`. */ +export const createTaskAction = { + "id": "create_task", + "canonical": { + "operationId": "create_task", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "delegation_dependencies", + "requiredClaims": [ + "delegation:tasks:create" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus company-entity state diff and audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipCreateIssue" + ] + }, + "documentation": { + "title": "Create child task", + "description": "Create one child mock task under the active task.", + "note": null + }, + "examples": { + "call": { + "operationId": "create_task", + "input": { + "idempotencyKey": "example", + "title": "example" + } + }, + "success": { + "ok": true, + "operationId": "create_task", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 22, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "create_task", + "version": 1, + "title": "Create child task", + "description": "Create one child mock task under the active task.", + "exposure": "optional", + "requiredClaims": [ + "delegation:tasks:create" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "title": { + "type": "string", + "description": "Child task title.", + "minLength": 1, + "maxLength": 500 + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Child task description.", + "maxLength": 20000 + }, + "assigneeActorId": { + "type": [ + "string", + "null" + ], + "description": "Optional mock actor assignee.", + "maxLength": 20000 + }, + "priority": { + "enum": [ + "critical", + "high", + "medium", + "low" + ] + }, + "blockedByTaskIds": { + "type": "array", + "description": "Initial blocker task ids.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "idempotencyKey", + "title" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 18, + "descriptor": { + "operationId": "create_task", + "version": 1, + "title": "Create Task", + "description": "Create Task through the Capability delegation dependencies capability set.", + "inputSchema": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string" + }, + "assigneeActorId": { + "type": "string" + }, + "priority": { + "type": "string" + }, + "blockedByTaskIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "title" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "delegation_dependencies", + "requiredClaims": [ + "delegation:tasks:create" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "create_task" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/decide-approval.ts b/packages/paperclip-runner/src/protocol-actions/decide-approval.ts new file mode 100644 index 00000000000..bfe415df641 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/decide-approval.ts @@ -0,0 +1,265 @@ +/** Canonical definition and documentation for `decide_approval`. */ +export const decideApprovalAction = { + "id": "decide_approval", + "canonical": { + "operationId": "decide_approval", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:decide" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "allowedRoles": [ + "board", + "approver", + "security" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "approval lifecycle plus governed-wait continuation and audit events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Decide approval", + "description": "Decide a mock approval as an explicitly authorized approver.", + "note": null + }, + "examples": { + "call": { + "operationId": "decide_approval", + "input": { + "idempotencyKey": "example", + "approvalId": "example", + "decision": "approved", + "note": "example" + } + }, + "success": { + "ok": true, + "operationId": "decide_approval", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 24, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "decide_approval", + "version": 1, + "title": "Decide approval", + "description": "Decide a mock approval as an explicitly authorized approver.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:decide" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "allowedRoles": [ + "board", + "approver", + "security" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "approvalId": { + "type": "string", + "description": "Mock approval id.", + "minLength": 1, + "maxLength": 200 + }, + "decision": { + "enum": [ + "approved", + "rejected", + "cancelled" + ] + }, + "note": { + "type": "string", + "description": "Decision note.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "approvalId", + "decision", + "note" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 22, + "descriptor": { + "operationId": "decide_approval", + "version": 1, + "title": "Decide Approval", + "description": "Decide Approval through the Capability governance capability set.", + "inputSchema": { + "type": "object", + "properties": { + "approvalId": { + "type": "string", + "minLength": 1 + }, + "decision": { + "type": "string", + "enum": [ + "approved", + "rejected", + "cancelled" + ] + }, + "note": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "approvalId", + "decision", + "note" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:decide" + ], + "allowedRoles": [ + "board", + "approver", + "security" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "decide_approval" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/export-company.ts b/packages/paperclip-runner/src/protocol-actions/export-company.ts new file mode 100644 index 00000000000..667b270ccbe --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/export-company.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `export_company`. */ +export const exportCompanyAction = { + "id": "export_company", + "canonical": { + "operationId": "export_company", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "portability:export" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Export Company", + "description": "Export Company through the Capability portability admin capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "export_company", + "input": {} + }, + "success": { + "ok": true, + "operationId": "export_company", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 34, + "descriptor": { + "operationId": "export_company", + "version": 1, + "title": "Export Company", + "description": "Export Company through the Capability portability admin capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "portability:export" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "portability.export" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/finish-task.ts b/packages/paperclip-runner/src/protocol-actions/finish-task.ts new file mode 100644 index 00000000000..6e0ded20342 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/finish-task.ts @@ -0,0 +1,213 @@ +/** Canonical definition and documentation for `finish_task`. */ +export const finishTaskAction = { + "id": "finish_task", + "canonical": { + "operationId": "finish_task", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Finish active task", + "description": "Finish the active mock task with a durable summary.", + "note": null + }, + "examples": { + "call": { + "operationId": "finish_task", + "input": { + "idempotencyKey": "example", + "summary": "example" + } + }, + "success": { + "ok": true, + "operationId": "finish_task", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 10, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "finish_task", + "version": 1, + "title": "Finish active task", + "description": "Finish the active mock task with a durable summary.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "summary": { + "type": "string", + "description": "Completion summary.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "summary" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 7, + "descriptor": { + "operationId": "finish_task", + "version": 1, + "title": "Finish task", + "description": "Finish the active task with a durable completion summary.", + "inputSchema": { + "type": "object", + "properties": { + "summary": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "summary" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "finish_task" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts b/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts new file mode 100644 index 00000000000..c9893df89ea --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts @@ -0,0 +1,200 @@ +/** Canonical definition and documentation for `generic_api_request`. */ +export const genericApiRequestAction = { + "id": "generic_api_request", + "canonical": { + "operationId": "generic_api_request", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "test_escape_hatch", + "requiredClaims": [ + "test:generic_api_request" + ], + "taskModes": [ + "skill_test" + ], + "sideEffectClass": "test_escape_hatch", + "idempotency": "required", + "disabledByDefault": true, + "realBindingStatus": "test_only", + "realServiceBinding": "unbound", + "prpEvidence": "test-only; excluded from product PRP evidence", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Test-only escape hatch; explicitly cannot count as product capability coverage (PAP-17016 deliverable D). Single unified claim test:generic_api_request." + }, + "documentation": { + "title": "Generic API request", + "description": "Test-only escape hatch. Disabled unless the scenario and explicit claim both enable it.", + "note": "Test-only escape hatch; explicitly cannot count as product capability coverage (PAP-17016 deliverable D). Single unified claim test:generic_api_request." + }, + "examples": { + "call": { + "operationId": "generic_api_request", + "input": { + "method": "GET", + "path": "example" + } + }, + "success": { + "ok": true, + "operationId": "generic_api_request", + "result": {} + } + }, + "live": { + "order": 27, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "generic_api_request", + "version": 1, + "title": "Generic API request", + "description": "Test-only escape hatch. Disabled unless the scenario and explicit claim both enable it.", + "exposure": "optional", + "requiredClaims": [ + "test:generic_api_request" + ], + "allowedModes": [ + "skill_test" + ], + "disabledByDefault": true, + "inputSchema": { + "type": "object", + "properties": { + "method": { + "enum": [ + "GET", + "POST", + "PATCH" + ] + }, + "path": { + "type": "string", + "pattern": "^/mock/", + "maxLength": 500 + }, + "body": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "method", + "path" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 36, + "descriptor": { + "operationId": "generic_api_request", + "version": 1, + "title": "Generic Api Request", + "description": "Generic Api Request through the Capability test escape hatch capability set.", + "inputSchema": { + "type": "object", + "properties": { + "method": { + "type": "string", + "minLength": 1 + }, + "path": { + "type": "string", + "minLength": 1 + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": {} + }, + "required": [ + "method", + "path" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "test_escape_hatch", + "requiredClaims": [ + "test:generic_api_request" + ], + "taskModes": [ + "skill_test" + ], + "sideEffectClass": "test_escape_hatch", + "idempotency": "required", + "redaction": [ + { + "path": "$.headers.authorization", + "replacement": "[REDACTED]", + "appliesTo": [ + "input", + "output", + "error", + "authorization_record" + ] + }, + { + "path": "$.headers.cookie", + "replacement": "[REDACTED]", + "appliesTo": [ + "input", + "output", + "error", + "authorization_record" + ] + } + ], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "test.generic_api" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-agent.ts b/packages/paperclip-runner/src/protocol-actions/get-agent.ts new file mode 100644 index 00000000000..2320ad42561 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-agent.ts @@ -0,0 +1,90 @@ +/** Canonical definition and documentation for `get_agent`. */ +export const getAgentAction = { + "id": "get_agent", + "canonical": { + "operationId": "get_agent", + "surfaces": [ + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": null, + "requiredClaims": [ + "discovery:agents:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipGetAgent" + ], + "note": "Live-only single-actor read; the scenario suite covers actor discovery through list_agents." + }, + "documentation": { + "title": "Get company agent", + "description": "Read one redacted mock actor profile.", + "note": "Live-only single-actor read; the scenario suite covers actor discovery through list_agents." + }, + "examples": { + "call": { + "operationId": "get_agent", + "input": { + "actorId": "example" + } + }, + "success": { + "ok": true, + "operationId": "get_agent", + "result": {} + } + }, + "live": { + "order": 14, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_agent", + "version": 1, + "title": "Get company agent", + "description": "Read one redacted mock actor profile.", + "exposure": "optional", + "requiredClaims": [ + "discovery:agents:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "actorId": { + "type": "string", + "description": "Mock actor id.", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "actorId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": null +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-approval-context.ts b/packages/paperclip-runner/src/protocol-actions/get-approval-context.ts new file mode 100644 index 00000000000..7cbc9650e76 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-approval-context.ts @@ -0,0 +1,88 @@ +/** Canonical definition and documentation for `get_approval_context`. */ +export const getApprovalContextAction = { + "id": "get_approval_context", + "canonical": { + "operationId": "get_approval_context", + "surfaces": [ + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": null, + "requiredClaims": [ + "governance:approvals:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Live-only approval-plus-linked-tasks read; no scenario counterpart." + }, + "documentation": { + "title": "Get approval context", + "description": "Read one approval, its comments, and linked mock tasks.", + "note": "Live-only approval-plus-linked-tasks read; no scenario counterpart." + }, + "examples": { + "call": { + "operationId": "get_approval_context", + "input": { + "approvalId": "example" + } + }, + "success": { + "ok": true, + "operationId": "get_approval_context", + "result": {} + } + }, + "live": { + "order": 18, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_approval_context", + "version": 1, + "title": "Get approval context", + "description": "Read one approval, its comments, and linked mock tasks.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "approvalId": { + "type": "string", + "description": "Mock approval id.", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "approvalId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": null +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-approval.ts b/packages/paperclip-runner/src/protocol-actions/get-approval.ts new file mode 100644 index 00000000000..c66dbd7dfd8 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-approval.ts @@ -0,0 +1,88 @@ +/** Canonical definition and documentation for `get_approval`. */ +export const getApprovalAction = { + "id": "get_approval", + "canonical": { + "operationId": "get_approval", + "surfaces": [ + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": null, + "requiredClaims": [ + "governance:approvals:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Live-only single-approval read; the scenario suite covers approvals through list_approvals." + }, + "documentation": { + "title": "Get approval", + "description": "Read one mock approval without protected data.", + "note": "Live-only single-approval read; the scenario suite covers approvals through list_approvals." + }, + "examples": { + "call": { + "operationId": "get_approval", + "input": { + "approvalId": "example" + } + }, + "success": { + "ok": true, + "operationId": "get_approval", + "result": {} + } + }, + "live": { + "order": 17, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_approval", + "version": 1, + "title": "Get approval", + "description": "Read one mock approval without protected data.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "approvalId": { + "type": "string", + "description": "Mock approval id.", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [ + "approvalId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": null +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-task-context.ts b/packages/paperclip-runner/src/protocol-actions/get-task-context.ts new file mode 100644 index 00000000000..19b51401046 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-task-context.ts @@ -0,0 +1,140 @@ +/** Canonical definition and documentation for `get_task_context`. */ +export const getTaskContextAction = { + "id": "get_task_context", + "canonical": { + "operationId": "get_task_context", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipMe" + ] + }, + "documentation": { + "title": "Get active task context", + "description": "Read the active mock task, actor, wake, ancestors, budget, and interaction results.", + "note": null + }, + "examples": { + "call": { + "operationId": "get_task_context", + "input": {} + }, + "success": { + "ok": true, + "operationId": "get_task_context", + "result": {} + } + }, + "live": { + "order": 0, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_task_context", + "version": 1, + "title": "Get active task context", + "description": "Read the active mock task, actor, wake, ancestors, budget, and interaction results.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 0, + "descriptor": { + "operationId": "get_task_context", + "version": 1, + "title": "Get task context", + "description": "Read the active task, ancestors, wake context, linked results, and budget summary.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "context_read", + "projection": "active_task" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-task-history.ts b/packages/paperclip-runner/src/protocol-actions/get-task-history.ts new file mode 100644 index 00000000000..825afa803db --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-task-history.ts @@ -0,0 +1,150 @@ +/** Canonical definition and documentation for `get_task_history`. */ +export const getTaskHistoryAction = { + "id": "get_task_history", + "canonical": { + "operationId": "get_task_history", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Get active task history", + "description": "Read bounded comments on the active mock task.", + "note": null + }, + "examples": { + "call": { + "operationId": "get_task_history", + "input": {} + }, + "success": { + "ok": true, + "operationId": "get_task_history", + "result": {} + } + }, + "live": { + "order": 1, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_task_history", + "version": 1, + "title": "Get active task history", + "description": "Read bounded comments on the active mock task.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + } + }, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 1, + "descriptor": { + "operationId": "get_task_history", + "version": 1, + "title": "Get task history", + "description": "Read comments and audit-visible history for the active task only.", + "inputSchema": { + "type": "object", + "properties": { + "limit": { + "type": "integer", + "minimum": 1 + } + }, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_history" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts b/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts new file mode 100644 index 00000000000..744cd972a0c --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts @@ -0,0 +1,144 @@ +/** Canonical definition and documentation for `get_workspace_runtime`. */ +export const getWorkspaceRuntimeAction = { + "id": "get_workspace_runtime", + "canonical": { + "operationId": "get_workspace_runtime", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Get workspace runtime", + "description": "Read active-task mock workspace services.", + "note": null + }, + "examples": { + "call": { + "operationId": "get_workspace_runtime", + "input": {} + }, + "success": { + "ok": true, + "operationId": "get_workspace_runtime", + "result": {} + } + }, + "live": { + "order": 19, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_workspace_runtime", + "version": 1, + "title": "Get workspace runtime", + "description": "Read active-task mock workspace services.", + "exposure": "optional", + "requiredClaims": [ + "workspace:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 26, + "descriptor": { + "operationId": "get_workspace_runtime", + "version": 1, + "title": "Get Workspace Runtime", + "description": "Get Workspace Runtime through the Capability workspace runtime capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_workspace" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/index.ts b/packages/paperclip-runner/src/protocol-actions/index.ts new file mode 100644 index 00000000000..692ea58f5dc --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/index.ts @@ -0,0 +1,89 @@ +import { administerCompanyAction } from "./administer-company.js"; +import { answerStatusQuestionAction } from "./answer-status-question.js"; +import { blockTaskAction } from "./block-task.js"; +import { commentOnApprovalAction } from "./comment-on-approval.js"; +import { controlWorkspaceServiceAction } from "./control-workspace-service.js"; +import { createTaskAction } from "./create-task.js"; +import { decideApprovalAction } from "./decide-approval.js"; +import { exportCompanyAction } from "./export-company.js"; +import { finishTaskAction } from "./finish-task.js"; +import { genericApiRequestAction } from "./generic-api-request.js"; +import { getAgentAction } from "./get-agent.js"; +import { getApprovalAction } from "./get-approval.js"; +import { getApprovalContextAction } from "./get-approval-context.js"; +import { getTaskContextAction } from "./get-task-context.js"; +import { getTaskHistoryAction } from "./get-task-history.js"; +import { getWorkspaceRuntimeAction } from "./get-workspace-runtime.js"; +import { inspectOperationResultAction } from "./inspect-operation-result.js"; +import { listAgentsAction } from "./list-agents.js"; +import { listApprovalsAction } from "./list-approvals.js"; +import { listCasesAction } from "./list-cases.js"; +import { listCompanySkillsAction } from "./list-company-skills.js"; +import { listDocumentRevisionsAction } from "./list-document-revisions.js"; +import { listDocumentsAction } from "./list-documents.js"; +import { listGoalsAction } from "./list-goals.js"; +import { listProjectsAction } from "./list-projects.js"; +import { listRoutinesAction } from "./list-routines.js"; +import { listSecretMetadataAction } from "./list-secret-metadata.js"; +import { manageRoutineAction } from "./manage-routine.js"; +import { readDocumentAction } from "./read-document.js"; +import { readSecretValueAction } from "./read-secret-value.js"; +import { registerDeliverableAction } from "./register-deliverable.js"; +import { reportProgressAction } from "./report-progress.js"; +import { requestApprovalAction } from "./request-approval.js"; +import { requestHumanInputAction } from "./request-human-input.js"; +import { requestReviewAction } from "./request-review.js"; +import { scheduleWakeAction } from "./schedule-wake.js"; +import { searchTasksAction } from "./search-tasks.js"; +import { setDependenciesAction } from "./set-dependencies.js"; +import { syncCompanySkillsAction } from "./sync-company-skills.js"; +import { upsertCaseAction } from "./upsert-case.js"; +import { writeDocumentAction } from "./write-document.js"; + +export const PAPERCLIP_PROTOCOL_ACTIONS = Object.freeze([ + administerCompanyAction, + answerStatusQuestionAction, + blockTaskAction, + commentOnApprovalAction, + controlWorkspaceServiceAction, + createTaskAction, + decideApprovalAction, + exportCompanyAction, + finishTaskAction, + genericApiRequestAction, + getAgentAction, + getApprovalAction, + getApprovalContextAction, + getTaskContextAction, + getTaskHistoryAction, + getWorkspaceRuntimeAction, + inspectOperationResultAction, + listAgentsAction, + listApprovalsAction, + listCasesAction, + listCompanySkillsAction, + listDocumentRevisionsAction, + listDocumentsAction, + listGoalsAction, + listProjectsAction, + listRoutinesAction, + listSecretMetadataAction, + manageRoutineAction, + readDocumentAction, + readSecretValueAction, + registerDeliverableAction, + reportProgressAction, + requestApprovalAction, + requestHumanInputAction, + requestReviewAction, + scheduleWakeAction, + searchTasksAction, + setDependenciesAction, + syncCompanySkillsAction, + upsertCaseAction, + writeDocumentAction, +]); + +export function paperclipProtocolAction(operationId: string) { + return PAPERCLIP_PROTOCOL_ACTIONS.find((action) => action.id === operationId); +} diff --git a/packages/paperclip-runner/src/protocol-actions/inspect-operation-result.ts b/packages/paperclip-runner/src/protocol-actions/inspect-operation-result.ts new file mode 100644 index 00000000000..3ff76e87712 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/inspect-operation-result.ts @@ -0,0 +1,127 @@ +/** Canonical definition and documentation for `inspect_operation_result`. */ +export const inspectOperationResultAction = { + "id": "inspect_operation_result", + "canonical": { + "operationId": "inspect_operation_result", + "surfaces": [ + "scenario" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only re-read of a prior operation result; the live dispatcher returns results inline." + }, + "documentation": { + "title": "Inspect operation result", + "description": "Read a prior semantic operation result from this run.", + "note": "Scenario/eval-only re-read of a prior operation result; the live dispatcher returns results inline." + }, + "examples": { + "call": { + "operationId": "inspect_operation_result", + "input": { + "operationResultId": "example" + } + }, + "success": { + "ok": true, + "operationId": "inspect_operation_result", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 13, + "descriptor": { + "operationId": "inspect_operation_result", + "version": 1, + "title": "Inspect operation result", + "description": "Read a prior semantic operation result from this run.", + "inputSchema": { + "type": "object", + "properties": { + "operationResultId": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "operationResultId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "operation_result" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-agents.ts b/packages/paperclip-runner/src/protocol-actions/list-agents.ts new file mode 100644 index 00000000000..41dd5856c85 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-agents.ts @@ -0,0 +1,146 @@ +/** Canonical definition and documentation for `list_agents`. */ +export const listAgentsAction = { + "id": "list_agents", + "canonical": { + "operationId": "list_agents", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:agents:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipListAgents" + ] + }, + "documentation": { + "title": "List company agents", + "description": "List redacted mock actor profiles.", + "note": null + }, + "examples": { + "call": { + "operationId": "list_agents", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_agents", + "result": {} + } + }, + "live": { + "order": 13, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "list_agents", + "version": 1, + "title": "List company agents", + "description": "List redacted mock actor profiles.", + "exposure": "optional", + "requiredClaims": [ + "discovery:agents:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 15, + "descriptor": { + "operationId": "list_agents", + "version": 1, + "title": "List Agents", + "description": "List Agents through the Capability discovery capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:agents:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "company_actors" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-approvals.ts b/packages/paperclip-runner/src/protocol-actions/list-approvals.ts new file mode 100644 index 00000000000..94ff63db481 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-approvals.ts @@ -0,0 +1,144 @@ +/** Canonical definition and documentation for `list_approvals`. */ +export const listApprovalsAction = { + "id": "list_approvals", + "canonical": { + "operationId": "list_approvals", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "List approvals", + "description": "List mock approvals in the run company.", + "note": null + }, + "examples": { + "call": { + "operationId": "list_approvals", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_approvals", + "result": {} + } + }, + "live": { + "order": 16, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "list_approvals", + "version": 1, + "title": "List approvals", + "description": "List mock approvals in the run company.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 20, + "descriptor": { + "operationId": "list_approvals", + "version": 1, + "title": "List Approvals", + "description": "List Approvals through the Capability governance capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "company_approvals" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-cases.ts b/packages/paperclip-runner/src/protocol-actions/list-cases.ts new file mode 100644 index 00000000000..4ca3d887bc0 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-cases.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_cases`. */ +export const listCasesAction = { + "id": "list_cases", + "canonical": { + "operationId": "list_cases", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Cases", + "description": "List Cases through the Capability cases capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_cases", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_cases", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 24, + "descriptor": { + "operationId": "list_cases", + "version": 1, + "title": "List Cases", + "description": "List Cases through the Capability cases capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "cases.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts b/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts new file mode 100644 index 00000000000..c0622de7d1d --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_company_skills`. */ +export const listCompanySkillsAction = { + "id": "list_company_skills", + "canonical": { + "operationId": "list_company_skills", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Company Skills", + "description": "List Company Skills through the Capability company skills capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_company_skills", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_company_skills", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 30, + "descriptor": { + "operationId": "list_company_skills", + "version": 1, + "title": "List Company Skills", + "description": "List Company Skills through the Capability company skills capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company_skills.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-document-revisions.ts b/packages/paperclip-runner/src/protocol-actions/list-document-revisions.ts new file mode 100644 index 00000000000..ba4c7b77c3e --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-document-revisions.ts @@ -0,0 +1,162 @@ +/** Canonical definition and documentation for `list_document_revisions`. */ +export const listDocumentRevisionsAction = { + "id": "list_document_revisions", + "canonical": { + "operationId": "list_document_revisions", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "List document revisions", + "description": "Read bounded revision history for one active-task document.", + "note": null + }, + "examples": { + "call": { + "operationId": "list_document_revisions", + "input": { + "key": "example" + } + }, + "success": { + "ok": true, + "operationId": "list_document_revisions", + "result": {} + } + }, + "live": { + "order": 4, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "list_document_revisions", + "version": 1, + "title": "List document revisions", + "description": "Read bounded revision history for one active-task document.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Stable issue-document key.", + "minLength": 1, + "maxLength": 120 + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + } + }, + "required": [ + "key" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 4, + "descriptor": { + "operationId": "list_document_revisions", + "version": 1, + "title": "List document revisions", + "description": "Inspect revision history for one active-task document.", + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "key" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_document_revisions" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-documents.ts b/packages/paperclip-runner/src/protocol-actions/list-documents.ts new file mode 100644 index 00000000000..51a15e107c1 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-documents.ts @@ -0,0 +1,138 @@ +/** Canonical definition and documentation for `list_documents`. */ +export const listDocumentsAction = { + "id": "list_documents", + "canonical": { + "operationId": "list_documents", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "List task documents", + "description": "List revisioned documents on the active mock task.", + "note": null + }, + "examples": { + "call": { + "operationId": "list_documents", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_documents", + "result": {} + } + }, + "live": { + "order": 2, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "list_documents", + "version": 1, + "title": "List task documents", + "description": "List revisioned documents on the active mock task.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 2, + "descriptor": { + "operationId": "list_documents", + "version": 1, + "title": "List task documents", + "description": "List document metadata attached to the active task.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_documents" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-goals.ts b/packages/paperclip-runner/src/protocol-actions/list-goals.ts new file mode 100644 index 00000000000..5bb0dc85275 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-goals.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_goals`. */ +export const listGoalsAction = { + "id": "list_goals", + "canonical": { + "operationId": "list_goals", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:goals:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." + }, + "documentation": { + "title": "List Goals", + "description": "List Goals through the Capability discovery capability set.", + "note": "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." + }, + "examples": { + "call": { + "operationId": "list_goals", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_goals", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 17, + "descriptor": { + "operationId": "list_goals", + "version": 1, + "title": "List Goals", + "description": "List Goals through the Capability discovery capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:goals:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "discovery.goals" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-projects.ts b/packages/paperclip-runner/src/protocol-actions/list-projects.ts new file mode 100644 index 00000000000..6207bea943d --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-projects.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_projects`. */ +export const listProjectsAction = { + "id": "list_projects", + "canonical": { + "operationId": "list_projects", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:projects:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." + }, + "documentation": { + "title": "List Projects", + "description": "List Projects through the Capability discovery capability set.", + "note": "Scenario/eval-only discovery via mock extension; no live dispatcher binding yet." + }, + "examples": { + "call": { + "operationId": "list_projects", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_projects", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 16, + "descriptor": { + "operationId": "list_projects", + "version": 1, + "title": "List Projects", + "description": "List Projects through the Capability discovery capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:projects:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "discovery.projects" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-routines.ts b/packages/paperclip-runner/src/protocol-actions/list-routines.ts new file mode 100644 index 00000000000..173d0bdae9e --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-routines.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_routines`. */ +export const listRoutinesAction = { + "id": "list_routines", + "canonical": { + "operationId": "list_routines", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Routines", + "description": "List Routines through the Capability routines capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_routines", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_routines", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 28, + "descriptor": { + "operationId": "list_routines", + "version": 1, + "title": "List Routines", + "description": "List Routines through the Capability routines capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "routines.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts b/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts new file mode 100644 index 00000000000..83c7db252cb --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_secret_metadata`. */ +export const listSecretMetadataAction = { + "id": "list_secret_metadata", + "canonical": { + "operationId": "list_secret_metadata", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:metadata:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension; metadata only." + }, + "documentation": { + "title": "List Secret Metadata", + "description": "List Secret Metadata through the Capability secrets capability set.", + "note": "Scenario/eval-only mock extension; metadata only." + }, + "examples": { + "call": { + "operationId": "list_secret_metadata", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_secret_metadata", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 32, + "descriptor": { + "operationId": "list_secret_metadata", + "version": 1, + "title": "List Secret Metadata", + "description": "List Secret Metadata through the Capability secrets capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:metadata:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "secrets.metadata" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/manage-routine.ts b/packages/paperclip-runner/src/protocol-actions/manage-routine.ts new file mode 100644 index 00000000000..745f507d214 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/manage-routine.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `manage_routine`. */ +export const manageRoutineAction = { + "id": "manage_routine", + "canonical": { + "operationId": "manage_routine", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Manage Routine", + "description": "Manage Routine through the Capability routines capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "manage_routine", + "input": {} + }, + "success": { + "ok": true, + "operationId": "manage_routine", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 29, + "descriptor": { + "operationId": "manage_routine", + "version": 1, + "title": "Manage Routine", + "description": "Manage Routine through the Capability routines capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "routines.manage" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/read-document.ts b/packages/paperclip-runner/src/protocol-actions/read-document.ts new file mode 100644 index 00000000000..b04c4c3e0c2 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/read-document.ts @@ -0,0 +1,156 @@ +/** Canonical definition and documentation for `read_document`. */ +export const readDocumentAction = { + "id": "read_document", + "canonical": { + "operationId": "read_document", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Read task document", + "description": "Read the current revision of one active-task document.", + "note": null + }, + "examples": { + "call": { + "operationId": "read_document", + "input": { + "key": "example" + } + }, + "success": { + "ok": true, + "operationId": "read_document", + "result": {} + } + }, + "live": { + "order": 3, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "read_document", + "version": 1, + "title": "Read task document", + "description": "Read the current revision of one active-task document.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Stable issue-document key.", + "minLength": 1, + "maxLength": 120 + } + }, + "required": [ + "key" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 3, + "descriptor": { + "operationId": "read_document", + "version": 1, + "title": "Read task document", + "description": "Read one document on the active task by stable key.", + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "key" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_document" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts b/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts new file mode 100644 index 00000000000..04b525f80b9 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts @@ -0,0 +1,138 @@ +/** Canonical definition and documentation for `read_secret_value`. */ +export const readSecretValueAction = { + "id": "read_secret_value", + "canonical": { + "operationId": "read_secret_value", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:values:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "secret_read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "redacted tool-result item event; secret value never reaches the wire", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension; secret value redacted from every observable sink." + }, + "documentation": { + "title": "Read Secret Value", + "description": "Read Secret Value through the Capability secrets capability set.", + "note": "Scenario/eval-only mock extension; secret value redacted from every observable sink." + }, + "examples": { + "call": { + "operationId": "read_secret_value", + "input": { + "name": "example" + } + }, + "success": { + "ok": true, + "operationId": "read_secret_value", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 33, + "descriptor": { + "operationId": "read_secret_value", + "version": 1, + "title": "Read Secret Value", + "description": "Read Secret Value through the Capability secrets capability set.", + "inputSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:values:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "secret_read", + "idempotency": "none", + "redaction": [ + { + "path": "$.value", + "replacement": "[SECRET_VALUE]", + "appliesTo": [ + "output", + "error", + "authorization_record" + ] + } + ], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "secrets.value" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts new file mode 100644 index 00000000000..2073bda4b6b --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts @@ -0,0 +1,278 @@ +/** Canonical definition and documentation for `register_deliverable`. */ +export const registerDeliverableAction = { + "id": "register_deliverable", + "canonical": { + "operationId": "register_deliverable", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Register inspectable deliverable", + "description": "Register mock attachment metadata and its artifact work product without credentials or bytes in the tool result.", + "note": null + }, + "examples": { + "call": { + "operationId": "register_deliverable", + "input": { + "idempotencyKey": "example", + "filename": "example", + "contentType": "example", + "byteSize": 1, + "sha256": "example", + "contentRef": "example", + "title": "example" + } + }, + "success": { + "ok": true, + "operationId": "register_deliverable", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 9, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "register_deliverable", + "version": 1, + "title": "Register inspectable deliverable", + "description": "Register mock attachment metadata and its artifact work product without credentials or bytes in the tool result.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "filename": { + "type": "string", + "description": "Display filename.", + "minLength": 1, + "maxLength": 500 + }, + "contentType": { + "type": "string", + "description": "Media type.", + "minLength": 1, + "maxLength": 200 + }, + "byteSize": { + "type": "integer", + "minimum": 0, + "maximum": 100000000 + }, + "sha256": { + "type": "string", + "pattern": "^[a-fA-F0-9]{64}$" + }, + "contentRef": { + "type": "string", + "description": "Opaque package-local content reference.", + "minLength": 1, + "maxLength": 2000 + }, + "title": { + "type": "string", + "description": "Work-product title.", + "minLength": 1, + "maxLength": 500 + } + }, + "required": [ + "idempotencyKey", + "filename", + "contentType", + "byteSize", + "sha256", + "contentRef", + "title" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 12, + "descriptor": { + "operationId": "register_deliverable", + "version": 1, + "title": "Register deliverable", + "description": "Register an inspectable artifact and its work product on the active task.", + "inputSchema": { + "type": "object", + "properties": { + "filename": { + "type": "string", + "minLength": 1 + }, + "contentType": { + "type": "string", + "minLength": 1 + }, + "byteSize": { + "type": "integer", + "minimum": 0 + }, + "sha256": { + "type": "string", + "minLength": 1 + }, + "contentRef": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "filename", + "contentType", + "byteSize", + "sha256", + "contentRef", + "title" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "register_deliverable" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/report-progress.ts b/packages/paperclip-runner/src/protocol-actions/report-progress.ts new file mode 100644 index 00000000000..671d34fd80a --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/report-progress.ts @@ -0,0 +1,221 @@ +/** Canonical definition and documentation for `report_progress`. */ +export const reportProgressAction = { + "id": "report_progress", + "canonical": { + "operationId": "report_progress", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipAddComment" + ] + }, + "documentation": { + "title": "Report durable progress", + "description": "Append a durable progress comment to the active mock task.", + "note": null + }, + "examples": { + "call": { + "operationId": "report_progress", + "input": { + "idempotencyKey": "example", + "body": "example" + } + }, + "success": { + "ok": true, + "operationId": "report_progress", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 5, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "report_progress", + "version": 1, + "title": "Report durable progress", + "description": "Append a durable progress comment to the active mock task.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "body": { + "type": "string", + "description": "Multiline progress update.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 5, + "descriptor": { + "operationId": "report_progress", + "version": 1, + "title": "Report progress", + "description": "Append a durable progress update to the active task.", + "inputSchema": { + "type": "object", + "properties": { + "body": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "report_progress" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/request-approval.ts b/packages/paperclip-runner/src/protocol-actions/request-approval.ts new file mode 100644 index 00000000000..01489938928 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/request-approval.ts @@ -0,0 +1,227 @@ +/** Canonical definition and documentation for `request_approval`. */ +export const requestApprovalAction = { + "id": "request_approval", + "canonical": { + "operationId": "request_approval", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:request" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "approval lifecycle plus governed-wait continuation and audit events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Request approval", + "description": "Create a governed mock approval and waiting posture.", + "note": null + }, + "examples": { + "call": { + "operationId": "request_approval", + "input": { + "idempotencyKey": "example", + "approvalType": "example", + "payload": {} + } + }, + "success": { + "ok": true, + "operationId": "request_approval", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 23, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "request_approval", + "version": 1, + "title": "Request approval", + "description": "Create a governed mock approval and waiting posture.", + "exposure": "optional", + "requiredClaims": [ + "governance:approvals:request" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "approvalType": { + "type": "string", + "description": "Stable approval type.", + "minLength": 1, + "maxLength": 200 + }, + "payload": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "idempotencyKey", + "approvalType", + "payload" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 21, + "descriptor": { + "operationId": "request_approval", + "version": 1, + "title": "Request Approval", + "description": "Request Approval through the Capability governance capability set.", + "inputSchema": { + "type": "object", + "properties": { + "approvalType": { + "type": "string", + "minLength": 1 + }, + "payload": {} + }, + "required": [ + "approvalType", + "payload" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "governance", + "requiredClaims": [ + "governance:approvals:request" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "governance", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "request_approval" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/request-human-input.ts b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts new file mode 100644 index 00000000000..2a2f61acfef --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts @@ -0,0 +1,293 @@ +/** Canonical definition and documentation for `request_human_input`. */ +export const requestHumanInputAction = { + "id": "request_human_input", + "canonical": { + "operationId": "request_human_input", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Request structured human input", + "description": "Create a typed, durable interaction on the active mock task.", + "note": null + }, + "examples": { + "call": { + "operationId": "request_human_input", + "input": { + "idempotencyKey": "example", + "interactionKind": "confirmation", + "title": "example", + "prompt": "example", + "continuationPolicy": "none" + } + }, + "success": { + "ok": true, + "operationId": "request_human_input", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 8, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "request_human_input", + "version": 1, + "title": "Request structured human input", + "description": "Create a typed, durable interaction on the active mock task.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "interactionKind": { + "enum": [ + "confirmation", + "checkbox", + "questions", + "suggest_tasks", + "item_verdicts" + ] + }, + "title": { + "type": "string", + "description": "Interaction card title.", + "minLength": 1, + "maxLength": 300 + }, + "prompt": { + "type": "string", + "description": "Question or decision prompt.", + "minLength": 1, + "maxLength": 10000 + }, + "payload": { + "type": "object", + "additionalProperties": true + }, + "targetRevisionId": { + "type": [ + "string", + "null" + ], + "description": "Optional bound document revision.", + "maxLength": 20000 + }, + "continuationPolicy": { + "enum": [ + "none", + "wake_assignee", + "wake_assignee_on_accept" + ] + } + }, + "required": [ + "idempotencyKey", + "interactionKind", + "title", + "prompt", + "continuationPolicy" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 11, + "descriptor": { + "operationId": "request_human_input", + "version": 1, + "title": "Request human input", + "description": "Create a typed confirmation, checkbox, question, task suggestion, or item-verdict request.", + "inputSchema": { + "type": "object", + "properties": { + "interactionKind": { + "type": "string", + "enum": [ + "confirmation", + "checkbox", + "questions", + "suggest_tasks", + "item_verdicts" + ] + }, + "title": { + "type": "string", + "minLength": 1 + }, + "prompt": { + "type": "string", + "minLength": 1 + }, + "payload": {}, + "targetRevisionId": { + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "null" + } + ] + }, + "continuationPolicy": { + "type": "string", + "enum": [ + "none", + "wake_assignee", + "wake_assignee_on_accept" + ] + } + }, + "required": [ + "interactionKind", + "title", + "prompt", + "continuationPolicy" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "request_human_input" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/request-review.ts b/packages/paperclip-runner/src/protocol-actions/request-review.ts new file mode 100644 index 00000000000..69ddc6fb3ca --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/request-review.ts @@ -0,0 +1,213 @@ +/** Canonical definition and documentation for `request_review`. */ +export const requestReviewAction = { + "id": "request_review", + "canonical": { + "operationId": "request_review", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Request task review", + "description": "Move the active mock task to review with a durable summary.", + "note": null + }, + "examples": { + "call": { + "operationId": "request_review", + "input": { + "idempotencyKey": "example", + "summary": "example" + } + }, + "success": { + "ok": true, + "operationId": "request_review", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 12, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "request_review", + "version": 1, + "title": "Request task review", + "description": "Move the active mock task to review with a durable summary.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "summary": { + "type": "string", + "description": "Review handoff summary.", + "minLength": 1, + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "summary" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 9, + "descriptor": { + "operationId": "request_review", + "version": 1, + "title": "Request task review", + "description": "Move the active task to review with a durable summary.", + "inputSchema": { + "type": "object", + "properties": { + "summary": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "summary" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "request_review" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts b/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts new file mode 100644 index 00000000000..ba3b4e88192 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts @@ -0,0 +1,163 @@ +/** Canonical definition and documentation for `schedule_wake`. */ +export const scheduleWakeAction = { + "id": "schedule_wake", + "canonical": { + "operationId": "schedule_wake", + "surfaces": [ + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": null, + "requiredClaims": [ + "control_plane:wakes" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Bounded, deterministic mock wake scheduling; requires the control_plane:wakes claim. Live-only continuation primitive." + }, + "documentation": { + "title": "Schedule bounded wake", + "description": "Schedule a deterministic mock continuation wake.", + "note": "Bounded, deterministic mock wake scheduling; requires the control_plane:wakes claim. Live-only continuation primitive." + }, + "examples": { + "call": { + "operationId": "schedule_wake", + "input": { + "idempotencyKey": "example", + "reason": "manual", + "delayTicks": 1 + } + }, + "success": { + "ok": true, + "operationId": "schedule_wake", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 26, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "schedule_wake", + "version": 1, + "title": "Schedule bounded wake", + "description": "Schedule a deterministic mock continuation wake.", + "exposure": "optional", + "requiredClaims": [ + "control_plane:wakes" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "reason": { + "enum": [ + "manual", + "issue_commented", + "interaction_resolved", + "approval_resolved", + "blockers_resolved", + "scheduled_retry", + "resume" + ] + }, + "payload": { + "type": "object", + "additionalProperties": true + }, + "delayTicks": { + "type": "integer", + "minimum": 1, + "maximum": 10000 + } + }, + "required": [ + "idempotencyKey", + "reason", + "delayTicks" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": null +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/search-tasks.ts b/packages/paperclip-runner/src/protocol-actions/search-tasks.ts new file mode 100644 index 00000000000..d2e795fe12b --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/search-tasks.ts @@ -0,0 +1,180 @@ +/** Canonical definition and documentation for `search_tasks`. */ +export const searchTasksAction = { + "id": "search_tasks", + "canonical": { + "operationId": "search_tasks", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:tasks:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [ + "mcp:paperclipListIssues" + ] + }, + "documentation": { + "title": "Search company tasks", + "description": "Search mock tasks by text and status within the run company.", + "note": null + }, + "examples": { + "call": { + "operationId": "search_tasks", + "input": {} + }, + "success": { + "ok": true, + "operationId": "search_tasks", + "result": {} + } + }, + "live": { + "order": 15, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "search_tasks", + "version": 1, + "title": "Search company tasks", + "description": "Search mock tasks by text and status within the run company.", + "exposure": "optional", + "requiredClaims": [ + "discovery:tasks:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "query": { + "type": "string", + "maxLength": 500 + }, + "statuses": { + "type": "array", + "items": { + "enum": [ + "backlog", + "todo", + "in_progress", + "in_review", + "done", + "blocked", + "cancelled" + ] + }, + "maxItems": 7, + "uniqueItems": true + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 200, + "default": 50 + } + }, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 14, + "descriptor": { + "operationId": "search_tasks", + "version": 1, + "title": "Search Tasks", + "description": "Search Tasks through the Capability discovery capability set.", + "inputSchema": { + "type": "object", + "properties": { + "query": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "discovery", + "requiredClaims": [ + "discovery:tasks:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "company_tasks" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts b/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts new file mode 100644 index 00000000000..6e15b30c8c0 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts @@ -0,0 +1,228 @@ +/** Canonical definition and documentation for `set_dependencies`. */ +export const setDependenciesAction = { + "id": "set_dependencies", + "canonical": { + "operationId": "set_dependencies", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "delegation_dependencies", + "requiredClaims": [ + "dependencies:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus company-entity state diff and audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Set task dependencies", + "description": "Replace the active task's first-class blocker set.", + "note": null + }, + "examples": { + "call": { + "operationId": "set_dependencies", + "input": { + "idempotencyKey": "example", + "blockedByTaskIds": [ + "example" + ] + } + }, + "success": { + "ok": true, + "operationId": "set_dependencies", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 21, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "set_dependencies", + "version": 1, + "title": "Set task dependencies", + "description": "Replace the active task's first-class blocker set.", + "exposure": "optional", + "requiredClaims": [ + "dependencies:write" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "blockedByTaskIds": { + "type": "array", + "description": "Replacement blocker task ids.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "idempotencyKey", + "blockedByTaskIds" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 19, + "descriptor": { + "operationId": "set_dependencies", + "version": 1, + "title": "Set Dependencies", + "description": "Set Dependencies through the Capability delegation dependencies capability set.", + "inputSchema": { + "type": "object", + "properties": { + "blockedByTaskIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "required": [ + "blockedByTaskIds" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "delegation_dependencies", + "requiredClaims": [ + "dependencies:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "set_dependencies" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts b/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts new file mode 100644 index 00000000000..91dd63f92f5 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `sync_company_skills`. */ +export const syncCompanySkillsAction = { + "id": "sync_company_skills", + "canonical": { + "operationId": "sync_company_skills", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Sync Company Skills", + "description": "Sync Company Skills through the Capability company skills capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "sync_company_skills", + "input": {} + }, + "success": { + "ok": true, + "operationId": "sync_company_skills", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 31, + "descriptor": { + "operationId": "sync_company_skills", + "version": 1, + "title": "Sync Company Skills", + "description": "Sync Company Skills through the Capability company skills capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company_skills.sync" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/upsert-case.ts b/packages/paperclip-runner/src/protocol-actions/upsert-case.ts new file mode 100644 index 00000000000..426074c0778 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/upsert-case.ts @@ -0,0 +1,133 @@ +/** Canonical definition and documentation for `upsert_case`. */ +export const upsertCaseAction = { + "id": "upsert_case", + "canonical": { + "operationId": "upsert_case", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus company-entity state diff and audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Upsert Case", + "description": "Upsert Case through the Capability cases capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "upsert_case", + "input": { + "key": "example", + "body": "example" + } + }, + "success": { + "ok": true, + "operationId": "upsert_case", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 25, + "descriptor": { + "operationId": "upsert_case", + "version": 1, + "title": "Upsert Case", + "description": "Upsert Case through the Capability cases capability set.", + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "minLength": 1 + }, + "body": { + "type": "string" + } + }, + "required": [ + "key", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "cases.upsert" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/write-document.ts b/packages/paperclip-runner/src/protocol-actions/write-document.ts new file mode 100644 index 00000000000..9cf429b0b5a --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/write-document.ts @@ -0,0 +1,274 @@ +/** Canonical definition and documentation for `write_document`. */ +export const writeDocumentAction = { + "id": "write_document", + "canonical": { + "operationId": "write_document", + "surfaces": [ + "scenario", + "live" + ], + "placement": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Write revisioned document", + "description": "Create or update an active-task document with optimistic revision safety.", + "note": null + }, + "examples": { + "call": { + "operationId": "write_document", + "input": { + "idempotencyKey": "example", + "key": "example", + "title": "example", + "body": "example", + "baseRevisionId": "example" + } + }, + "success": { + "ok": true, + "operationId": "write_document", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 7, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "write_document", + "version": 1, + "title": "Write revisioned document", + "description": "Create or update an active-task document with optimistic revision safety.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "key": { + "type": "string", + "description": "Stable issue-document key.", + "minLength": 1, + "maxLength": 120 + }, + "title": { + "type": "string", + "description": "Document title.", + "minLength": 1, + "maxLength": 300 + }, + "body": { + "type": "string", + "description": "Markdown document body.", + "minLength": 1, + "maxLength": 200000 + }, + "baseRevisionId": { + "type": [ + "string", + "null" + ], + "description": "Current revision id, or null when creating.", + "maxLength": 20000 + }, + "changeSummary": { + "type": [ + "string", + "null" + ], + "description": "Optional revision summary.", + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "key", + "title", + "body", + "baseRevisionId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 10, + "descriptor": { + "operationId": "write_document", + "version": 1, + "title": "Write task document", + "description": "Create or revision-safely update an active-task document.", + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "body": { + "type": "string" + }, + "baseRevisionId": { + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "null" + } + ] + }, + "changeSummary": { + "type": "string" + } + }, + "required": [ + "key", + "title", + "body", + "baseRevisionId" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "always_agent_tool", + "optionalGroup": null, + "requiredClaims": [], + "taskModes": [ + "standard", + "planning", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "write_document" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/semantic-tools/catalog.ts b/packages/paperclip-runner/src/semantic-tools/catalog.ts index adf5e2f4f36..3e9564c3380 100644 --- a/packages/paperclip-runner/src/semantic-tools/catalog.ts +++ b/packages/paperclip-runner/src/semantic-tools/catalog.ts @@ -1,204 +1,15 @@ -import { - capabilityCanonicalOperationsForSurface, - type CapabilityCanonicalOperation, -} from "../catalog/canonical-operations.js"; -import type { - CapabilityJsonSchema, - CapabilitySemanticOperationId, - CapabilitySemanticToolDescriptor, -} from "./types.js"; - -// --------------------------------------------------------------------------- -// This catalog no longer declares an independent operation list, exposure, or -// claim/mode policy. Exposure (`always`/`optional`), required claims, allowed -// task modes, allowed roles, and the disabled-by-default flag are single-sourced -// from `src/catalog/canonical-operations.ts` (PAP-17039). This module supplies -// only the live provider *presentation*: title, description, and the in-band -// provider input/output schemas the model sees. -// --------------------------------------------------------------------------- - -const text = (description: string, maxLength = 20_000): CapabilityJsonSchema => ({ - type: "string", - description, - minLength: 1, - maxLength, -}); -const nullableText = (description: string): CapabilityJsonSchema => ({ - type: ["string", "null"], - description, - maxLength: 20_000, -}); -const stringArray = (description: string): CapabilityJsonSchema => ({ - type: "array", - description, - items: { type: "string", minLength: 1 }, - maxItems: 200, - uniqueItems: true, -}); -const object = ( - properties: Readonly> = {}, - required: readonly string[] = [], -): CapabilityJsonSchema => ({ - type: "object", - properties, - required, - additionalProperties: false, -}); -const jsonObject: CapabilityJsonSchema = { type: "object", additionalProperties: true }; -const operationResult = object({ - commandId: text("Stable mock command identifier.", 200), - disposition: { enum: ["applied", "duplicate"] }, - stateRevision: { type: "integer", minimum: 0 }, - entityRefs: stringArray("Mock entities affected by the operation."), - scheduledWakeIds: stringArray("Wake identifiers scheduled by the operation."), -}, ["commandId", "disposition", "stateRevision", "entityRefs", "scheduledWakeIds"]); -const readResult: CapabilityJsonSchema = { type: "object", additionalProperties: true }; - -const idempotency = { idempotencyKey: text("Caller-stable retry key.", 240) } as const; - -/** Per-operation live provider presentation, in golden declaration order. */ -interface LivePresentation { - readonly operationId: CapabilitySemanticOperationId; - readonly title: string; - readonly description: string; - readonly inputSchema?: CapabilityJsonSchema; - readonly outputSchema?: CapabilityJsonSchema; -} - -const PRESENTATION: readonly LivePresentation[] = [ - { operationId: "get_task_context", title: "Get active task context", description: "Read the active mock task, actor, wake, ancestors, budget, and interaction results." }, - { operationId: "get_task_history", title: "Get active task history", description: "Read bounded comments on the active mock task.", inputSchema: object({ limit: { type: "integer", minimum: 1, maximum: 200, default: 50 } }) }, - { operationId: "list_documents", title: "List task documents", description: "List revisioned documents on the active mock task." }, - { operationId: "read_document", title: "Read task document", description: "Read the current revision of one active-task document.", inputSchema: object({ key: text("Stable issue-document key.", 120) }, ["key"]) }, - { operationId: "list_document_revisions", title: "List document revisions", description: "Read bounded revision history for one active-task document.", inputSchema: object({ key: text("Stable issue-document key.", 120), limit: { type: "integer", minimum: 1, maximum: 200, default: 50 } }, ["key"]) }, - { operationId: "report_progress", title: "Report durable progress", description: "Append a durable progress comment to the active mock task.", inputSchema: object({ ...idempotency, body: text("Multiline progress update.") }, ["idempotencyKey", "body"]), outputSchema: operationResult }, - { operationId: "answer_status_question", title: "Answer status question", description: "Append the answer to a status-only wake without changing task disposition.", inputSchema: object({ ...idempotency, body: text("Concise status answer.") }, ["idempotencyKey", "body"]), outputSchema: operationResult }, - { - operationId: "write_document", title: "Write revisioned document", description: "Create or update an active-task document with optimistic revision safety.", - inputSchema: object({ - ...idempotency, - key: text("Stable issue-document key.", 120), - title: text("Document title.", 300), - body: text("Markdown document body.", 200_000), - baseRevisionId: nullableText("Current revision id, or null when creating."), - changeSummary: nullableText("Optional revision summary."), - }, ["idempotencyKey", "key", "title", "body", "baseRevisionId"]), - outputSchema: operationResult, - }, - { - operationId: "request_human_input", title: "Request structured human input", description: "Create a typed, durable interaction on the active mock task.", - inputSchema: object({ - ...idempotency, - interactionKind: { enum: ["confirmation", "checkbox", "questions", "suggest_tasks", "item_verdicts"] }, - title: text("Interaction card title.", 300), - prompt: text("Question or decision prompt.", 10_000), - payload: jsonObject, - targetRevisionId: nullableText("Optional bound document revision."), - continuationPolicy: { enum: ["none", "wake_assignee", "wake_assignee_on_accept"] }, - }, ["idempotencyKey", "interactionKind", "title", "prompt", "continuationPolicy"]), - outputSchema: operationResult, - }, - { - operationId: "register_deliverable", title: "Register inspectable deliverable", description: "Register mock attachment metadata and its artifact work product without credentials or bytes in the tool result.", - inputSchema: object({ - ...idempotency, - filename: text("Display filename.", 500), - contentType: text("Media type.", 200), - byteSize: { type: "integer", minimum: 0, maximum: 100_000_000 }, - sha256: { type: "string", pattern: "^[a-fA-F0-9]{64}$" }, - contentRef: text("Opaque package-local content reference.", 2_000), - title: text("Work-product title.", 500), - }, ["idempotencyKey", "filename", "contentType", "byteSize", "sha256", "contentRef", "title"]), - outputSchema: operationResult, - }, - { operationId: "finish_task", title: "Finish active task", description: "Finish the active mock task with a durable summary.", inputSchema: object({ ...idempotency, summary: text("Completion summary.") }, ["idempotencyKey", "summary"]), outputSchema: operationResult }, - { operationId: "block_task", title: "Block active task", description: "Block the active mock task with a durable reason and optional first-class dependencies.", inputSchema: object({ ...idempotency, reason: text("Block reason."), blockedByTaskIds: stringArray("Internal mock task ids that block this task.") }, ["idempotencyKey", "reason"]), outputSchema: operationResult }, - { operationId: "request_review", title: "Request task review", description: "Move the active mock task to review with a durable summary.", inputSchema: object({ ...idempotency, summary: text("Review handoff summary.") }, ["idempotencyKey", "summary"]), outputSchema: operationResult }, - { operationId: "list_agents", title: "List company agents", description: "List redacted mock actor profiles." }, - { operationId: "get_agent", title: "Get company agent", description: "Read one redacted mock actor profile.", inputSchema: object({ actorId: text("Mock actor id.", 200) }, ["actorId"]) }, - { operationId: "search_tasks", title: "Search company tasks", description: "Search mock tasks by text and status within the run company.", inputSchema: object({ query: { type: "string", maxLength: 500 }, statuses: { type: "array", items: { enum: ["backlog", "todo", "in_progress", "in_review", "done", "blocked", "cancelled"] }, maxItems: 7, uniqueItems: true }, limit: { type: "integer", minimum: 1, maximum: 200, default: 50 } }) }, - { operationId: "list_approvals", title: "List approvals", description: "List mock approvals in the run company." }, - { operationId: "get_approval", title: "Get approval", description: "Read one mock approval without protected data.", inputSchema: object({ approvalId: text("Mock approval id.", 200) }, ["approvalId"]) }, - { operationId: "get_approval_context", title: "Get approval context", description: "Read one approval, its comments, and linked mock tasks.", inputSchema: object({ approvalId: text("Mock approval id.", 200) }, ["approvalId"]) }, - { operationId: "get_workspace_runtime", title: "Get workspace runtime", description: "Read active-task mock workspace services." }, - { operationId: "control_workspace_service", title: "Control workspace service", description: "Start, stop, or fault one active-task mock workspace service.", inputSchema: object({ ...idempotency, serviceId: text("Mock workspace service id.", 200), action: { enum: ["start", "stop", "fail"] }, url: nullableText("Optional mock service URL.") }, ["idempotencyKey", "serviceId", "action"]), outputSchema: operationResult }, - { operationId: "set_dependencies", title: "Set task dependencies", description: "Replace the active task's first-class blocker set.", inputSchema: object({ ...idempotency, blockedByTaskIds: stringArray("Replacement blocker task ids.") }, ["idempotencyKey", "blockedByTaskIds"]), outputSchema: operationResult }, - { operationId: "create_task", title: "Create child task", description: "Create one child mock task under the active task.", inputSchema: object({ ...idempotency, title: text("Child task title.", 500), description: nullableText("Child task description."), assigneeActorId: nullableText("Optional mock actor assignee."), priority: { enum: ["critical", "high", "medium", "low"] }, blockedByTaskIds: stringArray("Initial blocker task ids.") }, ["idempotencyKey", "title"]), outputSchema: operationResult }, - { operationId: "request_approval", title: "Request approval", description: "Create a governed mock approval and waiting posture.", inputSchema: object({ ...idempotency, approvalType: text("Stable approval type.", 200), payload: jsonObject }, ["idempotencyKey", "approvalType", "payload"]), outputSchema: operationResult }, - { operationId: "decide_approval", title: "Decide approval", description: "Decide a mock approval as an explicitly authorized approver.", inputSchema: object({ ...idempotency, approvalId: text("Mock approval id.", 200), decision: { enum: ["approved", "rejected", "cancelled"] }, note: text("Decision note.") }, ["idempotencyKey", "approvalId", "decision", "note"]), outputSchema: operationResult }, - { operationId: "comment_on_approval", title: "Comment on approval", description: "Add a durable comment to a mock approval.", inputSchema: object({ ...idempotency, approvalId: text("Mock approval id.", 200), body: text("Approval comment.") }, ["idempotencyKey", "approvalId", "body"]), outputSchema: operationResult }, - { operationId: "schedule_wake", title: "Schedule bounded wake", description: "Schedule a deterministic mock continuation wake.", inputSchema: object({ ...idempotency, reason: { enum: ["manual", "issue_commented", "interaction_resolved", "approval_resolved", "blockers_resolved", "scheduled_retry", "resume"] }, payload: jsonObject, delayTicks: { type: "integer", minimum: 1, maximum: 10_000 } }, ["idempotencyKey", "reason", "delayTicks"]), outputSchema: operationResult }, - { operationId: "generic_api_request", title: "Generic API request", description: "Test-only escape hatch. Disabled unless the scenario and explicit claim both enable it.", inputSchema: object({ method: { enum: ["GET", "POST", "PATCH"] }, path: { type: "string", pattern: "^/mock/", maxLength: 500 }, body: jsonObject }, ["method", "path"]) }, -]; - -const canonicalById = new Map( - capabilityCanonicalOperationsForSurface("live").map((operation) => [operation.operationId, operation]), -); - -function toDescriptor( - presentation: LivePresentation, - operation: CapabilityCanonicalOperation, -): CapabilitySemanticToolDescriptor { - return { - schema: "paperclip.semantic-tool.v1", - operationId: presentation.operationId, - version: 1, - title: presentation.title, - description: presentation.description, - exposure: operation.placement === "always_agent_tool" ? "always" : "optional", - requiredClaims: [...operation.requiredClaims], - allowedModes: [...operation.taskModes] as CapabilitySemanticToolDescriptor["allowedModes"], - ...(operation.allowedRoles === undefined ? {} : { allowedRoles: [...operation.allowedRoles] }), - ...(operation.disabledByDefault ? { disabledByDefault: true } : {}), - inputSchema: presentation.inputSchema ?? object(), - outputSchema: presentation.outputSchema ?? readResult, - }; -} - -// Bidirectional parity: presentation set === canonical live-surface set. -const presentedIds = new Set(PRESENTATION.map((entry) => entry.operationId)); -if (presentedIds.size !== PRESENTATION.length) throw new Error("duplicate Capability semantic operation id"); -for (const entry of PRESENTATION) { - if (!canonicalById.has(entry.operationId)) { - throw new Error(`Live presentation ${entry.operationId} is not a canonical live-surface operation.`); - } -} -for (const operationId of canonicalById.keys()) { - if (!presentedIds.has(operationId as CapabilitySemanticOperationId)) { - throw new Error(`Canonical live operation ${operationId} has no live presentation.`); - } -} - -const descriptors: readonly CapabilitySemanticToolDescriptor[] = PRESENTATION.map((presentation) => - toDescriptor(presentation, canonicalById.get(presentation.operationId)!), -); - +/** Live provider projection of the per-action protocol definitions. */ +import { PAPERCLIP_PROTOCOL_ACTIONS } from "../protocol-actions/index.js"; +import type { CapabilitySemanticOperationId, CapabilitySemanticToolDescriptor } from "./types.js"; +const descriptors = PAPERCLIP_PROTOCOL_ACTIONS.filter((action) => action.live !== null) + .sort((left, right) => left.live!.order - right.live!.order) + .map((action) => action.live!.descriptor as unknown as CapabilitySemanticToolDescriptor); +export const CAPABILITY_SEMANTIC_TOOL_CATALOG: readonly CapabilitySemanticToolDescriptor[] = Object.freeze(descriptors); const byId = new Map(descriptors.map((item) => [item.operationId, item])); - -export const CAPABILITY_SEMANTIC_TOOL_CATALOG = deepFreeze(descriptors); - -export function capabilitySemanticToolDescriptor( - operationId: string, -): CapabilitySemanticToolDescriptor | undefined { - return byId.get(operationId as CapabilitySemanticOperationId); -} - -export function canonicalCapabilitySemanticCatalog(): string { - return canonicalJson(CAPABILITY_SEMANTIC_TOOL_CATALOG); -} - -function deepFreeze(value: T): T { - if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value; - Object.freeze(value); - for (const child of Object.values(value)) deepFreeze(child); - return value; -} - +export function capabilitySemanticToolDescriptor(operationId: string): CapabilitySemanticToolDescriptor | undefined { return byId.get(operationId as CapabilitySemanticOperationId); } +export function canonicalCapabilitySemanticCatalog(): string { return canonicalJson(CAPABILITY_SEMANTIC_TOOL_CATALOG); } function canonicalJson(value: unknown): string { if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`; - if (typeof value === "object" && value !== null) { - const record = value as Record; - return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`; - } + if (typeof value === "object" && value !== null) { const record = value as Record; return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`; } return JSON.stringify(value) ?? "null"; } diff --git a/packages/paperclip-runner/src/semantic-tools/discovery.ts b/packages/paperclip-runner/src/semantic-tools/discovery.ts index 499347e7de2..0ff30e281f6 100644 --- a/packages/paperclip-runner/src/semantic-tools/discovery.ts +++ b/packages/paperclip-runner/src/semantic-tools/discovery.ts @@ -39,6 +39,42 @@ export const CAPABILITY_DISCOVERY_NAMESPACES = Object.freeze([ { name: "continuation", description: "Schedule a bounded continuation wake." }, ]); +export const CAPABILITY_DISCOVERY_GATEWAY_DEFINITIONS = Object.freeze([{ + name: "discover_capabilities", + title: "Discover optional capabilities", + description: `Search authorized optional Paperclip capabilities. Namespaces: ${CAPABILITY_DISCOVERY_NAMESPACES.map((item) => `${item.name} (${item.description})`).join("; ")}`, + inputSchema: { + type: "object", properties: { + query: { type: "string", minLength: 1, maxLength: 500 }, + namespace: { type: "string" }, + limit: { type: "integer", minimum: 1, maximum: 8 }, + }, required: ["query"], additionalProperties: false, + }, + outputSchema: { + type: "object", properties: { + schema: { const: "paperclip.capability-discovery.v1" }, + query: { type: "string" }, namespace: { type: ["string", "null"] }, + operations: { type: "array", items: { type: "object", additionalProperties: true } }, + truncated: { type: "boolean" }, + }, required: ["schema", "query", "namespace", "operations", "truncated"], additionalProperties: false, + }, +}, { + name: "invoke_discovered_capability", + title: "Invoke a discovered capability", + description: "Invoke one optional Paperclip operation returned by discover_capabilities. Authority is rechecked at invocation.", + inputSchema: { + type: "object", properties: { + operationId: { type: "string" }, input: { type: "object", additionalProperties: true }, + }, required: ["operationId", "input"], additionalProperties: false, + }, + outputSchema: { + type: "object", properties: { + success: { type: "boolean" }, + contentItems: { type: "array", items: { type: "object", additionalProperties: true } }, + }, required: ["success", "contentItems"], additionalProperties: false, + }, +}] as const); + export function capabilityToolNamespace(operationId: CapabilitySemanticOperationId): string { return NAMESPACE[operationId]; } diff --git a/packages/paperclip-runner/src/tools/capability-semantic-tool-catalog.ts b/packages/paperclip-runner/src/tools/capability-semantic-tool-catalog.ts index e6aad90919c..f4113ebc098 100644 --- a/packages/paperclip-runner/src/tools/capability-semantic-tool-catalog.ts +++ b/packages/paperclip-runner/src/tools/capability-semantic-tool-catalog.ts @@ -1,383 +1,12 @@ -import { - capabilityCanonicalOperationsForSurface, - type CapabilityCanonicalOperation, -} from "../catalog/canonical-operations.js"; -import type { - CapabilityJsonSchema, - CapabilityMockCommandMapping, - CapabilityOptionalCatalogGroup, - CapabilityRedactionRule, - CapabilitySemanticToolDescriptor, -} from "./capability-semantic-tool-types.js"; - -// --------------------------------------------------------------------------- -// This catalog no longer declares an independent operation list. Placement, -// required claims, task modes, allowed roles, side-effect class, idempotency, -// and optional-group membership are single-sourced from -// `src/catalog/canonical-operations.ts` (PAP-17039). This module supplies only -// the scenario-surface *presentation*: title, description, input schema, the -// abstract mock-command mapping, and any redaction rules. -// --------------------------------------------------------------------------- - -const RESULT_SCHEMA = objectSchema({ - schema: stringSchema({ enum: ["paperclip.capability.tool-result.v1"] }), - ok: { type: "boolean" }, - operationId: stringSchema({ minLength: 1 }), - operationResultId: stringSchema({ minLength: 1 }), - value: {}, - commandResult: {}, - authorization: {}, -}, ["schema", "ok", "operationId", "operationResultId", "value", "commandResult", "authorization"]); -const SECRET_REDACTION: CapabilityRedactionRule[] = [ - { - path: "$.value", - replacement: "[SECRET_VALUE]", - appliesTo: ["output", "error", "authorization_record"], - }, -]; -const AUTH_REDACTION: CapabilityRedactionRule[] = [ - { - path: "$.headers.authorization", - replacement: "[REDACTED]", - appliesTo: ["input", "output", "error", "authorization_record"], - }, - { - path: "$.headers.cookie", - replacement: "[REDACTED]", - appliesTo: ["input", "output", "error", "authorization_record"], - }, -]; - -function stringSchema(options: Partial = {}): CapabilityJsonSchema { - return { type: "string", ...options }; -} - -function arraySchema(items: CapabilityJsonSchema): CapabilityJsonSchema { - return { type: "array", items }; -} - -function objectSchema( - properties: Record, - required: string[] = [], -): CapabilityJsonSchema { - return { type: "object", properties, required, additionalProperties: false }; -} - -/** Per-operation scenario presentation, keyed by canonical operation id. */ -interface ScenarioPresentation { - /** Bespoke title; optional tools default to a title derived from the id. */ - readonly title?: string; - /** Bespoke description; optional tools default to a group-scoped sentence. */ - readonly description?: string; - readonly inputSchema: CapabilityJsonSchema; - readonly mockCommandMapping: CapabilityMockCommandMapping; - readonly redaction?: CapabilityRedactionRule[]; -} - -const PRESENTATION: Readonly> = { - // --- always tools (bespoke titles/descriptions) --- - get_task_context: { - title: "Get task context", - description: "Read the active task, ancestors, wake context, linked results, and budget summary.", - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "context_read", projection: "active_task" }, - }, - get_task_history: { - title: "Get task history", - description: "Read comments and audit-visible history for the active task only.", - inputSchema: objectSchema({ limit: { type: "integer", minimum: 1 } }), - mockCommandMapping: { kind: "snapshot_read", projection: "active_task_history" }, - }, - list_documents: { - title: "List task documents", - description: "List document metadata attached to the active task.", - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "snapshot_read", projection: "active_task_documents" }, - }, - read_document: { - title: "Read task document", - description: "Read one document on the active task by stable key.", - inputSchema: objectSchema({ key: stringSchema({ minLength: 1 }) }, ["key"]), - mockCommandMapping: { kind: "snapshot_read", projection: "active_task_document" }, - }, - list_document_revisions: { - title: "List document revisions", - description: "Inspect revision history for one active-task document.", - inputSchema: objectSchema({ key: stringSchema({ minLength: 1 }) }, ["key"]), - mockCommandMapping: { kind: "snapshot_read", projection: "active_task_document_revisions" }, - }, - report_progress: { - title: "Report progress", - description: "Append a durable progress update to the active task.", - inputSchema: objectSchema({ body: stringSchema({ minLength: 1 }) }, ["body"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "report_progress" }, - }, - answer_status_question: { - title: "Answer status question", - description: "Post an answer to a status question without changing task state.", - inputSchema: objectSchema({ body: stringSchema({ minLength: 1 }) }, ["body"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "report_progress" }, - }, - finish_task: { - title: "Finish task", - description: "Finish the active task with a durable completion summary.", - inputSchema: objectSchema({ summary: stringSchema({ minLength: 1 }) }, ["summary"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "finish_task" }, - }, - block_task: { - title: "Block task", - description: "Block the active task with a reason and optional first-class dependencies.", - inputSchema: objectSchema({ - reason: stringSchema({ minLength: 1 }), - blockedByTaskIds: arraySchema(stringSchema({ minLength: 1 })), - }, ["reason"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "block_task" }, - }, - request_review: { - title: "Request task review", - description: "Move the active task to review with a durable summary.", - inputSchema: objectSchema({ summary: stringSchema({ minLength: 1 }) }, ["summary"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "request_review" }, - }, - write_document: { - title: "Write task document", - description: "Create or revision-safely update an active-task document.", - inputSchema: objectSchema({ - key: stringSchema({ minLength: 1 }), - title: stringSchema({ minLength: 1 }), - body: stringSchema(), - baseRevisionId: { oneOf: [stringSchema({ minLength: 1 }), { type: "null" }] }, - changeSummary: stringSchema(), - }, ["key", "title", "body", "baseRevisionId"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "write_document" }, - }, - request_human_input: { - title: "Request human input", - description: "Create a typed confirmation, checkbox, question, task suggestion, or item-verdict request.", - inputSchema: objectSchema({ - interactionKind: stringSchema({ enum: ["confirmation", "checkbox", "questions", "suggest_tasks", "item_verdicts"] }), - title: stringSchema({ minLength: 1 }), - prompt: stringSchema({ minLength: 1 }), - payload: {}, - targetRevisionId: { oneOf: [stringSchema({ minLength: 1 }), { type: "null" }] }, - continuationPolicy: stringSchema({ enum: ["none", "wake_assignee", "wake_assignee_on_accept"] }), - }, ["interactionKind", "title", "prompt", "continuationPolicy"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "request_human_input" }, - }, - register_deliverable: { - title: "Register deliverable", - description: "Register an inspectable artifact and its work product on the active task.", - inputSchema: objectSchema({ - filename: stringSchema({ minLength: 1 }), - contentType: stringSchema({ minLength: 1 }), - byteSize: { type: "integer", minimum: 0 }, - sha256: stringSchema({ minLength: 1 }), - contentRef: stringSchema({ minLength: 1 }), - title: stringSchema({ minLength: 1 }), - }, ["filename", "contentType", "byteSize", "sha256", "contentRef", "title"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "register_deliverable" }, - }, - inspect_operation_result: { - title: "Inspect operation result", - description: "Read a prior semantic operation result from this run.", - inputSchema: objectSchema({ operationResultId: stringSchema({ minLength: 1 }) }, ["operationResultId"]), - mockCommandMapping: { kind: "operation_result" }, - }, - - // --- optional tools (title/description derived from id + group) --- - search_tasks: { - inputSchema: objectSchema({ query: stringSchema(), status: stringSchema() }), - mockCommandMapping: { kind: "snapshot_read", projection: "company_tasks" }, - }, - list_agents: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "snapshot_read", projection: "company_actors" }, - }, - list_projects: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "discovery.projects" }, - }, - list_goals: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "discovery.goals" }, - }, - create_task: { - inputSchema: objectSchema({ - title: stringSchema({ minLength: 1 }), - description: stringSchema(), - assigneeActorId: stringSchema(), - priority: stringSchema(), - blockedByTaskIds: arraySchema(stringSchema()), - }, ["title"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "create_task" }, - }, - set_dependencies: { - inputSchema: objectSchema({ blockedByTaskIds: arraySchema(stringSchema({ minLength: 1 })) }, ["blockedByTaskIds"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "set_dependencies" }, - }, - list_approvals: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "snapshot_read", projection: "company_approvals" }, - }, - request_approval: { - inputSchema: objectSchema({ approvalType: stringSchema({ minLength: 1 }), payload: {} }, ["approvalType", "payload"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "request_approval" }, - }, - decide_approval: { - inputSchema: objectSchema({ - approvalId: stringSchema({ minLength: 1 }), - decision: stringSchema({ enum: ["approved", "rejected", "cancelled"] }), - note: stringSchema({ minLength: 1 }), - }, ["approvalId", "decision", "note"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "decide_approval" }, - }, - comment_on_approval: { - inputSchema: objectSchema({ approvalId: stringSchema({ minLength: 1 }), body: stringSchema({ minLength: 1 }) }, ["approvalId", "body"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "comment_on_approval" }, - }, - list_cases: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "cases.list" }, - }, - upsert_case: { - inputSchema: objectSchema({ key: stringSchema({ minLength: 1 }), body: stringSchema() }, ["key", "body"]), - mockCommandMapping: { kind: "mock_extension", extension: "cases.upsert" }, - }, - get_workspace_runtime: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "snapshot_read", projection: "active_task_workspace" }, - }, - control_workspace_service: { - inputSchema: objectSchema({ - serviceId: stringSchema({ minLength: 1 }), - action: stringSchema({ enum: ["start", "stop", "fail"] }), - url: stringSchema(), - }, ["serviceId", "action"]), - mockCommandMapping: { kind: "semantic_command", commandKind: "control_workspace_service" }, - }, - list_routines: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "routines.list" }, - }, - manage_routine: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "routines.manage" }, - }, - list_company_skills: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "company_skills.list" }, - }, - sync_company_skills: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "company_skills.sync" }, - }, - list_secret_metadata: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "secrets.metadata" }, - }, - read_secret_value: { - inputSchema: objectSchema({ name: stringSchema({ minLength: 1 }) }, ["name"]), - mockCommandMapping: { kind: "mock_extension", extension: "secrets.value" }, - redaction: [...SECRET_REDACTION], - }, - export_company: { - inputSchema: objectSchema({}), - mockCommandMapping: { kind: "mock_extension", extension: "portability.export" }, - }, - administer_company: { - inputSchema: objectSchema({ action: stringSchema({ minLength: 1 }), payload: {} }, ["action"]), - mockCommandMapping: { kind: "mock_extension", extension: "company.admin" }, - }, - generic_api_request: { - inputSchema: objectSchema({ - method: stringSchema({ minLength: 1 }), - path: stringSchema({ minLength: 1 }), - headers: { type: "object", additionalProperties: stringSchema() }, - body: {}, - }, ["method", "path"]), - mockCommandMapping: { kind: "mock_extension", extension: "test.generic_api" }, - redaction: [...AUTH_REDACTION], - }, -}; - -function titleFor(operationId: string): string { - return operationId.split("_").map((part) => part[0]!.toUpperCase() + part.slice(1)).join(" "); -} - -function descriptionFor(title: string, group: CapabilityOptionalCatalogGroup): string { - return `${title} through the Capability ${group.replaceAll("_", " ")} capability set.`; -} - -function toDescriptor(operation: CapabilityCanonicalOperation): CapabilitySemanticToolDescriptor { - const presentation = PRESENTATION[operation.operationId]; - if (presentation === undefined) { - throw new Error(`Missing scenario presentation for operation ${operation.operationId}.`); - } - const title = presentation.title ?? titleFor(operation.operationId); - const description = presentation.description - ?? descriptionFor(title, operation.optionalGroup ?? "discovery"); - return Object.freeze({ - operationId: operation.operationId, - version: 1, - title, - description, - inputSchema: presentation.inputSchema, - outputSchema: RESULT_SCHEMA, - disposition: operation.placement, - optionalGroup: operation.optionalGroup, - requiredClaims: [...operation.requiredClaims], - ...(operation.allowedRoles === undefined ? {} : { allowedRoles: [...operation.allowedRoles] }), - taskModes: [...operation.taskModes], - sideEffectClass: operation.sideEffectClass, - idempotency: operation.idempotency, - redaction: presentation.redaction ?? [], - mockCommandMapping: presentation.mockCommandMapping, - }); -} - -const SCENARIO_OPERATIONS = capabilityCanonicalOperationsForSurface("scenario"); -const canonicalById = new Map(SCENARIO_OPERATIONS.map((operation) => [operation.operationId, operation])); - -// Bidirectional parity: every presented operation is a canonical scenario-surface -// operation, and every canonical scenario-surface operation has a presentation. -for (const key of Object.keys(PRESENTATION)) { - if (!canonicalById.has(key)) { - throw new Error(`Scenario presentation ${key} is not a canonical scenario-surface operation.`); - } -} -for (const operation of SCENARIO_OPERATIONS) { - if (PRESENTATION[operation.operationId] === undefined) { - throw new Error(`Canonical scenario operation ${operation.operationId} has no scenario presentation.`); - } -} - -// Declaration order follows the presentation map so the exported surface stays -// stable; the operation set itself is single-sourced from the canonical list. -export const CAPABILITY_SEMANTIC_TOOL_CATALOG: readonly CapabilitySemanticToolDescriptor[] = Object.freeze( - Object.keys(PRESENTATION).map((operationId) => toDescriptor(canonicalById.get(operationId)!)), -); - -export const CAPABILITY_OPTIONAL_TOOL_CATALOGS: Readonly< - Record -> = Object.freeze({ - discovery: toolsInGroup("discovery"), - delegation_dependencies: toolsInGroup("delegation_dependencies"), - governance: toolsInGroup("governance"), - cases: toolsInGroup("cases"), - workspace_runtime: toolsInGroup("workspace_runtime"), - routines: toolsInGroup("routines"), - company_skills: toolsInGroup("company_skills"), - secrets: toolsInGroup("secrets"), - portability_admin: toolsInGroup("portability_admin"), - test_escape_hatch: toolsInGroup("test_escape_hatch"), +/** Scenario/eval projection of the per-action protocol definitions. */ +import { PAPERCLIP_PROTOCOL_ACTIONS } from "../protocol-actions/index.js"; +import type { CapabilityOptionalCatalogGroup, CapabilitySemanticToolDescriptor } from "./capability-semantic-tool-types.js"; +const descriptors = PAPERCLIP_PROTOCOL_ACTIONS.filter((action) => action.scenario !== null) + .sort((left, right) => left.scenario!.order - right.scenario!.order) + .map((action) => action.scenario!.descriptor as unknown as CapabilitySemanticToolDescriptor); +export const CAPABILITY_SEMANTIC_TOOL_CATALOG: readonly CapabilitySemanticToolDescriptor[] = Object.freeze(descriptors); +export const CAPABILITY_OPTIONAL_TOOL_CATALOGS: Readonly> = Object.freeze({ + discovery: toolsInGroup("discovery"), delegation_dependencies: toolsInGroup("delegation_dependencies"), governance: toolsInGroup("governance"), cases: toolsInGroup("cases"), workspace_runtime: toolsInGroup("workspace_runtime"), routines: toolsInGroup("routines"), company_skills: toolsInGroup("company_skills"), secrets: toolsInGroup("secrets"), portability_admin: toolsInGroup("portability_admin"), test_escape_hatch: toolsInGroup("test_escape_hatch"), }); - -export function capabilitySemanticTool(operationId: string): CapabilitySemanticToolDescriptor | undefined { - return CAPABILITY_SEMANTIC_TOOL_CATALOG.find((tool) => tool.operationId === operationId); -} - -function toolsInGroup(group: CapabilityOptionalCatalogGroup): readonly CapabilitySemanticToolDescriptor[] { - return Object.freeze( - CAPABILITY_SEMANTIC_TOOL_CATALOG.filter((tool) => tool.optionalGroup === group), - ); -} +export function capabilitySemanticTool(operationId: string): CapabilitySemanticToolDescriptor | undefined { return CAPABILITY_SEMANTIC_TOOL_CATALOG.find((tool) => tool.operationId === operationId); } +function toolsInGroup(group: CapabilityOptionalCatalogGroup): readonly CapabilitySemanticToolDescriptor[] { return Object.freeze(CAPABILITY_SEMANTIC_TOOL_CATALOG.filter((tool) => tool.optionalGroup === group)); }