mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-26 10:26:26 +01:00
## Thinking Path > - The runner already persists PRP events, but provider-native activity needs one bounded, provider-neutral vocabulary before additional providers can be added safely. > - The protocol catalog must describe capabilities without enabling or authorizing a provider. > - Provider normalization must not require an ACPX runtime dependency merely to compile the shared event layer. > - This pull request adds the event contract and pure normalizers only; provider transports and production selection remain unchanged. ## Linked Issues or Issue Description This is the first follow-up stacked on #12321. Codex, OpenCode, and ACP runtimes expose different activity shapes. Without canonical normalization, downstream task threads and traces would need provider-specific branching and could retain unbounded or unsafe payloads. ## What Changed - Expand the PRP provider descriptor and canonical activity event families. - Add bounded Codex, OpenCode, and ACP event normalizers for plans, tools, research, delegation, artifacts, review, safety, waits, and notices. - Preserve strict schema validation and regenerate the checked-in schema bundle and manifest. - Use a structural ACP event input so the provider-neutral layer does not introduce or authorize an ACPX runtime dependency. - Export the provider-event contract from the existing package root. ## Verification - `pnpm --filter @paperclipai/paperclip-runner typecheck:typescript` - `pnpm --filter @paperclipai/paperclip-runner test:typescript` — 11 files and 88 tests passed. - `pnpm -r typecheck` - `pnpm build` - `git diff --check` - The local full repository runner reached unrelated macOS workspace-path fixture failures; the affected runner suites pass and the repository CI shards are the handoff authority. - Diff against the declared base: 8 files. ## Compatibility Boundary - No provider transport, adapter, server route, feature flag, or runtime selection changes. - Catalog presence does not authorize discovery or execution. - Existing Codex execution continues through its current path. - No dependency, migration, workflow, or lockfile change. ## Risks The main risk is accepting malformed or unbounded provider payloads. Schema validation remains fail-closed, text/output fields are bounded and redacted, unsafe paths and URLs are discarded, and representative variants for every declared event family are covered by tests. ## Model Used OpenAI Codex, GPT-5 family. The client does not expose the exact deployment ID or context window. Agentic reasoning, tool use, and code execution were enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have described the issue in-PR following the relevant template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal task identifier - [x] I have run the affected local tests and they pass - [x] I have added or updated tests where applicable - [x] I have updated the compatibility notes for this change - [x] I have considered and documented risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open actionable comments - [x] I will address all Greptile and reviewer comments before requesting merge
169 lines
12 KiB
JSON
169 lines
12 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json",
|
|
"title": "Provider-neutral runner activity payload",
|
|
"oneOf": [
|
|
{ "$ref": "#/$defs/plan" },
|
|
{ "$ref": "#/$defs/toolExecution" },
|
|
{ "$ref": "#/$defs/research" },
|
|
{ "$ref": "#/$defs/delegation" },
|
|
{ "$ref": "#/$defs/modelRoute" },
|
|
{ "$ref": "#/$defs/modelVerification" },
|
|
{ "$ref": "#/$defs/contextCompacted" },
|
|
{ "$ref": "#/$defs/artifactViewed" },
|
|
{ "$ref": "#/$defs/artifactGenerated" },
|
|
{ "$ref": "#/$defs/reviewMode" },
|
|
{ "$ref": "#/$defs/hook" },
|
|
{ "$ref": "#/$defs/memoryCitation" },
|
|
{ "$ref": "#/$defs/safetyReview" },
|
|
{ "$ref": "#/$defs/terminalInput" },
|
|
{ "$ref": "#/$defs/wait" },
|
|
{ "$ref": "#/$defs/providerNotice" }
|
|
],
|
|
"$defs": {
|
|
"id": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]*$" },
|
|
"shortText": { "type": "string", "maxLength": 4000 },
|
|
"nullableShortText": { "type": ["string", "null"], "maxLength": 4000 },
|
|
"safePath": { "type": ["string", "null"], "maxLength": 4096, "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).*$" },
|
|
"safeUrl": { "type": ["string", "null"], "maxLength": 8192, "pattern": "^https?://" },
|
|
"plan": {
|
|
"type": "object",
|
|
"description": "A complete provider-authored within-turn checklist snapshot. Consumers replace the prior snapshot with the same planId in PRP sourceSeq order; this is not Paperclip's durable Plan document.",
|
|
"required": ["schema", "planId", "revision", "steps", "complete", "syncStatus"],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.plan.updated.v1" },
|
|
"planId": { "$ref": "#/$defs/id" },
|
|
"revision": { "type": "integer", "minimum": 1 },
|
|
"explanation": { "$ref": "#/$defs/nullableShortText" },
|
|
"steps": { "type": "array", "maxItems": 256, "items": { "type": "object", "required": ["stepId", "body", "status"], "properties": { "stepId": { "$ref": "#/$defs/id" }, "body": { "$ref": "#/$defs/shortText" }, "status": { "enum": ["pending", "in_progress", "completed", "blocked"] } }, "additionalProperties": false } },
|
|
"complete": { "type": "boolean" },
|
|
"syncStatus": { "description": "Legacy compatibility field. Within-turn checklist snapshots use not_applicable.", "enum": ["streaming", "pending", "synchronized", "conflict", "not_applicable"] },
|
|
"documentRevision": { "description": "Legacy compatibility field. Within-turn checklist snapshots use null.", "type": ["integer", "null"], "minimum": 1 }
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"toolExecution": {
|
|
"type": "object",
|
|
"required": ["schema", "executionId", "transport", "operation", "status", "output", "outputBytes", "outputTruncated", "outputDigest"],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.tool.execution.v1" },
|
|
"executionId": { "$ref": "#/$defs/id" },
|
|
"transport": { "enum": ["process", "mcp", "dynamic", "builtin"] },
|
|
"operation": { "enum": ["read", "search", "list", "execute", "edit", "unknown"] },
|
|
"name": { "$ref": "#/$defs/nullableShortText" },
|
|
"target": { "$ref": "#/$defs/safePath" },
|
|
"namespace": { "type": ["string", "null"], "maxLength": 240 },
|
|
"readOnly": { "type": ["boolean", "null"] },
|
|
"status": { "enum": ["running", "completed", "failed", "cancelled", "interrupted"] },
|
|
"durationMs": { "type": ["integer", "null"], "minimum": 0 },
|
|
"exitCode": { "type": ["integer", "null"] },
|
|
"progress": { "$ref": "#/$defs/nullableShortText" },
|
|
"output": { "type": ["string", "null"], "maxLength": 65536 },
|
|
"outputBytes": { "type": "integer", "minimum": 0 },
|
|
"outputTruncated": { "type": "boolean" },
|
|
"outputDigest": { "type": ["string", "null"], "pattern": "^sha256:[a-f0-9]{64}$" }
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"research": {
|
|
"type": "object",
|
|
"required": ["schema", "researchId", "action", "status", "sources"],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.research.v1" },
|
|
"researchId": { "$ref": "#/$defs/id" },
|
|
"action": { "enum": ["search", "open_page", "find_in_page", "other"] },
|
|
"status": { "enum": ["running", "completed", "failed", "cancelled"] },
|
|
"query": { "$ref": "#/$defs/nullableShortText" },
|
|
"url": { "$ref": "#/$defs/safeUrl" },
|
|
"pattern": { "$ref": "#/$defs/nullableShortText" },
|
|
"sources": { "type": "array", "maxItems": 64, "items": { "type": "object", "required": ["sourceId", "title", "url", "snippet"], "properties": { "sourceId": { "$ref": "#/$defs/id" }, "title": { "$ref": "#/$defs/shortText" }, "url": { "$ref": "#/$defs/safeUrl" }, "snippet": { "$ref": "#/$defs/nullableShortText" } }, "additionalProperties": false } }
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"delegation": {
|
|
"type": "object",
|
|
"required": ["schema", "delegationId", "action", "status", "children"],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.delegation.v1" },
|
|
"delegationId": { "$ref": "#/$defs/id" },
|
|
"action": { "enum": ["spawn", "message", "resume", "wait", "close"] },
|
|
"status": { "enum": ["running", "waiting", "completed", "failed", "interrupted", "closed"] },
|
|
"children": { "type": "array", "maxItems": 64, "items": { "type": "object", "required": ["childId", "role", "model", "status", "summary", "activitySummary"], "properties": { "childId": { "$ref": "#/$defs/id" }, "role": { "type": ["string", "null"], "maxLength": 160 }, "model": { "type": ["string", "null"], "maxLength": 240 }, "status": { "enum": ["running", "waiting", "completed", "failed", "interrupted", "closed"] }, "summary": { "$ref": "#/$defs/nullableShortText" }, "activitySummary": { "$ref": "#/$defs/nullableShortText" } }, "additionalProperties": false } }
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"modelRoute": {
|
|
"type": "object",
|
|
"required": ["schema", "routeId", "provider", "requestedModel", "fromModel", "effectiveModel", "reason"],
|
|
"properties": { "schema": { "const": "paperclip.model.route_changed.v1" }, "routeId": { "$ref": "#/$defs/id" }, "provider": { "type": "string", "minLength": 1, "maxLength": 160 }, "requestedModel": { "type": "string", "minLength": 1, "maxLength": 240 }, "fromModel": { "type": ["string", "null"], "maxLength": 240 }, "effectiveModel": { "type": "string", "minLength": 1, "maxLength": 240 }, "reason": { "$ref": "#/$defs/shortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"modelVerification": {
|
|
"type": "object",
|
|
"required": ["schema", "verificationId", "status", "classes", "buffering", "summary"],
|
|
"properties": { "schema": { "const": "paperclip.model.verification.v1" }, "verificationId": { "$ref": "#/$defs/id" }, "status": { "enum": ["running", "completed", "failed"] }, "classes": { "type": "array", "maxItems": 32, "items": { "type": "string", "maxLength": 160 } }, "buffering": { "type": "boolean" }, "summary": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"contextCompacted": {
|
|
"type": "object",
|
|
"required": ["schema", "compactionId", "reason", "preTokens", "postTokens", "sameSession"],
|
|
"properties": { "schema": { "const": "paperclip.context.compacted.v1" }, "compactionId": { "$ref": "#/$defs/id" }, "reason": { "enum": ["context_window", "manual", "provider", "unknown"] }, "preTokens": { "type": ["integer", "null"], "minimum": 0 }, "postTokens": { "type": ["integer", "null"], "minimum": 0 }, "sameSession": { "type": "boolean" } },
|
|
"additionalProperties": false
|
|
},
|
|
"artifactViewed": {
|
|
"type": "object",
|
|
"required": ["schema", "artifactId", "reference", "mediaType", "title"],
|
|
"properties": { "schema": { "const": "paperclip.artifact.viewed.v1" }, "artifactId": { "$ref": "#/$defs/id" }, "reference": { "$ref": "#/$defs/safePath" }, "mediaType": { "type": ["string", "null"], "maxLength": 160 }, "title": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"artifactGenerated": {
|
|
"type": "object",
|
|
"required": ["schema", "artifactId", "status", "reference", "mediaType", "registered", "failure"],
|
|
"properties": { "schema": { "const": "paperclip.artifact.generated.v1" }, "artifactId": { "$ref": "#/$defs/id" }, "status": { "enum": ["running", "completed", "failed"] }, "reference": { "$ref": "#/$defs/safePath" }, "mediaType": { "type": ["string", "null"], "maxLength": 160 }, "registered": { "type": "boolean" }, "transparentBackground": { "type": ["boolean", "null"] }, "failure": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"reviewMode": {
|
|
"type": "object",
|
|
"required": ["schema", "reviewId", "state", "scope"],
|
|
"properties": { "schema": { "const": "paperclip.review.mode_changed.v1" }, "reviewId": { "$ref": "#/$defs/id" }, "state": { "enum": ["entered", "exited"] }, "scope": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"hook": {
|
|
"type": "object",
|
|
"required": ["schema", "hookId", "event", "scope", "status", "blocking", "durationMs", "summary"],
|
|
"properties": { "schema": { "const": "paperclip.hook.v1" }, "hookId": { "$ref": "#/$defs/id" }, "event": { "type": "string", "minLength": 1, "maxLength": 160 }, "scope": { "type": "string", "minLength": 1, "maxLength": 160 }, "status": { "enum": ["running", "completed", "failed", "cancelled"] }, "blocking": { "type": "boolean" }, "durationMs": { "type": ["integer", "null"], "minimum": 0 }, "summary": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"memoryCitation": {
|
|
"type": "object",
|
|
"required": ["schema", "citationId", "messageItemId", "label", "available", "reference"],
|
|
"properties": { "schema": { "const": "paperclip.memory.citation.v1" }, "citationId": { "$ref": "#/$defs/id" }, "messageItemId": { "$ref": "#/$defs/id" }, "label": { "$ref": "#/$defs/shortText" }, "available": { "type": "boolean" }, "reference": { "type": ["string", "null"], "maxLength": 4096 } },
|
|
"additionalProperties": false
|
|
},
|
|
"safetyReview": {
|
|
"type": "object",
|
|
"required": ["schema", "reviewId", "targetExecutionId", "status", "decision", "summary"],
|
|
"properties": { "schema": { "const": "paperclip.safety.review.v1" }, "reviewId": { "$ref": "#/$defs/id" }, "targetExecutionId": { "anyOf": [{ "$ref": "#/$defs/id" }, { "type": "null" }] }, "status": { "enum": ["running", "completed", "failed"] }, "decision": { "enum": ["pending", "allowed", "denied", "user_required", "unknown"] }, "summary": { "$ref": "#/$defs/nullableShortText" } },
|
|
"additionalProperties": false
|
|
},
|
|
"terminalInput": {
|
|
"type": "object",
|
|
"required": ["schema", "executionId", "origin", "inputClass", "byteCount"],
|
|
"properties": { "schema": { "const": "paperclip.terminal.input_sent.v1" }, "executionId": { "$ref": "#/$defs/id" }, "origin": { "enum": ["agent", "user", "system"] }, "inputClass": { "enum": ["text", "control", "eof"] }, "byteCount": { "type": "integer", "minimum": 0 } },
|
|
"additionalProperties": false
|
|
},
|
|
"wait": {
|
|
"type": "object",
|
|
"required": ["schema", "waitId", "reason", "status", "plannedDurationMs", "elapsedDurationMs"],
|
|
"properties": { "schema": { "const": "paperclip.wait.v1" }, "waitId": { "$ref": "#/$defs/id" }, "reason": { "enum": ["timer", "provider", "rate_limit", "unknown"] }, "status": { "enum": ["running", "completed", "interrupted", "cancelled"] }, "plannedDurationMs": { "type": ["integer", "null"], "minimum": 0 }, "elapsedDurationMs": { "type": ["integer", "null"], "minimum": 0 } },
|
|
"additionalProperties": false
|
|
},
|
|
"providerNotice": {
|
|
"type": "object",
|
|
"required": ["schema", "noticeId", "severity", "category", "scope", "recoverable", "userActionable", "summary"],
|
|
"properties": { "schema": { "const": "paperclip.provider.notice.v1" }, "noticeId": { "$ref": "#/$defs/id" }, "severity": { "enum": ["info", "warning", "error"] }, "category": { "type": "string", "minLength": 1, "maxLength": 160 }, "scope": { "enum": ["turn", "session", "environment", "account"] }, "recoverable": { "type": "boolean" }, "userActionable": { "type": "boolean" }, "summary": { "$ref": "#/$defs/shortText" } },
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|