forked from EduCraft/curriculum-project-hub
8df8156969
Introduces the External Capability abstraction: platform-registered, org-enabled document/media transform services invoked as side effects of an AgentRun. The first concrete capability is pdf_to_md_bundle backed by MinerU. This lands the contract, schema, adapter interface, and a fully mock-tested adapter; the real MinerU HTTP client is deferred until credentials and pricing are confirmed. Contract: - spec/Spec/System/Agent/Capability.lean pins ExternalCapability, OrganizationCapabilityConnection (reuses ADR-0024 envelope, distinct from model-provider connection), and CapabilityInvocation.Authorized (workspace containment predicate, ADR-0018). lake build green (41 jobs). - ADR-0027 records why capability credentials are a separate connection type (MinerU/Whisper have their own auth shape, not OpenRouter /v1/models), the adapter seam, and what is deferred (capability invocation record, pricebook, agent-facing tool discovery). Schema: - OrganizationCapabilityConnection + CapabilityCredentialVersion, mirroring the Feishu Application Connection shape. Unique by (organizationId, capabilityId). Migration 20260718130000 applied. Adapter (hub/src/capability): - types.ts: CapabilityId, CapabilityAdapter interface, secret payload, CapabilityConnectionUnavailable. - mineruClient.ts: MineruClient interface + MineruParseResult + errors. Real HTTP client deferred; the interface is the seam. - capabilityConnections.ts: resolveCapabilityCredential — org-scoped, fail-closed, reuses LocalSecretEnvelope with purpose="capability". - pdfToMdBundle.ts: adapter that resolves credential, confines input/output to the run workspace (ADR-0018), calls MineruClient, writes md + images into workspace, and writes a UsageFact (kind=external_capability, quantity=pages, costSource=provider_reported|unknown per ADR-0022). Tests (7, all green): - md + images written to workspace, UsageFact attributes pages + cost - costUsd null -> costSource=unknown (missing cost != zero, ADR-0022) - no ACTIVE connection -> fail-closed, no fact written - input/output path escape -> CapabilityPathEscape - MinerU client error propagates, no fact written - empty markdown -> parse failure Deferred (needs operator): MinerU account/API key/pricing, real MineruClient HTTP implementation, org admin UI for capability connection management, agent-facing tool exposure (MCP vs built-in).