Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
378 changes: 378 additions & 0 deletions .agents/plugins/evaluations/contentcloud-video-production-0.26.0.json

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions .agents/plugins/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
{
"id": "contentcloud-video-production",
"kind": "scene_plugin",
"version": "0.25.0",
"version": "0.26.0",
"source": {
"repository": "https://github.com/limecloud/contentcloud",
"ref": "v0.25.0"
"ref": "v0.26.0"
},
"license": "Apache-2.0",
"digest": "sha256:e8dabc6ebae6f9a9c264a16a7083e4c7da45aef1e12d68690dc69297691bf9d4",
"digest": "sha256:6c8fdbaa10d887d94880f0451d5b336da871d36faf71a23a85f3d05212b1e756",
"signature": {
"status": "verified",
"algorithm": "ed25519",
"key_id": "contentcloud-plugin-release-2026-07",
"value": "Acl1ei4XN2GR6Oxnzk6KtGBjrdvyegRcMcuMHT6WM/T/X62S2iDp+/NeqSNnzff1J4ff3tANHLO3AJq031a9Dg=="
"value": "lyM2tA6XXRz0Ox+urs9JC2DdfZ6d45mKbKygSJTSvNrEaAo9cwXk/Qwqk3hp0ZJczvv1arj3FGkR57IpKorkBg=="
},
"compatible_profiles": [
"contentcloud.video-production"
Expand Down Expand Up @@ -54,8 +54,8 @@
],
"evaluation": {
"status": "passed",
"report": ".agents/plugins/evaluations/contentcloud-video-production-0.25.0.json",
"digest": "sha256:3fd4adeec6fbbcac651dbb05723c30b0a7dfe27f3af7742a3e455c0039aae555",
"report": ".agents/plugins/evaluations/contentcloud-video-production-0.26.0.json",
"digest": "sha256:84063ed0aa42593ef77cec0e6ac640ae3040cff7b0f256aad2624a652da55edd",
"evidence": [
"codex-plugin-transaction",
"bootstrap-confirmation",
Expand All @@ -67,6 +67,7 @@
"v5-local-production-boundary",
"wechat-article-governance",
"browser-navigation-safety",
"local-workbench-governance",
"environment-control-plane",
"agent-client-governance",
"v7-marketing-video-golden-journey"
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

ContentCloud 的重要变更记录在此文件中。

## [0.26.0] - 2026-08-14

### Added

- 增加 Agent Plugin 的本地 Workspace 工作台能力,通过 `Skills + stdio MCP` 提供类型化 View、digest 固定 Resource 与安全静态 HTML presentation。
- 增加 Attempt 级 Runtime MCP Gateway、Daemon 绑定与运行诊断,使 Codex/Claude Harness 在受控工具边界内恢复本地与云端执行上下文。

### Changed

- 废弃本地 Node/HTTP localhost 工作台方案,宿主面板、Browser 与资源内嵌改为可检测增强,不再作为插件正确性依赖。
- Server、Worker、Web、CLI、Plugin、MCP 和 Environment Profile 统一升级到 `0.26.0`。

### Fixed

- 修复 Codex Harness 在 Runtime Gateway 参数校验失败时创建未释放 context 的问题。

## [0.25.0] - 2026-08-12

### Added
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.25.0
0.26.0
1 change: 1 addition & 0 deletions cmd/contentcloud-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func main() {
}()
}
httpOptions := providerCallbackHTTPOptions(os.Getenv("CONTENTCLOUD_PROVIDER_CALLBACK_SECRETS"))
httpOptions = append(httpOptions, httpapi.WithRuntimeWakeContext(workerCtx))
httpOptions = append(httpOptions, channelCallbackHTTPOptions(os.Getenv("CONTENTCLOUD_CHANNEL_CALLBACK_SECRETS"))...)
httpOptions = append(httpOptions, agentCallbackHTTPOptions(os.Getenv("CONTENTCLOUD_AGENT_CALLBACK_SECRETS"))...)
server := &http.Server{Addr: addr, Handler: httpapi.New(service, logger, devMode, webDist, httpOptions...).Handler(), ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 35 * time.Second, IdleTimeout: 60 * time.Second}
Expand Down
59 changes: 59 additions & 0 deletions contracts/embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,62 @@ func TestStudioOpenAPIContractKeepsProductBoundaries(t *testing.T) {
}
}
}

