mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 01:27:09 +01:00
## Thinking Path > - Paperclip manages agents and tasks. > - Runner reports durable run events through PRP. > - Runtime clients need a typed record of reported activity. > - The event must keep the normal run authority and read boundaries. > - This pull request adds the generic runtime activity event contract. > - Later PRs can publish and consume this contract without private plugin coupling. ## Linked Issues or Issue Description First feature prerequisite extracted from #18050. Runner publishing is #18050; the dependent consumer is #18131. Related independent test stability work: #18128. The parent search and review history is preserved in [the verification archive](https://github.com/paperclipai/paperclip/pull/18050#issuecomment-6489369676). **Subsystem affected** Runner event protocol, server run-event persistence and redaction, and UI event taxonomy. **Problem or motivation** Core needs a durable, typed activity record tied to the authenticated run. A text marker is not an event contract. **Proposed solution** Add `runtime.activity.recorded` as a P1 event with a closed `{ namespace, activityKey }` payload. Runner knows no plugin or panel identity. Run/session identity, sequence and emission time stay in the outer envelope; Core resolves company, task and agent through the authorized run binding. Use the existing authenticated persistence, acknowledgement, replay and redaction paths. ## What Changed - Define and validate the event in PRP v1, v2 and v3. Update the generated protocol artifacts and event catalog. - Preserve saved and live event redaction. Test persistence, replay deduplication and the existing run-read boundary. - Register the event in the UI taxonomy without changing panel display behavior. - Advance the source-bound Copilot identity to 78. Retain all published historical identity fixtures without changing their bytes. ## Verification - Root `pnpm typecheck` and `pnpm build`: passed for the revised activity contract. - Node protocol checks: 14 passed. Provider identity and registry tests: 185 passed. Server tests: 103 passed. UI event registry: five passed. - Maintained Grok and Copilot identity generator checks and `git diff --check`: passed. - The first activity-contract review scored 4/5 because the dependent producer and readers still used the earlier contract. Both dependent PRs are now updated and restacked; the finding is resolved and review is running again. - Initial extraction retained a consumer-only import in one server suite. That suite failed to load. The consumer case and import were moved out; the final three server files passed all 103 cases. - Earlier panel-specific head `6137c50bc` had green CI and standard/Apex 5/5. Those scores do not qualify this revised activity contract. Fresh CI and reviews are pending. Earlier combined results in the archive apply only to their recorded source revisions. ## Risks This change is additive. It adds no route, publisher, filesystem transport, provider sandbox grant, or panel display behavior. Activation hints grant no permission to read a plugin view. Provider identities bind the changed protocol source; historical identities remain decode-only. No schema migration or dependency change is required. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, repository tools and code execution. The exact serving snapshot is not exposed. ## 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 either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
738 lines
20 KiB
JSON
738 lines
20 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://paperclip.dev/schemas/prp/v3/event.schema.json",
|
|
"title": "PRP v3 native event",
|
|
"type": "object",
|
|
"required": [
|
|
"schema",
|
|
"sourceEventId",
|
|
"sourceSeq",
|
|
"sourceInstanceId",
|
|
"sourceKind",
|
|
"runId",
|
|
"eventType",
|
|
"schemaVersion",
|
|
"priority",
|
|
"emittedAt",
|
|
"payload"
|
|
],
|
|
"properties": {
|
|
"schema": {
|
|
"const": "paperclip.prp.event.v3"
|
|
},
|
|
"sourceEventId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"sourceSeq": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 9007199254740991
|
|
},
|
|
"sourceInstanceId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"sourceKind": {
|
|
"enum": [
|
|
"runner",
|
|
"control_plane"
|
|
]
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"itemId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"eventType": {
|
|
"enum": [
|
|
"runner.connected",
|
|
"runner.reconnected",
|
|
"runner.reconciled",
|
|
"runner.disconnected",
|
|
"runner.draining",
|
|
"runner.suspending",
|
|
"runner.suspended",
|
|
"runner.stopped",
|
|
"runner.diagnostic",
|
|
"runtime.phase.changed",
|
|
"sandbox.metric",
|
|
"workspace.ready",
|
|
"workspace.change.updated",
|
|
"workspace.diff.recorded",
|
|
"workspace.file.referenced",
|
|
"harness.starting",
|
|
"harness.ready",
|
|
"harness.exited",
|
|
"harness.diagnostic",
|
|
"plan.updated",
|
|
"tool.execution.started",
|
|
"tool.execution.progressed",
|
|
"tool.execution.completed",
|
|
"research.started",
|
|
"research.progressed",
|
|
"research.completed",
|
|
"delegation.started",
|
|
"delegation.updated",
|
|
"delegation.completed",
|
|
"model.route.changed",
|
|
"model.verification.updated",
|
|
"context.compacted",
|
|
"artifact.viewed",
|
|
"artifact.generated",
|
|
"review.mode.changed",
|
|
"hook.started",
|
|
"hook.completed",
|
|
"memory.citation.referenced",
|
|
"safety.review.started",
|
|
"safety.review.completed",
|
|
"terminal.input.sent",
|
|
"wait.started",
|
|
"wait.completed",
|
|
"provider.notice.recorded",
|
|
"session.starting",
|
|
"session.started",
|
|
"session.resuming",
|
|
"session.resumed",
|
|
"session.reconciled",
|
|
"session.updated",
|
|
"session.closed",
|
|
"session.failed",
|
|
"session.capabilities.updated",
|
|
"session.goal.snapshot",
|
|
"session.goal.updated",
|
|
"session.goal.cleared",
|
|
"turn.submitted",
|
|
"turn.accepted",
|
|
"turn.started",
|
|
"turn.completed",
|
|
"turn.failed",
|
|
"turn.interrupted",
|
|
"turn.cancelled",
|
|
"item.started",
|
|
"item.delta",
|
|
"item.completed",
|
|
"item.failed",
|
|
"usage.reported",
|
|
"semantic_tool.input",
|
|
"semantic_tool.result",
|
|
"mcp_app.discovered",
|
|
"mcp_app.resource.resolved",
|
|
"mcp_app.initializing",
|
|
"mcp_app.ready",
|
|
"mcp_app.tool_input",
|
|
"mcp_app.tool_result",
|
|
"mcp_app.action.requested",
|
|
"mcp_app.action.resolved",
|
|
"mcp_app.host_context.changed",
|
|
"mcp_app.failed",
|
|
"mcp_app.teardown",
|
|
"runtime_request.created",
|
|
"runtime_request.resolved",
|
|
"runtime_request.expired",
|
|
"runtime_request.cancelled",
|
|
"interaction.request.proposed",
|
|
"interaction.request.materialized",
|
|
"interaction.request.rejected",
|
|
"interaction.response.progressed",
|
|
"interaction.response.resolved",
|
|
"interaction.response.delivered",
|
|
"run.attached",
|
|
"run.detached",
|
|
"run.result.proposed",
|
|
"run.result.accepted",
|
|
"run.result.rejected",
|
|
"attention.request.proposed",
|
|
"attention.request.routed",
|
|
"attention.request.resolved",
|
|
"attention.request.expired",
|
|
"attention.request.superseded",
|
|
"work.assessment.recorded",
|
|
"issue.status.decision.recorded",
|
|
"issue.status.decision.applied",
|
|
"issue.status.decision.rejected",
|
|
"issue.status.decision.superseded",
|
|
"run.terminal",
|
|
"external_provider.dispatch_requested",
|
|
"external_provider.operation_settled",
|
|
"external_provider.input_available",
|
|
"auth.credentials.updated",
|
|
"runtime.activity.recorded"
|
|
]
|
|
},
|
|
"schemaVersion": {
|
|
"const": 3
|
|
},
|
|
"priority": {
|
|
"enum": [
|
|
0,
|
|
1,
|
|
2
|
|
]
|
|
},
|
|
"emittedAt": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"observedAt": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"payload": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"debug": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"enum": [
|
|
"session.goal.snapshot",
|
|
"session.goal.updated"
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"goal"
|
|
],
|
|
"properties": {
|
|
"goal": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/snapshot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "session.capabilities.updated"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"sessionGoals"
|
|
],
|
|
"properties": {
|
|
"sessionGoals": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/capability"
|
|
},
|
|
"turnControls": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/provider-descriptor.schema.json#/$defs/turnControls"
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.dispatch_requested"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"text": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 1048576
|
|
},
|
|
"instructions": {
|
|
"type": "string",
|
|
"maxLength": 1048576
|
|
},
|
|
"acceptByUnixMs": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"expiresAtUnixMs": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"completionContract": {
|
|
"type": "object",
|
|
"properties": {
|
|
"revision": {
|
|
"type": "string",
|
|
"minLength": 1
|
|
},
|
|
"criterionIds": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"maxItems": 256,
|
|
"uniqueItems": true,
|
|
"items": {
|
|
"type": "string",
|
|
"minLength": 1
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"revision",
|
|
"criterionIds"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"tools": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
},
|
|
"maxItems": 512
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"binding",
|
|
"text",
|
|
"instructions",
|
|
"acceptByUnixMs",
|
|
"expiresAtUnixMs",
|
|
"completionContract",
|
|
"tools"
|
|
]
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"kind": {
|
|
"const": "authority_revoked"
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
},
|
|
"externalStopConfirmed": {
|
|
"const": false
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"kind",
|
|
"externalStopConfirmed"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.operation_settled"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"requestId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"outcome": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"requestId",
|
|
"outcome"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.input_available"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"requestId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"inputDigest": {
|
|
"type": "string",
|
|
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
},
|
|
"response": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/question-response.schema.json"
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"requestId",
|
|
"turnId",
|
|
"inputDigest",
|
|
"response"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "auth.credentials.updated"
|
|
}
|
|
}
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"sourceKind": {
|
|
"const": "runner"
|
|
},
|
|
"priority": {
|
|
"const": 0
|
|
},
|
|
"payload": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/auth-credentials.schema.json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "runtime.activity.recorded"
|
|
}
|
|
}
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"sourceKind": {
|
|
"const": "runner"
|
|
},
|
|
"priority": {
|
|
"const": 1
|
|
},
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"namespace",
|
|
"activityKey"
|
|
],
|
|
"properties": {
|
|
"namespace": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160,
|
|
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
|
|
},
|
|
"activityKey": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160,
|
|
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"additionalProperties": true
|
|
}
|