@openwop/openwop-conformance 1.6.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +2 -2
- package/api/asyncapi.yaml +57 -0
- package/api/openapi.yaml +250 -0
- package/coverage.md +14 -0
- package/fixtures/conformance-run-duration-breach.json +33 -0
- package/fixtures.md +19 -0
- package/package.json +1 -1
- package/schemas/README.md +10 -0
- package/schemas/agent-inventory-response.schema.json +90 -0
- package/schemas/ai-envelope.schema.json +28 -0
- package/schemas/artifact-type-pack-manifest.schema.json +160 -0
- package/schemas/capabilities.schema.json +171 -4
- package/schemas/chat-card-pack-manifest.schema.json +158 -0
- package/schemas/envelopes/media.audio.schema.json +38 -0
- package/schemas/envelopes/media.file.schema.json +37 -0
- package/schemas/envelopes/media.image.schema.json +33 -0
- package/schemas/heartbeat-evaluated.schema.json +14 -0
- package/schemas/heartbeat-state-changed.schema.json +14 -0
- package/schemas/node-pack-manifest.schema.json +16 -1
- package/schemas/run-event-payloads.schema.json +96 -5
- package/schemas/run-event.schema.json +4 -0
- package/schemas/workflow-definition.schema.json +5 -0
- package/schemas/workspace-file-create.schema.json +20 -0
- package/schemas/workspace-file.schema.json +39 -0
- package/src/lib/agentLoop.ts +44 -0
- package/src/lib/agentRuntime.ts +45 -0
- package/src/lib/artifactTypes.ts +96 -0
- package/src/lib/cardPacks.ts +52 -0
- package/src/lib/discovery-capabilities.ts +50 -0
- package/src/lib/distillation.ts +38 -0
- package/src/lib/feedback.ts +3 -3
- package/src/lib/heartbeat.ts +31 -0
- package/src/lib/memoryAttribution.ts +48 -0
- package/src/lib/subRunAttestation.ts +35 -0
- package/src/lib/toolHooks.ts +33 -0
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +33 -0
- package/src/scenarios/agent-loop-stateful-resume.test.ts +28 -0
- package/src/scenarios/agent-loop-version5-shape.test.ts +41 -0
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +33 -0
- package/src/scenarios/agent-manifest-runtime.test.ts +85 -0
- package/src/scenarios/ai-envelope-shape.test.ts +14 -18
- package/src/scenarios/aiEnvelope.capBreached.test.ts +2 -1
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +2 -1
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +2 -1
- package/src/scenarios/approval-gate-flow.test.ts +4 -6
- package/src/scenarios/artifact-schema-compile-bounded.test.ts +126 -0
- package/src/scenarios/artifact-type-pack-install.test.ts +78 -0
- package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +140 -0
- package/src/scenarios/artifact-type-store-without-render.test.ts +54 -0
- package/src/scenarios/audit-log-integrity.test.ts +3 -2
- package/src/scenarios/auth-api-key-rotation.test.ts +2 -1
- package/src/scenarios/auth-mtls.test.ts +2 -1
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +2 -1
- package/src/scenarios/auth-oidc-user-bearer.test.ts +2 -1
- package/src/scenarios/auth-saml-profile.test.ts +2 -1
- package/src/scenarios/auth-scim-profile.test.ts +2 -1
- package/src/scenarios/authorization-fail-closed.test.ts +2 -1
- package/src/scenarios/authorization-roles-shape.test.ts +2 -1
- package/src/scenarios/byok-auth-modes.test.ts +141 -0
- package/src/scenarios/chat-card-pack-execution.test.ts +56 -0
- package/src/scenarios/chat-card-pack-manifest-validation.test.ts +128 -0
- package/src/scenarios/commitment-fired.test.ts +83 -0
- package/src/scenarios/credential-payload-redaction.test.ts +2 -1
- package/src/scenarios/credentials-capability-shape.test.ts +2 -1
- package/src/scenarios/cross-engine-append-ordering.test.ts +2 -1
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +3 -2
- package/src/scenarios/cross-host-causation-shape.test.ts +3 -2
- package/src/scenarios/deadletter-capability-shape.test.ts +2 -1
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +2 -1
- package/src/scenarios/distillation-index-roundtrip.test.ts +35 -0
- package/src/scenarios/distillation-secret-carryforward.test.ts +35 -0
- package/src/scenarios/distillation-shape.test.ts +41 -0
- package/src/scenarios/distillation-stable-archive.test.ts +37 -0
- package/src/scenarios/distillation-token-budget.test.ts +45 -0
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +4 -3
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +5 -4
- package/src/scenarios/envelope-reasoning-shape.test.ts +3 -2
- package/src/scenarios/envelope-refusal-shape.test.ts +3 -2
- package/src/scenarios/envelope-rendering-hint.test.ts +95 -0
- package/src/scenarios/envelope-retry-attempted.test.ts +2 -1
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +3 -2
- package/src/scenarios/exec-not-protocol-tier.test.ts +137 -0
- package/src/scenarios/experimental-tier-shape.test.ts +5 -4
- package/src/scenarios/fs-path-traversal.test.ts +2 -1
- package/src/scenarios/heartbeat-capability-shape.test.ts +35 -0
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +28 -0
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +43 -0
- package/src/scenarios/heartbeat-runtime-bound.test.ts +30 -0
- package/src/scenarios/http-client-ssrf.test.ts +10 -13
- package/src/scenarios/mcp-toolcall-redaction.test.ts +3 -2
- package/src/scenarios/media-url-inline-cap.test.ts +167 -0
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +54 -0
- package/src/scenarios/memory-attribution-no-content.test.ts +45 -0
- package/src/scenarios/memory-attribution-replay-stable.test.ts +60 -0
- package/src/scenarios/memory-attribution-shape.test.ts +28 -0
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +44 -0
- package/src/scenarios/memory-compaction-event-emitted.test.ts +2 -1
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +2 -1
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +2 -1
- package/src/scenarios/memory-consolidation-idempotent.test.ts +77 -0
- package/src/scenarios/memory-consolidation-shape.test.ts +90 -0
- package/src/scenarios/model-capability-substituted.test.ts +2 -1
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +5 -4
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +6 -5
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +4 -3
- package/src/scenarios/multi-region-idempotency.test.ts +10 -10
- package/src/scenarios/oauth-capability-shape.test.ts +2 -1
- package/src/scenarios/oauth-connector-redaction.test.ts +2 -1
- package/src/scenarios/pause-resume.test.ts +3 -3
- package/src/scenarios/production-backpressure.test.ts +2 -2
- package/src/scenarios/production-retention-expiry.test.ts +2 -2
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +2 -1
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +2 -1
- package/src/scenarios/prompt-composed-trust-marker.test.ts +2 -1
- package/src/scenarios/prompt-end-to-end-events.test.ts +2 -1
- package/src/scenarios/prompt-list-and-fetch.test.ts +2 -1
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +2 -1
- package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +2 -1
- package/src/scenarios/prompt-pack-install.test.ts +2 -1
- package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +2 -1
- package/src/scenarios/prompt-render-deterministic.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +2 -1
- package/src/scenarios/prompt-template-shape.test.ts +2 -1
- package/src/scenarios/provider-usage.test.ts +2 -1
- package/src/scenarios/replay-divergence-at-refusal.test.ts +4 -3
- package/src/scenarios/replay-fork-arbitrary.test.ts +3 -1
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +2 -1
- package/src/scenarios/replayDeterminism.test.ts +3 -1
- package/src/scenarios/run-execution-bounds-shape.test.ts +133 -0
- package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
- package/src/scenarios/sandbox-mvp-behavior.test.ts +2 -1
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +2 -1
- package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
- package/src/scenarios/scheduling-capability-shape.test.ts +2 -1
- package/src/scenarios/scheduling-cron-fires-once.test.ts +2 -1
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +7 -6
- package/src/scenarios/spec-corpus-validity.test.ts +1 -1
- package/src/scenarios/subrun-approval-fail-closed.test.ts +33 -0
- package/src/scenarios/subrun-approval-gate.test.ts +35 -0
- package/src/scenarios/subrun-attestation-shape.test.ts +30 -0
- package/src/scenarios/subrun-checksum-stable.test.ts +43 -0
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +39 -0
- package/src/scenarios/tool-hooks-content-free.test.ts +40 -0
- package/src/scenarios/tool-hooks-rate-limit.test.ts +32 -0
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +34 -0
- package/src/scenarios/tool-hooks-shape.test.ts +34 -0
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -10
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +2 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +2 -2
- package/src/scenarios/wasm-pack-load.test.ts +2 -2
- package/src/scenarios/wasm-pack-memory-cap.test.ts +3 -6
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -2
- package/src/scenarios/workflow-primary-output-annotation.test.ts +142 -0
- package/src/scenarios/workspace-behavior.test.ts +134 -0
- package/src/scenarios/workspace-capability-shape.test.ts +73 -0
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +84 -0
|
@@ -44,6 +44,16 @@
|
|
|
44
44
|
"type": "integer",
|
|
45
45
|
"minimum": 1,
|
|
46
46
|
"description": "Engine-side ceiling on total node executions per run. Acts as the upper bound for `RunOptions.configurable.recursionLimit`. Optional in v1; hosts that advertise it MUST enforce it."
|
|
47
|
+
},
|
|
48
|
+
"maxRunDurationMs": {
|
|
49
|
+
"type": "integer",
|
|
50
|
+
"minimum": 1000,
|
|
51
|
+
"description": "RFC 0058. Engine-side wall-clock ceiling per run (milliseconds). Upper bound for `RunOptions.configurable.runTimeoutMs`. Breach emits `cap.breached { kind: 'run-duration' }` + error `run_timeout`. Optional; hosts that advertise it MUST enforce it."
|
|
52
|
+
},
|
|
53
|
+
"maxLoopIterations": {
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"minimum": 1,
|
|
56
|
+
"description": "RFC 0058. Authoritative engine-side ceiling on agent-loop iterations. Upper bound for `RunOptions.configurable.maxLoopIterations`. Breach emits `cap.breached { kind: 'loop-iterations' }` + error `loop_limit_exceeded`. Optional; hosts that advertise it MUST enforce it."
|
|
47
57
|
}
|
|
48
58
|
},
|
|
49
59
|
"additionalProperties": false,
|
|
@@ -533,8 +543,8 @@
|
|
|
533
543
|
"version": {
|
|
534
544
|
"type": "integer",
|
|
535
545
|
"minimum": 1,
|
|
536
|
-
"maximum":
|
|
537
|
-
"description": "Profile version. 1 = Phase 1 (execution-loop framework + planner→worker handoff). 2 = Phase 2 (confidence-floor escalation + agent-memory lifecycle, RFC 0039). 3 = Phase 3 (cross-host causation,
|
|
546
|
+
"maximum": 5,
|
|
547
|
+
"description": "Profile version. 1 = Phase 1 (execution-loop framework + planner→worker handoff). 2 = Phase 2 (confidence-floor escalation + agent-memory lifecycle, RFC 0039). 3 = Phase 3 (cross-host causation, RFC 0040). 4 = Phase 4 (replay determinism under nondeterministic models, RFC 0041). 5 = Phase 5 (stateful agent-loop lifecycle — per-iteration workspace+memory snapshot inputs, the observable `iteration` counter on `runOrchestrator.decided`, and stateful HITL resume, RFC 0061). A host advertising `version: N` MUST implement all phases 1..N additively."
|
|
538
548
|
},
|
|
539
549
|
"confidenceEscalationFloor": {
|
|
540
550
|
"type": "number",
|
|
@@ -600,6 +610,15 @@
|
|
|
600
610
|
"description": "Host emits `replay.divergedAtRefusal` events + fails replay with `error.code: replay_diverged_at_refusal` per RFC 0041 §B. Hosts advertising `version: 4` MUST set this to `true`."
|
|
601
611
|
}
|
|
602
612
|
}
|
|
613
|
+
},
|
|
614
|
+
"statefulResume": {
|
|
615
|
+
"type": "boolean",
|
|
616
|
+
"description": "RFC 0061 (`version >= 5`). When `true`, a `clarify`/`escalate` HITL suspend resumes the execution loop at the SAME iteration — the `runOrchestrator.decided.iteration` counter does not reset or skip — with the per-iteration memory (RFC 0039 MAE-3) + workspace (RFC 0059) snapshot lineage intact, so a mid-loop human interrupt does not lose progress. A distinct claim from plain replay re-entrancy (deterministic replay of a completed prefix); this is about a LIVE suspend preserving the counter. Omitted by hosts on `version < 5`."
|
|
617
|
+
},
|
|
618
|
+
"transcriptWindow": {
|
|
619
|
+
"type": "integer",
|
|
620
|
+
"minimum": 1,
|
|
621
|
+
"description": "RFC 0061 (`version >= 5`). Host-advertised count of recent event-log entries the host feeds each orchestrator turn as the iteration's transcript input (§C input 3). Advertise-and-honor; not a fixed wire constant. Absent ⇒ the host does not bound the transcript window on the wire."
|
|
603
622
|
}
|
|
604
623
|
}
|
|
605
624
|
}
|
|
@@ -622,7 +641,7 @@
|
|
|
622
641
|
"pattern": "^([a-z][a-z0-9-]*|x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*)$"
|
|
623
642
|
},
|
|
624
643
|
"uniqueItems": true,
|
|
625
|
-
"description": "Capability identifiers the host's active model advertises. Clients MAY introspect this at install time to determine whether their NodeModules' `requiredModelCapabilities` are satisfiable without fallback. Spec-reserved identifiers per RFC 0031 §C: `structured-output`, `discriminator-enum`, `long-context`, `reasoning` (model-native thinking-tokens), `function-calling
|
|
644
|
+
"description": "Capability identifiers the host's active model advertises. Clients MAY introspect this at install time to determine whether their NodeModules' `requiredModelCapabilities` are satisfiable without fallback. Spec-reserved identifiers per RFC 0031 §C + RFC 0055: `structured-output`, `discriminator-enum`, `long-context`, `reasoning` (model-native thinking-tokens), `function-calling`, `vision-input` (model accepts image content in the prompt), `audio-input` (model accepts audio content), `audio-output` (model emits audio content), `image-output` (model emits images directly in its completion, distinct from the host-side `aiProviders.imageGeneration` tool surface). This is an open, pattern-validated registry — NOT a closed enum; growth requires an RFC. Host-private extensions MUST prefix with `x-host-<host>-`."
|
|
626
645
|
},
|
|
627
646
|
"substitutionSupported": {
|
|
628
647
|
"type": "boolean",
|
|
@@ -649,7 +668,7 @@
|
|
|
649
668
|
"type": "array",
|
|
650
669
|
"items": { "type": "string", "minLength": 1 },
|
|
651
670
|
"uniqueItems": true,
|
|
652
|
-
"description": "Provider ids the host's AI-proxy can route to. Conventional ids: `anthropic`, `openai`, `gemini`, `mistral`, `cohere`, `
|
|
671
|
+
"description": "Provider ids the host's AI-proxy can route to. Conventional ids (RFC 0067 §C recommended vocabulary — advisory, not a closed set): `anthropic`, `openai`, `gemini`, `vertex`, `bedrock`, `mistral`, `cohere`, `openrouter`, `litellm`, `together`, `huggingface`, `qwen`, `ollama`, `vllm`. Hosts MAY add vendor-prefixed extensions; clients MUST tolerate unknown ids."
|
|
653
672
|
},
|
|
654
673
|
"byok": {
|
|
655
674
|
"type": "array",
|
|
@@ -657,6 +676,19 @@
|
|
|
657
676
|
"uniqueItems": true,
|
|
658
677
|
"description": "Subset of `supported` for which BYOK is permitted. Empty array → all calls use platform-managed keys; non-empty → clients MAY pass `ai.credentialRef` in `RunOptions.configurable` for matching providers."
|
|
659
678
|
},
|
|
679
|
+
"authModes": {
|
|
680
|
+
"type": "object",
|
|
681
|
+
"description": "RFC 0067 (`Draft`). Optional per-provider advertisement of HOW the host expects a provider's credential to be supplied. Keys are provider ids appearing in `supported`; values are the auth modes the host honors for that provider. Absent ⇒ no advertisement: a provider in `byok` defaults to `apiKey` semantics (client passes `ai.credentialRef`); a provider in `supported` but not in `byok` defaults to `none` (platform-managed). This map only DESCRIBES the supply mechanism — `oauth-pkce`/`oauth-device` flow mechanics compose RFC 0047 `host.oauth` and resolve credentials by `ref` (RFC 0046), never on `ai.credentialRef`. A provider with `apiKey` MUST appear in `byok`; a provider whose modes are exactly `[\"none\"]` MUST NOT appear in `byok`. Consumers MUST ignore an auth mode they don't recognize rather than reject the discovery doc.",
|
|
682
|
+
"additionalProperties": {
|
|
683
|
+
"type": "array",
|
|
684
|
+
"minItems": 1,
|
|
685
|
+
"uniqueItems": true,
|
|
686
|
+
"items": {
|
|
687
|
+
"type": "string",
|
|
688
|
+
"enum": ["apiKey", "oauth-pkce", "oauth-device", "none"]
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
},
|
|
660
692
|
"policies": {
|
|
661
693
|
"type": "object",
|
|
662
694
|
"description": "Optional v1 host-side policy enforcement modes for per-provider gating. Omitted → no enforcement; clients see only `optional` semantics. When present, MUST declare `modes` — an empty `{}` is not a valid third state. See `capabilities.md` §`aiProviders.policies`.",
|
|
@@ -681,6 +713,12 @@
|
|
|
681
713
|
}
|
|
682
714
|
},
|
|
683
715
|
"additionalProperties": false
|
|
716
|
+
},
|
|
717
|
+
"maxInlineMediaBytes": {
|
|
718
|
+
"type": "integer",
|
|
719
|
+
"minimum": 0,
|
|
720
|
+
"default": 262144,
|
|
721
|
+
"description": "RFC 0055 §C rule 2 — optional cap (bytes) on inline base64 in `media.*` envelope payloads. A `media.{image,audio,file}` asset above this size MUST be served by a tenant-scoped `url` reference rather than inlined (bounds event-log + replay-payload size). Default 256 KiB (262144) when absent. A host MAY set 0 to force URL references for all emitted media."
|
|
684
722
|
}
|
|
685
723
|
},
|
|
686
724
|
"additionalProperties": false
|
|
@@ -762,6 +800,41 @@
|
|
|
762
800
|
"uniqueItems": true,
|
|
763
801
|
"description": "Optional list of memory backends (Phase 3). `long-term` means the host implements `ExecutionHost.memory` against a durable store with the SR-1 redaction invariant intact end-to-end. Hosts that don't wire `MemoryAdapter` omit this field."
|
|
764
802
|
},
|
|
803
|
+
"memoryConsolidation": {
|
|
804
|
+
"type": "object",
|
|
805
|
+
"description": "RFC 0068 (`Draft`). Background reconciliation of LONG-TERM memory (merge/dedup/supersede/strengthen) — distinct from RFC 0062 token-budgeted distillation of TRANSACTIONAL memory. A host advertising this emits `agent.memory.consolidated` (content-free) after a consolidation pass. Requires `agents.memoryBackends` to include `long-term`. SR-1 carry-forward + CTI-1 (RFC 0004) hold across the pass. Hosts that omit this block do not consolidate; the conformance scenarios skip cleanly.",
|
|
806
|
+
"additionalProperties": false,
|
|
807
|
+
"required": ["supported"],
|
|
808
|
+
"properties": {
|
|
809
|
+
"supported": {
|
|
810
|
+
"type": "boolean",
|
|
811
|
+
"description": "REQUIRED when the block is present. When `true`, the host performs background consolidation over long-term memory and emits `agent.memory.consolidated`."
|
|
812
|
+
},
|
|
813
|
+
"schedule": {
|
|
814
|
+
"type": "string",
|
|
815
|
+
"enum": ["host-managed", "scheduled", "on-demand"],
|
|
816
|
+
"description": "How a consolidation pass is initiated. `host-managed`: a host-internal cadence clients do not control (default when absent and supported:true). `scheduled`: bound to a `capabilities.scheduling` (RFC 0052) trigger. `on-demand`: the host runs a pass when explicitly requested. A host MAY honor more than one path but advertises the primary."
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
"commitments": {
|
|
821
|
+
"type": "object",
|
|
822
|
+
"description": "RFC 0068 (`Draft`). Inferred STANDING commitments — durable, memory-derived intentions the host promotes into a time- or predicate-gated arm that fires a run later, without a fresh user turn. When an arm fires the host emits `commitment.fired` (content-free — the intention text lives in SR-1-redacted memory). Composes RFC 0052 (time arms) / RFC 0060 (predicate arms) for the fire substrate. Hosts that omit this block do not infer commitments; the conformance scenario skips cleanly.",
|
|
823
|
+
"additionalProperties": false,
|
|
824
|
+
"required": ["supported"],
|
|
825
|
+
"properties": {
|
|
826
|
+
"supported": {
|
|
827
|
+
"type": "boolean",
|
|
828
|
+
"description": "REQUIRED when the block is present. When `true`, the host infers standing commitments from memory and emits `commitment.fired` when one fires."
|
|
829
|
+
},
|
|
830
|
+
"fireConditions": {
|
|
831
|
+
"type": "array",
|
|
832
|
+
"items": { "type": "string", "enum": ["time", "predicate"] },
|
|
833
|
+
"uniqueItems": true,
|
|
834
|
+
"description": "Which fire-condition kinds the host supports. `time` composes RFC 0052 scheduling; `predicate` composes RFC 0060 heartbeat. Absent ⇒ `['time']`."
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
},
|
|
765
838
|
"orchestrator": {
|
|
766
839
|
"type": "boolean",
|
|
767
840
|
"description": "Phase 5. When `true`, host advertises that it implements the `core.orchestrator.supervisor` node typeId AND honors the conservative-path suspend semantics (CP-1: low-confidence suspend via `node.suspended { reason: 'low-confidence' }`)."
|
|
@@ -770,6 +843,29 @@
|
|
|
770
843
|
"type": "boolean",
|
|
771
844
|
"description": "Phase 6. When `true`, host advertises that it implements the `core.dispatch` Core typeId AND honors the conservative-path commitment CP-2 (`core.dispatch` MUST NOT mutate the run's DAG mid-run). Implies (but does NOT require) `agents.orchestrator: true`."
|
|
772
845
|
},
|
|
846
|
+
"manifestRuntime": {
|
|
847
|
+
"type": "object",
|
|
848
|
+
"description": "RFC 0070. Agent-manifest runtime floor — the minimal tier that makes a published agent pack (RFC 0003) runnable. When `supported: true`, the host implements RFC 0003 `installAgents`: it loads each installed pack's `agents[]` into an in-process AgentRegistry, resolves `systemPromptRef` + `handoff.*SchemaRef` from the tarball at install (RFC 0003 §C/§D), and can DISPATCH a manifest agent on the existing `core.dispatch`/orchestrator loop (RFC 0007/0037/0061). Does NOT imply swarm/consensus (`host.agentRuntime`), long-term memory (`agents.memoryBackends`), or crews beyond `agents.dispatch`. A host advertising `host.agentRuntime: supported` is treated as also satisfying this flag (RFC 0070 §B). Hosts that omit this block do not instantiate manifest agents (today's default).",
|
|
849
|
+
"additionalProperties": false,
|
|
850
|
+
"required": ["supported"],
|
|
851
|
+
"properties": {
|
|
852
|
+
"supported": {
|
|
853
|
+
"type": "boolean",
|
|
854
|
+
"description": "REQUIRED when the block is present. When `true`, the host loads + dispatches pack-declared manifest agents. A host with `supported: true` MUST enforce each dispatched agent's `toolAllowlist` (RFC 0002 §A14) and MUST NOT leak BYOK plaintext into `agent.*` events or handoff payloads (SR-1)."
|
|
855
|
+
},
|
|
856
|
+
"handoffValidation": {
|
|
857
|
+
"type": "boolean",
|
|
858
|
+
"default": false,
|
|
859
|
+
"description": "When `true`, the host validates inbound task payloads against the agent's `handoff.taskSchemaRef` before dispatch and outbound results against `handoff.returnSchemaRef` before persistence (RFC 0003 §D). When `false`/absent, manifests carrying `handoff` schemas are dispatched with opaque payloads."
|
|
860
|
+
},
|
|
861
|
+
"installScope": {
|
|
862
|
+
"type": "string",
|
|
863
|
+
"enum": ["host", "tenant"],
|
|
864
|
+
"default": "host",
|
|
865
|
+
"description": "RFC 0074. Scope at which manifest agents are installed/approved and therefore enumerated by GET /v1/agents. 'host' (default): a single host-global inventory; the endpoint returns the same set for every caller (RFC 0072's original behavior). 'tenant': agents are installed per tenant·workspace (RFC 0048 owner triple); GET /v1/agents returns ONLY the agents available to the authenticated principal's workspace, and an unapproved/unknown agent 404s — the surface never discloses another tenant's inventory. Does not change dispatch (RFC 0072 §B, owner-triple-scoped POST /v1/runs) or any floor safety guarantee (toolAllowlist/systemPromptRef/SR-1 stay mandatory regardless of scope)."
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
},
|
|
773
869
|
"dispatchMapping": {
|
|
774
870
|
"type": "boolean",
|
|
775
871
|
"default": false,
|
|
@@ -796,6 +892,11 @@
|
|
|
796
892
|
}
|
|
797
893
|
},
|
|
798
894
|
"additionalProperties": false
|
|
895
|
+
},
|
|
896
|
+
"subRunAttestation": {
|
|
897
|
+
"type": "boolean",
|
|
898
|
+
"default": false,
|
|
899
|
+
"description": "RFC 0063 (`Active`). When `true`, host honors the optional `outputAttestation` block on `core.subWorkflow`: computes a content checksum (RFC 8785 JCS + SHA-256, the `replay.md` recipe) over a child's harvested outputs and surfaces it as the additive optional `attestation` object on the existing `core.workflowChain.event { phase: 'output.harvested' }` (RFC 0037) BEFORE applying `outputMapping`; when the config sets `requireApproval: true`, suspends the parent via an `approval` interrupt (RFC 0051) before merge and fails closed (no `accept`/`edit-accept` ⇒ no merge). Reuses RFC 0051's `approval` kind + RFC 0049 scopes for `principalScope` — no new interrupt kind, event type, or error code. Hosts that omit / `false` this flag treat `outputAttestation` as inert (blind merge, today's behavior)."
|
|
799
900
|
}
|
|
800
901
|
},
|
|
801
902
|
"additionalProperties": true
|
|
@@ -845,6 +946,36 @@
|
|
|
845
946
|
"additionalProperties": false,
|
|
846
947
|
"if": { "properties": { "supported": { "const": true } }, "required": ["supported"] },
|
|
847
948
|
"then": { "required": ["supported", "trigger"] }
|
|
949
|
+
},
|
|
950
|
+
"distillation": {
|
|
951
|
+
"type": "object",
|
|
952
|
+
"description": "RFC 0062 (`Active`). Scheduled, token-budgeted background compaction — the 'dream' pattern — built on compaction (RFC 0012) + scheduling (RFC 0052) + the workspace index (RFC 0059). A distillation run IS a compaction run with a mandatory token budget, an optional schedule, and a retrieval index wrapped around it; it reuses the `memory.compacted` event (extended with the additive optional `distillation` sub-object) rather than a parallel `memory.distilled` event. SR-1 carry-forward (RFC 0012 §D) holds — a distilled archive MUST NOT re-expose a redacted secret. Hosts that omit this block keep plain on-demand compaction (RFC 0012) or no memory.",
|
|
953
|
+
"required": ["supported"],
|
|
954
|
+
"additionalProperties": false,
|
|
955
|
+
"properties": {
|
|
956
|
+
"supported": { "type": "boolean", "description": "REQUIRED when the sub-block is present. When `true`, host honors the `distillation.tokenBudget` reserved run-option key, runs budgeted distillation over `longTerm` memory, writes a stable archive, and emits `memory.compacted` with the `distillation` sub-object." },
|
|
957
|
+
"maxTokenBudget": { "type": "integer", "minimum": 1, "description": "Largest per-run distillation token budget the host honors. A supplied `distillation.tokenBudget` is clamped to this; absent ⇒ the host defaults to this." },
|
|
958
|
+
"scheduled": { "type": "boolean", "description": "When `true`, host can initiate distillation on a schedule (requires `capabilities.scheduling`, RFC 0052). Distillation MAY also run on-demand without scheduling." },
|
|
959
|
+
"indexEmitted": { "type": "boolean", "description": "When `true`, host writes a retrievable memory-index manifest (`MEMORY-INDEX.json`, a workspace file per RFC 0059) after distillation; updating it emits `workspace.updated`." },
|
|
960
|
+
"tokenizerName": { "type": "string", "description": "Identifier of the tokenizer the budget is counted against (e.g. `claude`, `gpt-4`). The budget is best-effort-honest per this tokenizer (±10% conformance tolerance), not byte-exact." },
|
|
961
|
+
"archiveRetention": { "type": "string", "description": "ISO-8601 duration (e.g. `P30D`) the distilled archives persist before GC. Recursive distillation (distilling prior archives) is allowed; each level re-checks SR-1." }
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
"attribution": {
|
|
965
|
+
"type": "object",
|
|
966
|
+
"description": "RFC 0057 Memory write-attribution. Hosts that emit per-node memory provenance on the run event log MAY advertise here. Advertising `emitsWriteEvents: true` commits the host to emit a `memory.written` RunEvent for every memory write a run makes (identifiers only, never content), and implies the SECURITY invariants `memory-attribution-no-content` + `memory-attribution-tenant-scoped`.",
|
|
967
|
+
"required": ["supported"],
|
|
968
|
+
"properties": {
|
|
969
|
+
"supported": {
|
|
970
|
+
"const": true,
|
|
971
|
+
"description": "REQUIRED when the sub-block is present. The block is omitted entirely by hosts that do not support write attribution."
|
|
972
|
+
},
|
|
973
|
+
"emitsWriteEvents": {
|
|
974
|
+
"type": "boolean",
|
|
975
|
+
"description": "When `true`, the host emits `memory.written` (per `run-event-payloads.schema.json#/$defs/memoryWritten`) for every memory write during a run. When `false` or absent, consumers MUST tolerate the event never appearing."
|
|
976
|
+
}
|
|
977
|
+
},
|
|
978
|
+
"additionalProperties": false
|
|
848
979
|
}
|
|
849
980
|
},
|
|
850
981
|
"additionalProperties": true
|
|
@@ -976,6 +1107,29 @@
|
|
|
976
1107
|
},
|
|
977
1108
|
"additionalProperties": false
|
|
978
1109
|
},
|
|
1110
|
+
"heartbeat": {
|
|
1111
|
+
"type": "object",
|
|
1112
|
+
"description": "RFC 0060 (`Draft`). System-managed, predicate-gated polling: a short-interval, runtime-bounded evaluation of an idempotent predicate that emits state-change events and conditionally enqueues a run, rather than re-running an agent blindly. Composes with `scheduling` (RFC 0052) for the once-per-tick interval substrate; the controlled, request-shaped exception to openwop's poll-free design (`positioning.md`).",
|
|
1113
|
+
"required": ["supported"],
|
|
1114
|
+
"properties": {
|
|
1115
|
+
"supported": { "type": "boolean" },
|
|
1116
|
+
"minIntervalSec": { "type": "integer", "minimum": 1, "description": "Smallest interval the host honors; requests below it clamp up." },
|
|
1117
|
+
"maxRuntimeMs": { "type": "integer", "minimum": 1, "description": "Per-tick predicate-evaluation budget; bounded above by `capabilities.limits.maxRunDurationMs` (RFC 0058) as the hard ceiling. Over-budget evaluation is terminated and reported as `heartbeat.evaluated { status: 'timeout' }`." }
|
|
1118
|
+
},
|
|
1119
|
+
"additionalProperties": false
|
|
1120
|
+
},
|
|
1121
|
+
"toolHooks": {
|
|
1122
|
+
"type": "object",
|
|
1123
|
+
"description": "RFC 0064 (`Active`) — sibling of `heartbeat`. Per-tool authorization + rate limiting + content-free tool-call audit fields, layered on the existing `agent.toolCalled` / `agent.toolReturned` events (RFC 0002). Generalizes the MCP-specific bridges across transports (mcp / http / native). Reuses RFC 0049's `forbidden` error + `authorization-fail-closed` invariant and the existing `rate_limited` error — no new event type, error code, or invariant.",
|
|
1124
|
+
"required": ["supported"],
|
|
1125
|
+
"additionalProperties": false,
|
|
1126
|
+
"properties": {
|
|
1127
|
+
"supported": { "type": "boolean" },
|
|
1128
|
+
"prePostEvents": { "type": "boolean", "description": "Host populates `argsHash`/`principal`/`transport` on `agent.toolCalled` + `status`/`durationMs` on `agent.toolReturned` for every external tool call." },
|
|
1129
|
+
"perToolAuthorization": { "type": "boolean", "description": "Host enforces per-tool scopes against the run principal (RFC 0049), fail-closed; a lacked-or-unevaluable scope yields `agent.toolReturned { status: 'forbidden' }` + a `forbidden` (403) error and the tool is never invoked." },
|
|
1130
|
+
"perToolRateLimit": { "type": "boolean", "description": "Host applies a per-`(principal, tool)` token-bucket rate limit; exhaustion yields `agent.toolReturned { status: 'rate_limited' }` + a `rate_limited` (429) error." }
|
|
1131
|
+
}
|
|
1132
|
+
},
|
|
979
1133
|
"deadLetter": {
|
|
980
1134
|
"type": "object",
|
|
981
1135
|
"description": "RFC 0053 (`Draft`). Run-level dead-letter sink for terminally-failed runs/nodes. On retry exhaustion (RFC 0009), the run is routed to a durable, inspectable sink and a `run.dead_lettered` event is emitted; dead-lettered runs remain fork-eligible (RFC 0011) for the retention window. Distinct from `queueBus.deadLetterSupported`, which dead-letters transport *messages*, not *runs*.",
|
|
@@ -986,6 +1140,19 @@
|
|
|
986
1140
|
},
|
|
987
1141
|
"additionalProperties": false
|
|
988
1142
|
},
|
|
1143
|
+
"workspace": {
|
|
1144
|
+
"type": "object",
|
|
1145
|
+
"description": "RFC 0059 (`Active`). Versioned, tenant·workspace-scoped ground-truth file store (the `host.workspace` capability). Scopes to the RFC 0048 owner triple. Atomic, optimistically-concurrent writes (`If-Match` ETag); a read snapshot is exposed to every run at `run.started` (deterministic for replay). Complements the transactional `MemoryAdapter` (RFC 0004) with a durable, path-addressable file layer. Endpoints (`/v1/host/workspace/files[/{path}]`) are gated on `supported: true`; unsupported hosts return `501 capability_not_provided`. SECURITY invariants `workspace-cross-tenant-isolation` (WCT-1) + the WSR-1 secret-redaction MUST land with their conformance tests at implementation (RFC 0059 §E).",
|
|
1146
|
+
"required": ["supported"],
|
|
1147
|
+
"properties": {
|
|
1148
|
+
"supported": { "type": "boolean", "description": "Host implements the RFC 0059 workspace file store + endpoints + `workspace.updated` event." },
|
|
1149
|
+
"versioned": { "type": "boolean", "description": "Each write bumps a monotonic `version`; prior versions are retrievable via `GET …/files/{path}?version=N`. Latest-version retrieval is the MUST regardless; history is best-effort up to `maxVersions`." },
|
|
1150
|
+
"maxFileBytes": { "type": "integer", "minimum": 1, "description": "Per-file byte ceiling; writes beyond it return `workspace_too_large`." },
|
|
1151
|
+
"maxFiles": { "type": "integer", "minimum": 1, "description": "Per-workspace file-count ceiling." },
|
|
1152
|
+
"maxVersions": { "type": "integer", "minimum": 1, "description": "When `versioned: true`, the number of historical versions a host advertises it will retain (history best-effort beyond the mandatory latest)." }
|
|
1153
|
+
},
|
|
1154
|
+
"additionalProperties": false
|
|
1155
|
+
},
|
|
989
1156
|
"sql": {
|
|
990
1157
|
"type": "object",
|
|
991
1158
|
"description": "RFC 0018 (`Active`). SQL database adapter with parametric-only enforcement. Hosts MUST reject non-parametric queries that inline user input (`sql-parametric-only` invariant — guards against SQL injection across every workflow).",
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/chat-card-pack-manifest.schema.json",
|
|
4
|
+
"title": "ChatCardPackManifest",
|
|
5
|
+
"description": "Manifest for a published OpenWOP AI chat card pack — `pack.json` at the pack root with `kind: \"card\"`. Peer to the node / workflow-chain / prompt / artifact-type pack manifests; disjoint via the `kind` discriminator. See `spec/v1/chat-card-packs.md` for the canonical contract and RFC 0071 Phase 2 for the rationale.\n\nA chat card pack distributes AI step cards: each card binds a prompt template (with typed input slots) to a typed output artifact. When a host advertises `host.chat.cardPacks: supported` and a registered card is invoked, the host substitutes inputs into the prompt, routes the call through `ctx.aiEnvelope.generate`, and (when `outputArtifactType` is set) validates the result against the referenced artifact-type pack's schema before emitting `artifact.created`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "version", "kind", "engines", "cards"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"kind": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"const": "card",
|
|
13
|
+
"description": "Pack kind discriminator. MUST be the literal string `\"card\"`."
|
|
14
|
+
},
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Reverse-DNS pack name per `node-packs.md` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`).",
|
|
18
|
+
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
|
|
19
|
+
"minLength": 1,
|
|
20
|
+
"maxLength": 256
|
|
21
|
+
},
|
|
22
|
+
"version": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Pack-level SemVer 2.0.0.",
|
|
25
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
|
|
26
|
+
},
|
|
27
|
+
"description": { "type": "string", "maxLength": 1024 },
|
|
28
|
+
"author": { "type": "string" },
|
|
29
|
+
"license": { "type": "string", "description": "SPDX license identifier (e.g., `Apache-2.0`, `MIT`)." },
|
|
30
|
+
"homepage": { "type": "string", "format": "uri" },
|
|
31
|
+
"repository": { "type": "string", "format": "uri" },
|
|
32
|
+
"keywords": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "type": "string", "maxLength": 64 },
|
|
35
|
+
"maxItems": 50
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": ["openwop"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"openwop": { "type": "string", "description": "Semver range — which openwop protocol versions this pack works against." }
|
|
42
|
+
},
|
|
43
|
+
"additionalProperties": true
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": { "type": "string" },
|
|
48
|
+
"description": "Other packs this pack depends on (e.g., the artifact-type pack declaring this card's `outputArtifactType`). Map of pack name → semver range."
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": { "type": "string" },
|
|
53
|
+
"description": "Engine-supplied capabilities the pack consumes (e.g., `{ \"host.aiEnvelope\": \"supported\", \"host.chat.cards\": \"supported\" }`). Resolved against the host's advertised capabilities at register time."
|
|
54
|
+
},
|
|
55
|
+
"cards": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"minItems": 1,
|
|
58
|
+
"items": { "$ref": "#/$defs/Card" },
|
|
59
|
+
"description": "AI chat card definitions this pack contributes. Each MUST have a unique `cardTypeId` within the pack."
|
|
60
|
+
},
|
|
61
|
+
"signing": { "$ref": "#/$defs/Signing" }
|
|
62
|
+
},
|
|
63
|
+
"$defs": {
|
|
64
|
+
"Card": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"required": ["cardTypeId", "prompt"],
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"properties": {
|
|
69
|
+
"cardTypeId": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "Reverse-DNS card identifier. Same pattern and reserved scopes as a pack `name`. The value `WorkflowNode.cardType` / `ctx.chat.emitCard` MAY reference. Third parties MUST NOT publish under `core.*`.",
|
|
72
|
+
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
|
|
73
|
+
"minLength": 1,
|
|
74
|
+
"maxLength": 256
|
|
75
|
+
},
|
|
76
|
+
"schemaVersion": {
|
|
77
|
+
"type": "integer",
|
|
78
|
+
"minimum": 0,
|
|
79
|
+
"description": "Non-negative integer card-schema version (the envelope/artifact integer-version axis). Absent ⇒ treated as 0."
|
|
80
|
+
},
|
|
81
|
+
"prompt": { "$ref": "#/$defs/PromptSpec" },
|
|
82
|
+
"inputs": {
|
|
83
|
+
"type": "array",
|
|
84
|
+
"items": { "$ref": "#/$defs/InputField" },
|
|
85
|
+
"description": "Typed input fields the card collects. The portable subset only; host-specific widget kinds extend via `vendor.*`/`x-` prefixed `type` values."
|
|
86
|
+
},
|
|
87
|
+
"outputArtifactType": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "A registered `artifactTypeId` (RFC 0071 Phase 1) the card produces. When present, the host MUST validate the LLM output against that artifact type's schema and emit `artifact.created`. Registered-only by design: unlike a bare node `WorkflowNode.artifactType` (where the unregistered free-string tier is permanently valid), a card's product is always a contract-bound artifact, so this MUST be a reverse-DNS registered id. Omit the field for a prompt-only card that produces no durable artifact.",
|
|
90
|
+
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$"
|
|
91
|
+
},
|
|
92
|
+
"outputSchemaRef": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"minLength": 1,
|
|
95
|
+
"description": "Path inside the pack tarball to the JSON Schema (Draft 2020-12) the LLM output MUST conform to. SHOULD be consistent with the referenced artifact type's schema. MUST set top-level `additionalProperties: false`."
|
|
96
|
+
},
|
|
97
|
+
"requiredModelCapabilities": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"pattern": "^([a-z][a-z0-9-]*|x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*)$"
|
|
102
|
+
},
|
|
103
|
+
"uniqueItems": true,
|
|
104
|
+
"maxItems": 32,
|
|
105
|
+
"description": "Model capabilities the card requires the active model to advertise. Reuses the `requiredModelCapabilities` registry in `host-capabilities.md` (spec-reserved: `structured-output`, `discriminator-enum`, `long-context`, `reasoning`, `function-calling`; host extensions `x-host-<host>-`)."
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"PromptSpec": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"required": ["template", "placeholderMapping"],
|
|
112
|
+
"additionalProperties": false,
|
|
113
|
+
"description": "The prompt the card composes. The host substitutes mapped input values into `template`/`systemPrompt` before dispatch; segments derived from card inputs are `untrusted` (RFC 0071 Trust boundary).",
|
|
114
|
+
"properties": {
|
|
115
|
+
"template": { "type": "string", "minLength": 1, "description": "Prompt body with `{{placeholder}}` slots." },
|
|
116
|
+
"systemPrompt": { "type": "string", "description": "Optional system prompt." },
|
|
117
|
+
"placeholderMapping": {
|
|
118
|
+
"type": "object",
|
|
119
|
+
"additionalProperties": { "type": "string" },
|
|
120
|
+
"description": "Map of `{{placeholder}}` name → input path (e.g. `\"spec\": \"inputs.spec\"`)."
|
|
121
|
+
},
|
|
122
|
+
"temperature": { "type": "number", "minimum": 0, "maximum": 2 },
|
|
123
|
+
"maxTokens": { "type": "integer", "minimum": 1 }
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"InputField": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"required": ["id", "type"],
|
|
129
|
+
"additionalProperties": false,
|
|
130
|
+
"properties": {
|
|
131
|
+
"id": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$" },
|
|
132
|
+
"type": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"description": "Closed portable subset OR a `vendor.<org>.<kind>` / `x-<kind>` host extension other hosts ignore. The portable subset (G9, resolved 2026-05-27 against MyndHyve's `CardFieldType`): `text`, `longtext`, `number`, `boolean`, `select`, `multiselect`, `file`, `artifact-ref`. MyndHyve maps `textarea`→`longtext` and `toggle`→`boolean`; its product-specific kinds (`canvas-reference`, `collection-reference`, `color`) are host extensions (`vendor.myndhyve.*`), not portable.",
|
|
135
|
+
"pattern": "^(text|longtext|number|boolean|select|multiselect|file|artifact-ref|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
|
|
136
|
+
},
|
|
137
|
+
"label": { "type": "string" },
|
|
138
|
+
"required": { "type": "boolean" },
|
|
139
|
+
"default": {},
|
|
140
|
+
"options": {
|
|
141
|
+
"type": "array",
|
|
142
|
+
"items": { "type": "string" },
|
|
143
|
+
"description": "Choices for `type: \"select\"`."
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"Signing": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"description": "Optional signing metadata. See node-packs.md §signing.",
|
|
150
|
+
"additionalProperties": false,
|
|
151
|
+
"properties": {
|
|
152
|
+
"publicKeyRef": { "type": "string" },
|
|
153
|
+
"signatureRef": { "type": "string" },
|
|
154
|
+
"method": { "type": "string", "enum": ["manual", "sigstore"] }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/envelopes/media.audio.schema.json",
|
|
4
|
+
"title": "MediaAudioPayload",
|
|
5
|
+
"description": "Payload for the OPTIONAL `media.audio` AI Envelope kind (RFC 0055 §C). Carries a host-served URL reference (preferred) or, below the host's `aiProviders.maxInlineMediaBytes` cap, inline base64 audio data. Pairs with the `meta.rendering.display: \"audio\"` hint. Advertised, opt-in kind — not a MUST-recognize universal kind.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["bytes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"url": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri",
|
|
12
|
+
"description": "Tenant-scoped, non-guessable host-served asset URL (RFC 0055 §C rule 1). SHOULD be used above `aiProviders.maxInlineMediaBytes`. Enforced by the `media-asset-url-tenant-scoped` SECURITY invariant."
|
|
13
|
+
},
|
|
14
|
+
"base64": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Inline base64-encoded audio, permitted only at or below `aiProviders.maxInlineMediaBytes` (RFC 0055 §C rule 2). Above the cap the host MUST use `url`."
|
|
17
|
+
},
|
|
18
|
+
"bytes": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Byte size of the asset."
|
|
22
|
+
},
|
|
23
|
+
"mimeType": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "IANA media type (e.g. `audio/mpeg`, `audio/wav`, `audio/ogg`). SHOULD match `meta.rendering.mimeType`."
|
|
26
|
+
},
|
|
27
|
+
"durationSeconds": {
|
|
28
|
+
"type": "number",
|
|
29
|
+
"minimum": 0,
|
|
30
|
+
"description": "Optional clip duration in seconds, for a consumer's player UI."
|
|
31
|
+
},
|
|
32
|
+
"alt": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "Text alternative / label for accessibility (RFC 0055 §B); mirrors `meta.rendering.alt` when the producer also sets the rendering hint."
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"additionalProperties": false
|
|
38
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/envelopes/media.file.schema.json",
|
|
4
|
+
"title": "MediaFilePayload",
|
|
5
|
+
"description": "Payload for the OPTIONAL `media.file` AI Envelope kind (RFC 0055 §C). A downloadable, non-inline-rendered asset (document, archive, dataset). Carries a host-served URL reference (preferred) or, below the host's `aiProviders.maxInlineMediaBytes` cap, inline base64. Pairs with the `meta.rendering.display: \"file\"` hint. Advertised, opt-in kind — not a MUST-recognize universal kind.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["bytes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"url": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri",
|
|
12
|
+
"description": "Tenant-scoped, non-guessable host-served asset URL (RFC 0055 §C rule 1). SHOULD be used above `aiProviders.maxInlineMediaBytes`. Enforced by the `media-asset-url-tenant-scoped` SECURITY invariant."
|
|
13
|
+
},
|
|
14
|
+
"base64": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Inline base64-encoded file bytes, permitted only at or below `aiProviders.maxInlineMediaBytes` (RFC 0055 §C rule 2). Above the cap the host MUST use `url`."
|
|
17
|
+
},
|
|
18
|
+
"bytes": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Byte size of the asset."
|
|
22
|
+
},
|
|
23
|
+
"mimeType": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "IANA media type (e.g. `application/pdf`, `text/csv`, `application/zip`). SHOULD match `meta.rendering.mimeType`."
|
|
26
|
+
},
|
|
27
|
+
"name": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Optional suggested filename for download (e.g. `q3-report.pdf`)."
|
|
30
|
+
},
|
|
31
|
+
"alt": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Text alternative / label for accessibility (RFC 0055 §B); mirrors `meta.rendering.alt` when the producer also sets the rendering hint."
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"additionalProperties": false
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/envelopes/media.image.schema.json",
|
|
4
|
+
"title": "MediaImagePayload",
|
|
5
|
+
"description": "Payload for the OPTIONAL `media.image` AI Envelope kind (RFC 0055 §C). Carries a host-served URL reference (preferred) or, below the host's `aiProviders.maxInlineMediaBytes` cap, inline base64 image data. Pairs with the `meta.rendering.display: \"image\"` hint. This is an advertised, opt-in kind — not one of the four MUST-recognize universal kinds; a host that emits no `media.*` kind is unaffected.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["bytes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"url": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri",
|
|
12
|
+
"description": "Tenant-scoped, non-guessable host-served asset URL (RFC 0055 §C rule 1 — signed-token / capability-token discipline). SHOULD be used when the asset exceeds `capabilities.aiProviders.maxInlineMediaBytes`. Enforced by the `media-asset-url-tenant-scoped` SECURITY invariant."
|
|
13
|
+
},
|
|
14
|
+
"base64": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Inline base64-encoded image, permitted only when the asset is at or below `aiProviders.maxInlineMediaBytes` (default 256 KiB, RFC 0055 §C rule 2). Above the cap the host MUST use `url`. Mutually exclusive with `url` in practice — a single envelope carries one or the other."
|
|
17
|
+
},
|
|
18
|
+
"bytes": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Byte size of the asset. Required so a consumer can decide whether to inline-render or defer-fetch, and so the cap rule is checkable."
|
|
22
|
+
},
|
|
23
|
+
"mimeType": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "IANA media type (e.g. `image/png`, `image/jpeg`, `image/webp`). SHOULD match `meta.rendering.mimeType`."
|
|
26
|
+
},
|
|
27
|
+
"alt": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Text alternative for accessibility (RFC 0055 §B). SHOULD be present so a consumer can describe the image to assistive technology; mirrors `meta.rendering.alt` when the producer also sets the rendering hint."
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/heartbeat-evaluated.schema.json",
|
|
4
|
+
"title": "HeartbeatEvaluated",
|
|
5
|
+
"description": "RFC 0060. Emitted every tick by a host advertising `capabilities.heartbeat.supported: true` — the observability record of a heartbeat predicate evaluation. Heartbeat-scoped (NOT a replayable run-event-log entry). Carries no external state or secret material; `changed` gates whether a `heartbeat.stateChanged` + enqueued run follow.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["heartbeatId", "status", "changed"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"heartbeatId": { "type": "string", "minLength": 1, "description": "Host-assigned identifier for the heartbeat whose tick this records." },
|
|
10
|
+
"status": { "type": "string", "enum": ["ok", "timeout", "error"], "description": "`ok` — predicate evaluated within `maxRuntimeMs`. `timeout` — terminated at the budget (RFC 0060 §B.2). `error` — the predicate threw." },
|
|
11
|
+
"changed": { "type": "boolean", "description": "Whether the predicate's state transitioned vs. the prior tick. `true` is the only path that may emit `heartbeat.stateChanged` and enqueue a run." }
|
|
12
|
+
},
|
|
13
|
+
"additionalProperties": false
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/heartbeat-state-changed.schema.json",
|
|
4
|
+
"title": "HeartbeatStateChanged",
|
|
5
|
+
"description": "RFC 0060. Emitted ONLY on a predicate-state transition — an unchanged tick MUST NOT emit it (this is what prevents notification spam). Heartbeat-scoped (NOT a replayable run-event-log entry). `from`/`to` are opaque host-persisted predicate-state tokens; they MUST NOT carry secret or external-content material beyond the minimal state needed to detect a transition.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["heartbeatId", "from", "to"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"heartbeatId": { "type": "string", "minLength": 1, "description": "Host-assigned identifier for the heartbeat that transitioned." },
|
|
10
|
+
"from": { "type": "object", "additionalProperties": true, "description": "Prior tick's predicate state (opaque, host-defined)." },
|
|
11
|
+
"to": { "type": "object", "additionalProperties": true, "description": "Current tick's predicate state — the transition target (opaque, host-defined)." }
|
|
12
|
+
},
|
|
13
|
+
"additionalProperties": false
|
|
14
|
+
}
|
|
@@ -56,7 +56,22 @@
|
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"type": "object",
|
|
58
58
|
"additionalProperties": { "type": "string" },
|
|
59
|
-
"description": "Engine-supplied capabilities the pack consumes (e.g., a particular AI provider extension). Resolved against `Capabilities` at register time."
|
|
59
|
+
"description": "Engine-supplied capabilities the pack consumes (e.g., a particular AI provider extension). Resolved against `Capabilities` at register time. Each entry is REQUIRED by default — an unmet entry fails install with `pack_peer_dependency_missing` — unless marked optional in `peerDependenciesMeta` (RFC 0072 §C)."
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"description": "Per-peer-dependency metadata (RFC 0072 §C). Keys mirror `peerDependencies` keys. Marking an entry `optional: true` makes it degrade-if-unmet instead of refuse-if-unmet: a host that does not satisfy it MUST install the pack with that capability inert AND surface it in the affected agents' inventory `degraded[]` (RFC 0072 §A); it MUST NOT silently ignore the declared dependency. Default (absent entry) is required. Packs published before RFC 0072 validate unchanged.",
|
|
64
|
+
"additionalProperties": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"properties": {
|
|
68
|
+
"optional": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"default": false,
|
|
71
|
+
"description": "When true, an unmet peer dependency degrades (inert + surfaced in `degraded[]`) rather than failing install."
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
60
75
|
},
|
|
61
76
|
"nodes": {
|
|
62
77
|
"type": "array",
|