func TestRuntimeWorkerOpenAPIContractMatchesCurrentServerBoundary(t *testing.T) {
var document struct {
Components struct {
Schemas map[string]map[string]any `yaml:"schemas"`
} `yaml:"components"`
}
if err := yaml.Unmarshal(OpenAPIYAML, &document); err != nil {
t.Fatalf("openapi.yaml is invalid: %v", err)
}
schema, ok := document.Components.Schemas["RuntimeWorkerPrepareInput"]
if !ok {
t.Fatal("RuntimeWorkerPrepareInput schema is missing")
}
required, ok := schema["required"].([]any)
if !ok {
t.Fatalf("RuntimeWorkerPrepareInput.required has unexpected type: %#v", schema["required"])
}
got := map[string]bool{}
for _, value := range required {
if name, ok := value.(string); ok {
got[name] = true
}
}
if !got["harness_kind"] || !got["capabilities"] || len(got) != 2 {
t.Fatalf("RuntimeWorkerPrepareInput.required=%v, want only harness_kind and capabilities", got)
}
properties, ok := schema["properties"].(map[string]any)
if !ok {
t.Fatalf("RuntimeWorkerPrepareInput.properties has unexpected type: %#v", schema["properties"])
}
for _, retired := range []string{"role", "execution_profile_id", "max_tokens", "budget_minor", "remaining_descendants", "workspace", "prompt"} {
if _, exists := properties[retired]; exists {
t.Fatalf("RuntimeWorkerPrepareInput still exposes retired client-controlled field %q", retired)
}
}
if _, ok := properties["daemon_instance_id"]; !ok {
t.Fatal("RuntimeWorkerPrepareInput must expose daemon_instance_id")
}
for _, path := range []string{"/v1/runtime/worker/control", "/v1/runtime/mcp/call"} {
var raw map[string]any
if err := yaml.Unmarshal(OpenAPIYAML, &raw); err != nil {
t.Fatal(err)
}
paths, ok := raw["paths"].(map[string]any)
if !ok {
t.Fatal("OpenAPI paths have unexpected type")
}
if _, ok := paths[path]; !ok {
t.Fatalf("Runtime path %q is missing from OpenAPI", path)
}
}
if _, ok := document.Components.Schemas["RuntimeGatewayCallInput"]; !ok {
t.Fatal("RuntimeGatewayCallInput schema is missing")
}
if _, ok := document.Components.Schemas["RuntimeControlSyncFrame"]; !ok {
t.Fatal("RuntimeControlSyncFrame schema is missing")
}
}
93 changes: 71 additions & 22 deletions contracts/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,39 @@ paths:
'401': {$ref: '#/components/responses/Error'}
'403': {$ref: '#/components/responses/Error'}
'409': {$ref: '#/components/responses/Error'}
/v1/runtime/worker/control:
get:
tags: [CLI]
operationId: openRuntimeWorkerControl
summary: Upgrade to the device-authenticated Runtime WebSocket control channel
description: >-
The first client text frame must be RuntimeControlSyncFrame. The server
acknowledges it with control.ready, emits coalesced runtime.available
wakeups, and sends control.heartbeat requests. Runtime commands, leases,
events, finalization, and MCP calls remain on HTTPS.
security: [{bearerAuth: []}]
responses:
'101': {description: WebSocket protocol switched}
'401': {$ref: '#/components/responses/Error'}
'503': {$ref: '#/components/responses/Error'}
/v1/runtime/mcp/call:
post:
tags: [CLI]
operationId: callRuntimeMCPGateway
summary: Call an Attempt-scoped Runtime MCP tool
description: >-
Accepts only a short-lived rtg_ credential. Tenant, Attempt, lease, fence,
ContextView, and tool allowlist are derived and revalidated server-side.
security: [{runtimeGatewayAuth: []}]
requestBody:
required: true
content:
application/json: {schema: {$ref: '#/components/schemas/RuntimeGatewayCallInput'}}
responses:
'200': {$ref: '#/components/responses/Success'}
'400': {$ref: '#/components/responses/Error'}
'401': {$ref: '#/components/responses/Error'}
'409': {$ref: '#/components/responses/Error'}
/v1/providers/{provider_id}/tenants/{tenant_id}/callbacks:
parameters:
- {name: provider_id, in: path, required: true, schema: {type: string}}
Expand Down Expand Up @@ -1671,6 +1704,7 @@ components:
securitySchemes:
cookieAuth: {type: apiKey, in: cookie, name: cc_session}
bearerAuth: {type: http, scheme: bearer}
runtimeGatewayAuth: {type: http, scheme: bearer, bearerFormat: rtg_}
parameters:
ProjectID: {name: project_id, in: path, required: true, schema: {type: string, format: uuid}}
ID: {name: id, in: path, required: true, schema: {type: string, format: uuid}}
Expand Down Expand Up @@ -2610,32 +2644,19 @@ components:
RuntimeWorkerPrepareInput:
type: object
additionalProperties: false
required: [harness_kind, capabilities, role, execution_profile_id, max_tokens, budget_minor, remaining_descendants]
required: [harness_kind, capabilities]
properties:
job_run_id: {type: string, format: uuid}
daemon_instance_id: {type: string, format: uuid}
harness_kind: {type: string, minLength: 1}
capabilities: {$ref: '#/components/schemas/RuntimeHarnessCapabilities'}
role: {type: string, minLength: 1}
execution_profile_id: {type: string, minLength: 1}
workspace: {type: string}
prompt: {type: string}
output_schema: {type: object, additionalProperties: true}
input_refs: {type: array, items: {type: string}}
state_refs: {type: array, items: {type: string}}
event_refs: {type: array, items: {type: string}}
allowed_tools: {type: array, items: {type: string}}
max_tokens: {type: integer, minimum: 1}
budget_minor: {type: integer, minimum: 0}
remaining_descendants: {type: integer, minimum: 0}
lease_for_seconds: {type: integer, minimum: 1}
context_ttl_seconds: {type: integer, minimum: 1}
resource_requests: {type: array, items: {type: object, additionalProperties: false}}
RuntimeHarnessCapabilities:
type: object
additionalProperties: false
required: [kind, events, resume, fork, mcp_stdio, mcp_http, structured_output, sandbox_profile, max_parallel_sessions, transcript_export]
properties:
kind: {type: string, minLength: 1}
version: {type: string}
events: {type: boolean}
resume: {type: boolean}
fork: {type: boolean}
Expand All @@ -2650,29 +2671,32 @@ components:
additionalProperties: false
required: [harness_kind, session_id]
properties:
tenant_id: {type: string, format: uuid}
tenant_id: {type: string, format: uuid, readOnly: true, description: Server-derived tenant scope; clients must not choose it.}
harness_kind: {type: string}
session_id: {type: string, minLength: 1}
RuntimeWorkerActivateInput:
type: object
additionalProperties: false
required: [attempt_id, fence_token, session]
required: [daemon_instance_id, attempt_id, fence_token, session]
properties:
daemon_instance_id: {type: string, format: uuid}
attempt_id: {type: string, format: uuid}
fence_token: {type: string, minLength: 1}
session: {$ref: '#/components/schemas/RuntimeWorkerSession'}
RuntimeWorkerHeartbeatInput:
type: object
additionalProperties: false
required: [attempt_id, fence_token]
required: [daemon_instance_id, attempt_id, fence_token]
properties:
daemon_instance_id: {type: string, format: uuid}
attempt_id: {type: string, format: uuid}
fence_token: {type: string, minLength: 1}
RuntimeWorkerEventInput:
type: object
additionalProperties: false
required: [attempt_id, fence_token, event]
required: [daemon_instance_id, attempt_id, fence_token, event]
properties:
daemon_instance_id: {type: string, format: uuid}
attempt_id: {type: string, format: uuid}
fence_token: {type: string, minLength: 1}
event:
Expand All @@ -2682,14 +2706,15 @@ components:
properties:
type: {type: string, minLength: 1}
session: {$ref: '#/components/schemas/RuntimeWorkerSession'}
data: {type: object, additionalProperties: true}
data: {description: Arbitrary JSON event payload; Runtime stores only a bounded canonical digest.}
error_code: {type: string}
occurred_at: {type: string, format: date-time}
RuntimeWorkerFinalizeInput:
type: object
additionalProperties: false
required: [attempt_id, fence_token, state]
required: [daemon_instance_id, attempt_id, fence_token, state]
properties:
daemon_instance_id: {type: string, format: uuid}
attempt_id: {type: string, format: uuid}
fence_token: {type: string, minLength: 1}
state: {type: string, enum: [succeeded, retryable_failed, failed, cancelled]}
Expand All @@ -2700,6 +2725,29 @@ components:
error_code: {type: string}
used_cost_minor: {type: integer, minimum: 0}
business_payload: {type: object, additionalProperties: true}
RuntimeGatewayCallInput:
type: object
additionalProperties: false
required: [tool_name, request_id, arguments]
properties:
tool_name: {type: string, minLength: 1}
request_id: {type: string, minLength: 1}
arguments: {type: object, additionalProperties: true}
RuntimeControlSyncFrame:
type: object
additionalProperties: false
required: [type, daemon_instance_id, connection_epoch, report_seq, pid, version, state, capabilities, active_attempts, started_at]
properties:
type: {const: control.sync_state}
daemon_instance_id: {type: string, format: uuid}
connection_epoch: {type: integer, minimum: 1}
report_seq: {type: integer, minimum: 1}
pid: {type: integer, minimum: 0}
version: {type: string, minLength: 1}
state: {type: string, enum: [connected, degraded]}
capabilities: {type: object, additionalProperties: true}
active_attempts: {type: array, maxItems: 32, uniqueItems: true, items: {type: string}}
started_at: {type: string, format: date-time}
LineageNode:
type: object
additionalProperties: false
Expand Down Expand Up @@ -3150,6 +3198,7 @@ components:
required: [kind, events, resume, fork, mcp_stdio, mcp_http, structured_output, sandbox_profile, max_parallel_sessions, transcript_export]
properties:
kind: {type: string, enum: [fake, codex, claude, remote-http, pi, agent-saas]}
version: {type: string}
events: {type: boolean}
resume: {type: boolean}
fork: {type: boolean}
Expand Down
2 changes: 1 addition & 1 deletion deploy/systemd/contentcloud.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ CONTENTCLOUD_PI_AGENT_ENDPOINT=
CONTENTCLOUD_PI_AGENT_TOKEN=
CONTENTCLOUD_AGENT_SAAS_ENDPOINT=
CONTENTCLOUD_AGENT_SAAS_TOKEN=
CONTENTCLOUD_CAPABILITY_RELEASE_VERSION=0.25.0
CONTENTCLOUD_CAPABILITY_RELEASE_VERSION=0.26.0
CONTENTCLOUD_ENVIRONMENT_MANIFEST_TTL=24h
2 changes: 1 addition & 1 deletion deploy/systemd/environment-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{
"id": "contentcloud-video-production",
"kind": "scene_plugin",
"version": "0.25.0",
"version": "0.26.0",
"required": true,
"scope": "environment",
"capabilities": [
Expand Down
Loading
Loading