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 0000000000..61a4033b14 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts @@ -0,0 +1,234 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "answer_status_question", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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 0000000000..a292e8763c --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/block-task.ts @@ -0,0 +1,245 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "block_task", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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/core-contracts.test.ts b/packages/paperclip-runner/src/protocol-actions/core-contracts.test.ts new file mode 100644 index 0000000000..d3bb1eaae7 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/core-contracts.test.ts @@ -0,0 +1,61 @@ +import Ajv2020 from "ajv/dist/2020.js"; +import { describe, expect, it } from "vitest"; + +import { PAPERCLIP_CORE_PROTOCOL_ACTIONS } from "./core.js"; + +describe("core Paperclip protocol action contracts", () => { + const ajv = new Ajv2020({ allErrors: true, allowUnionTypes: true, strict: false }); + + it.each(PAPERCLIP_CORE_PROTOCOL_ACTIONS.map((action) => [action.id, action] as const))( + "%s has immutable metadata and schema-valid examples", + (operationId, action) => { + expect(action.canonical.operationId).toBe(operationId); + expect(action.canonical.placement).toBe("always_agent_tool"); + expect(action.examples.call.operationId).toBe(operationId); + expect(action.examples.success.operationId).toBe(operationId); + expect(Object.isFrozen(action)).toBe(true); + expect(Object.isFrozen(action.canonical)).toBe(true); + + expect(action.live !== null || action.scenario !== null).toBe(true); + + if (action.live !== null) { + expect( + ajv.validate(action.live.descriptor.inputSchema, action.examples.call.input), + JSON.stringify(ajv.errors), + ).toBe(true); + expect( + ajv.validate(action.live.descriptor.outputSchema, action.examples.success.result), + JSON.stringify(ajv.errors), + ).toBe(true); + } + + if (action.scenario !== null) { + expect(action.scenario.successExample.operationId).toBe(operationId); + const scenarioProperties = action.scenario.descriptor.inputSchema.properties ?? {}; + const callEntries = Object.entries(action.examples.call.input); + const outOfBandKeys = callEntries + .map(([key]) => key) + .filter((key) => !(key in scenarioProperties)); + // Scenario mutation idempotency is carried by the invocation envelope, + // not the operation input. No other example field may be omitted. + expect(outOfBandKeys).toEqual( + "idempotencyKey" in action.examples.call.input ? ["idempotencyKey"] : [], + ); + const scenarioInput = Object.fromEntries( + callEntries.filter(([key]) => key !== "idempotencyKey"), + ); + expect( + ajv.validate(action.scenario.descriptor.inputSchema, scenarioInput), + JSON.stringify(ajv.errors), + ).toBe(true); + expect( + ajv.validate( + action.scenario.descriptor.outputSchema, + action.scenario.successExample, + ), + JSON.stringify(ajv.errors), + ).toBe(true); + } + }, + ); +}); diff --git a/packages/paperclip-runner/src/protocol-actions/core.ts b/packages/paperclip-runner/src/protocol-actions/core.ts new file mode 100644 index 0000000000..ee19581527 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/core.ts @@ -0,0 +1,33 @@ +import { answerStatusQuestionAction } from "./answer-status-question.js"; +import { blockTaskAction } from "./block-task.js"; +import { finishTaskAction } from "./finish-task.js"; +import { getTaskContextAction } from "./get-task-context.js"; +import { getTaskHistoryAction } from "./get-task-history.js"; +import { inspectOperationResultAction } from "./inspect-operation-result.js"; +import { listDocumentRevisionsAction } from "./list-document-revisions.js"; +import { listDocumentsAction } from "./list-documents.js"; +import { readDocumentAction } from "./read-document.js"; +import { registerDeliverableAction } from "./register-deliverable.js"; +import { reportProgressAction } from "./report-progress.js"; +import { requestHumanInputAction } from "./request-human-input.js"; +import { requestReviewAction } from "./request-review.js"; +import { writeDocumentAction } from "./write-document.js"; +import { deepFreezeProtocolAction } from "./freeze.js"; + +/** Core actions that are always present in an authorized runner projection. */ +export const PAPERCLIP_CORE_PROTOCOL_ACTIONS = deepFreezeProtocolAction([ + answerStatusQuestionAction, + blockTaskAction, + finishTaskAction, + getTaskContextAction, + getTaskHistoryAction, + inspectOperationResultAction, + listDocumentRevisionsAction, + listDocumentsAction, + readDocumentAction, + registerDeliverableAction, + reportProgressAction, + requestHumanInputAction, + requestReviewAction, + writeDocumentAction, +] 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 0000000000..3f9ab66926 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/finish-task.ts @@ -0,0 +1,228 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "finish_task", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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/freeze.ts b/packages/paperclip-runner/src/protocol-actions/freeze.ts new file mode 100644 index 0000000000..20765838fa --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/freeze.ts @@ -0,0 +1,9 @@ +export function deepFreezeProtocolAction(value: T): T { + if (value !== null && typeof value === "object" && !Object.isFrozen(value)) { + for (const nested of Object.values(value as Record)) { + deepFreezeProtocolAction(nested); + } + Object.freeze(value); + } + return value; +} 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 0000000000..8b6dae57d6 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-task-context.ts @@ -0,0 +1,149 @@ +/** 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": "PaperclipRunnerToolAuthority active issue/run + accepted plan revision", + "prpEvidence": "bound company/assignment query plus exact accepted document revision projection", + "prpBindingStatus": "bound", + "legacyAliases": [ + "mcp:paperclipMe" + ] + }, + "documentation": { + "title": "Get active task context", + "description": "Read the active task and actor, including the exact approved Markdown revision when this issue has an accepted plan.", + "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 task and actor, including the exact approved Markdown revision when this issue has an accepted plan.", + "exposure": "always", + "requiredClaims": [], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 0, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "get_task_context", + "operationResultId": "example-result", + "value": {}, + "commandResult": null, + "authorization": {} + }, + "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 0000000000..15acbdbabf --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-task-history.ts @@ -0,0 +1,159 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "get_task_history", + "operationResultId": "example-result", + "value": {}, + "commandResult": null, + "authorization": {} + }, + "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/inspect-operation-result.ts b/packages/paperclip-runner/src/protocol-actions/inspect-operation-result.ts new file mode 100644 index 0000000000..fc3c04f915 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/inspect-operation-result.ts @@ -0,0 +1,136 @@ +/** 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": "inspect_operation_result", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 13, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "inspect_operation_result", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + }, + "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-document-revisions.ts b/packages/paperclip-runner/src/protocol-actions/list-document-revisions.ts new file mode 100644 index 0000000000..3f9853bcba --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-document-revisions.ts @@ -0,0 +1,171 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "list_document_revisions", + "operationResultId": "example-result", + "value": {}, + "commandResult": null, + "authorization": {} + }, + "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 0000000000..2dce5dd540 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-documents.ts @@ -0,0 +1,147 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "list_documents", + "operationResultId": "example-result", + "value": {}, + "commandResult": null, + "authorization": {} + }, + "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/read-document.ts b/packages/paperclip-runner/src/protocol-actions/read-document.ts new file mode 100644 index 0000000000..b78f3d1bed --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/read-document.ts @@ -0,0 +1,165 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "read_document", + "operationResultId": "example-result", + "value": {}, + "commandResult": null, + "authorization": {} + }, + "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/register-deliverable.ts b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts new file mode 100644 index 0000000000..040f3477db --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts @@ -0,0 +1,293 @@ +/** 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": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "register_deliverable", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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 0000000000..f562c73f6e --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/report-progress.ts @@ -0,0 +1,236 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "report_progress", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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-human-input.ts b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts new file mode 100644 index 0000000000..34081f7d3e --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts @@ -0,0 +1,314 @@ +/** 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", + "ask", + "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", + "ask", + "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", + "description": "Kind-specific interaction data. For interactionKind='questions', use exactly {version:1, questions:[{id,prompt,selectionMode:'single'|'multi',required?,options:[{id,label,description?,freeText?}]}]}; option keys are id/label, not value, and question choice cardinality is selectionMode, not type. For confirmation, payload may be {}. Keep all ids stable across retries.", + "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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "request_human_input", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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": { + "description": "Kind-specific interaction data. Questions use {version:1, questions:[{id,prompt,selectionMode:'single'|'multi',required?,options:[{id,label,description?,freeText?}]}]}; do not use type:'single_choice' or option.value." + }, + "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", + "ask", + "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 0000000000..cb36d25d8d --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/request-review.ts @@ -0,0 +1,228 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "request_review", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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/write-document.ts b/packages/paperclip-runner/src/protocol-actions/write-document.ts new file mode 100644 index 0000000000..2b620352a3 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/write-document.ts @@ -0,0 +1,289 @@ +/** 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, + "successExample": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "write_document", + "operationResultId": "example-result", + "value": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": ["example"], + "scheduledWakeIds": ["example"] + }, + "commandResult": null, + "authorization": {} + }, + "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;