diff --git a/epiphany-core/src/bin/epiphany-mvp-coordinator.rs b/epiphany-core/src/bin/epiphany-mvp-coordinator.rs index 1fe75359..26925ba7 100644 --- a/epiphany-core/src/bin/epiphany-mvp-coordinator.rs +++ b/epiphany-core/src/bin/epiphany-mvp-coordinator.rs @@ -512,7 +512,7 @@ fn collect_coordinator_status( )?; let view = client.send( "thread/epiphany/view", - Some(json!({"threadId": thread_id, "lenses": ["scene", "pressure", "jobs"]})), + Some(json!({"threadId": thread_id, "lenses": ["scene", "pressure", "jobs", "roles", "planning", "reorient", "crrc", "coordinator"]})), true, )?; let scene = json!({ @@ -524,26 +524,14 @@ fn collect_coordinator_status( "source": "live", "pressure": view.get("pressure").cloned().unwrap_or_else(|| json!(null)), }); - let reorient = client.send( - "thread/epiphany/reorient", - Some(json!({"threadId": thread_id})), - true, - )?; + let reorient = view.get("reorient").cloned().unwrap_or_else(|| json!(null)); let jobs = json!({ "threadId": thread_id, "source": "live", "jobs": view.get("jobs").cloned().unwrap_or_else(|| json!([])), }); - let roles = client.send( - "thread/epiphany/roles", - Some(json!({"threadId": thread_id})), - true, - )?; - let planning = client.send( - "thread/epiphany/planning", - Some(json!({"threadId": thread_id})), - true, - )?; + let roles = view.get("roles").cloned().unwrap_or_else(|| json!(null)); + let planning = view.get("planning").cloned().unwrap_or_else(|| json!(null)); let role_results = json!({ "imagination": client.send("thread/epiphany/roleResult", Some(json!({"threadId": thread_id, "roleId": "imagination"})), true)?, "modeling": client.send("thread/epiphany/roleResult", Some(json!({"threadId": thread_id, "roleId": "modeling"})), true)?, @@ -554,16 +542,8 @@ fn collect_coordinator_status( Some(json!({"threadId": thread_id})), true, )?; - let crrc = client.send( - "thread/epiphany/crrc", - Some(json!({"threadId": thread_id})), - true, - )?; - let coordinator = client.send( - "thread/epiphany/coordinator", - Some(json!({"threadId": thread_id})), - true, - )?; + let crrc = view.get("crrc").cloned().unwrap_or_else(|| json!(null)); + let coordinator = view.get("coordinator").cloned().unwrap_or_else(|| json!(null)); let root = env::current_dir()?; let heartbeat_dir = root.join(".epiphany-heartbeats"); let face_dir = root.join(".epiphany-face"); diff --git a/epiphany-core/src/bin/epiphany-mvp-status.rs b/epiphany-core/src/bin/epiphany-mvp-status.rs index 828119f3..277194cc 100644 --- a/epiphany-core/src/bin/epiphany-mvp-status.rs +++ b/epiphany-core/src/bin/epiphany-mvp-status.rs @@ -161,7 +161,7 @@ fn run_status(args: &Args) -> Result { )?; let view = client.send( "thread/epiphany/view", - Some(json!({"threadId": thread_id, "lenses": ["scene", "pressure", "jobs"]})), + Some(json!({"threadId": thread_id, "lenses": ["scene", "pressure", "jobs", "roles", "planning", "reorient", "crrc", "coordinator"]})), true, )?; let scene = json!({ @@ -173,26 +173,14 @@ fn run_status(args: &Args) -> Result { "source": "live", "pressure": view.get("pressure").cloned().unwrap_or_else(|| json!(null)), }); - let reorient = client.send( - "thread/epiphany/reorient", - Some(json!({"threadId": thread_id})), - true, - )?; + let reorient = view.get("reorient").cloned().unwrap_or_else(|| json!(null)); let jobs = json!({ "threadId": thread_id, "source": "live", "jobs": view.get("jobs").cloned().unwrap_or_else(|| json!([])), }); - let roles = client.send( - "thread/epiphany/roles", - Some(json!({"threadId": thread_id})), - true, - )?; - let planning = client.send( - "thread/epiphany/planning", - Some(json!({"threadId": thread_id})), - true, - )?; + let roles = view.get("roles").cloned().unwrap_or_else(|| json!(null)); + let planning = view.get("planning").cloned().unwrap_or_else(|| json!(null)); let role_results = json!({ "imagination": client.send("thread/epiphany/roleResult", Some(json!({"threadId": thread_id, "roleId": "imagination"})), true)?, "modeling": client.send("thread/epiphany/roleResult", Some(json!({"threadId": thread_id, "roleId": "modeling"})), true)?, @@ -203,16 +191,8 @@ fn run_status(args: &Args) -> Result { Some(json!({"threadId": thread_id})), true, )?; - let crrc = client.send( - "thread/epiphany/crrc", - Some(json!({"threadId": thread_id})), - true, - )?; - let coordinator = client.send( - "thread/epiphany/coordinator", - Some(json!({"threadId": thread_id})), - true, - )?; + let crrc = view.get("crrc").cloned().unwrap_or_else(|| json!(null)); + let coordinator = view.get("coordinator").cloned().unwrap_or_else(|| json!(null)); let root = env::current_dir().context("failed to resolve current directory")?; let heartbeat_dir = root.join(".epiphany-heartbeats"); let face_dir = root.join(".epiphany-face"); diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/vendor/codex/codex-rs/app-server-protocol/schema/json/ClientRequest.json index 199846e7..7cf601f0 100644 --- a/vendor/codex/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/vendor/codex/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -4753,7 +4753,12 @@ "enum": [ "scene", "jobs", - "pressure" + "roles", + "planning", + "pressure", + "reorient", + "crrc", + "coordinator" ], "type": "string" }, diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 7f6a2aab..09db276b 100644 --- a/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -17833,14 +17833,278 @@ }, "type": "object" }, + "ThreadEpiphanyViewCoordinator": { + "properties": { + "action": { + "$ref": "#/definitions/v2/ThreadEpiphanyCoordinatorAction" + }, + "canAutoRun": { + "type": "boolean" + }, + "note": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "recommendedSceneAction": { + "anyOf": [ + { + "$ref": "#/definitions/v2/ThreadEpiphanySceneAction" + }, + { + "type": "null" + } + ] + }, + "requiresReview": { + "type": "boolean" + }, + "roles": { + "items": { + "$ref": "#/definitions/v2/ThreadEpiphanyRoleLane" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/v2/ThreadEpiphanyRolesSource" + }, + "sourceSignals": { + "$ref": "#/definitions/v2/ThreadEpiphanyCoordinatorSignals" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientStateStatus" + }, + "targetRole": { + "anyOf": [ + { + "$ref": "#/definitions/v2/ThreadEpiphanyRoleId" + }, + { + "type": "null" + } + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "action", + "canAutoRun", + "note", + "reason", + "requiresReview", + "roles", + "source", + "sourceSignals", + "stateStatus", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewCrrc": { + "properties": { + "availableActions": { + "items": { + "$ref": "#/definitions/v2/ThreadEpiphanySceneAction" + }, + "type": "array" + }, + "decision": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientDecision" + }, + "note": { + "type": "string" + }, + "pressure": { + "$ref": "#/definitions/v2/ThreadEpiphanyPressure" + }, + "recommendation": { + "$ref": "#/definitions/v2/ThreadEpiphanyCrrcRecommendation" + }, + "reorientBindingId": { + "type": "string" + }, + "reorientFinding": { + "anyOf": [ + { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientFinding" + }, + { + "type": "null" + } + ] + }, + "reorientJob": { + "anyOf": [ + { + "$ref": "#/definitions/v2/ThreadEpiphanyJob" + }, + { + "type": "null" + } + ] + }, + "reorientResultStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientResultStatus" + }, + "source": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "decision", + "note", + "pressure", + "recommendation", + "reorientBindingId", + "reorientResultStatus", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, "ThreadEpiphanyViewLens": { "enum": [ "scene", "jobs", - "pressure" + "roles", + "planning", + "pressure", + "reorient", + "crrc", + "coordinator" ], "type": "string" }, + "ThreadEpiphanyViewPlanning": { + "properties": { + "planning": { + "$ref": "#/definitions/v2/EpiphanyPlanningState" + }, + "source": { + "$ref": "#/definitions/v2/ThreadEpiphanyContextSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyContextStateStatus" + }, + "summary": { + "$ref": "#/definitions/v2/ThreadEpiphanyPlanningSummary" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "planning", + "source", + "stateStatus", + "summary", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewReorient": { + "properties": { + "decision": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientDecision" + }, + "source": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "decision", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewRoles": { + "properties": { + "note": { + "type": "string" + }, + "roles": { + "items": { + "$ref": "#/definitions/v2/ThreadEpiphanyRoleLane" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/v2/ThreadEpiphanyRolesSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/v2/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "note", + "roles", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, "ThreadForkParams": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using path, the thread_id param will be ignored.\n\nPrefer using thread_id whenever possible.", diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 08d5bef9..c6de71ff 100644 --- a/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/vendor/codex/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -15720,14 +15720,278 @@ }, "type": "object" }, + "ThreadEpiphanyViewCoordinator": { + "properties": { + "action": { + "$ref": "#/definitions/ThreadEpiphanyCoordinatorAction" + }, + "canAutoRun": { + "type": "boolean" + }, + "note": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "recommendedSceneAction": { + "anyOf": [ + { + "$ref": "#/definitions/ThreadEpiphanySceneAction" + }, + { + "type": "null" + } + ] + }, + "requiresReview": { + "type": "boolean" + }, + "roles": { + "items": { + "$ref": "#/definitions/ThreadEpiphanyRoleLane" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/ThreadEpiphanyRolesSource" + }, + "sourceSignals": { + "$ref": "#/definitions/ThreadEpiphanyCoordinatorSignals" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/ThreadEpiphanyReorientStateStatus" + }, + "targetRole": { + "anyOf": [ + { + "$ref": "#/definitions/ThreadEpiphanyRoleId" + }, + { + "type": "null" + } + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "action", + "canAutoRun", + "note", + "reason", + "requiresReview", + "roles", + "source", + "sourceSignals", + "stateStatus", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewCrrc": { + "properties": { + "availableActions": { + "items": { + "$ref": "#/definitions/ThreadEpiphanySceneAction" + }, + "type": "array" + }, + "decision": { + "$ref": "#/definitions/ThreadEpiphanyReorientDecision" + }, + "note": { + "type": "string" + }, + "pressure": { + "$ref": "#/definitions/ThreadEpiphanyPressure" + }, + "recommendation": { + "$ref": "#/definitions/ThreadEpiphanyCrrcRecommendation" + }, + "reorientBindingId": { + "type": "string" + }, + "reorientFinding": { + "anyOf": [ + { + "$ref": "#/definitions/ThreadEpiphanyReorientFinding" + }, + { + "type": "null" + } + ] + }, + "reorientJob": { + "anyOf": [ + { + "$ref": "#/definitions/ThreadEpiphanyJob" + }, + { + "type": "null" + } + ] + }, + "reorientResultStatus": { + "$ref": "#/definitions/ThreadEpiphanyReorientResultStatus" + }, + "source": { + "$ref": "#/definitions/ThreadEpiphanyReorientSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "decision", + "note", + "pressure", + "recommendation", + "reorientBindingId", + "reorientResultStatus", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, "ThreadEpiphanyViewLens": { "enum": [ "scene", "jobs", - "pressure" + "roles", + "planning", + "pressure", + "reorient", + "crrc", + "coordinator" ], "type": "string" }, + "ThreadEpiphanyViewPlanning": { + "properties": { + "planning": { + "$ref": "#/definitions/EpiphanyPlanningState" + }, + "source": { + "$ref": "#/definitions/ThreadEpiphanyContextSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/ThreadEpiphanyContextStateStatus" + }, + "summary": { + "$ref": "#/definitions/ThreadEpiphanyPlanningSummary" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "planning", + "source", + "stateStatus", + "summary", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewReorient": { + "properties": { + "decision": { + "$ref": "#/definitions/ThreadEpiphanyReorientDecision" + }, + "source": { + "$ref": "#/definitions/ThreadEpiphanyReorientSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "decision", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, + "ThreadEpiphanyViewRoles": { + "properties": { + "note": { + "type": "string" + }, + "roles": { + "items": { + "$ref": "#/definitions/ThreadEpiphanyRoleLane" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/ThreadEpiphanyRolesSource" + }, + "stateRevision": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "stateStatus": { + "$ref": "#/definitions/ThreadEpiphanyReorientStateStatus" + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "note", + "roles", + "source", + "stateStatus", + "threadId" + ], + "type": "object" + }, "ThreadForkParams": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "There are two ways to fork a thread: 1. By thread_id: load the thread from disk by thread_id and fork it into a new thread. 2. By path: load the thread from disk by path and fork it into a new thread.\n\nIf using path, the thread_id param will be ignored.\n\nPrefer using thread_id whenever possible.", diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCoordinator.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCoordinator.ts new file mode 100644 index 00000000..3f6f25c7 --- /dev/null +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCoordinator.ts @@ -0,0 +1,12 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ThreadEpiphanyCoordinatorAction } from "./ThreadEpiphanyCoordinatorAction"; +import type { ThreadEpiphanyCoordinatorSignals } from "./ThreadEpiphanyCoordinatorSignals"; +import type { ThreadEpiphanyReorientStateStatus } from "./ThreadEpiphanyReorientStateStatus"; +import type { ThreadEpiphanyRoleId } from "./ThreadEpiphanyRoleId"; +import type { ThreadEpiphanyRoleLane } from "./ThreadEpiphanyRoleLane"; +import type { ThreadEpiphanyRolesSource } from "./ThreadEpiphanyRolesSource"; +import type { ThreadEpiphanySceneAction } from "./ThreadEpiphanySceneAction"; + +export type ThreadEpiphanyViewCoordinator = { threadId: string, source: ThreadEpiphanyRolesSource, stateStatus: ThreadEpiphanyReorientStateStatus, stateRevision?: bigint | null, action: ThreadEpiphanyCoordinatorAction, targetRole?: ThreadEpiphanyRoleId | null, recommendedSceneAction?: ThreadEpiphanySceneAction | null, requiresReview: boolean, canAutoRun: boolean, reason: string, sourceSignals: ThreadEpiphanyCoordinatorSignals, roles: Array, note: string, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCrrc.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCrrc.ts new file mode 100644 index 00000000..569c1d93 --- /dev/null +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewCrrc.ts @@ -0,0 +1,14 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ThreadEpiphanyCrrcRecommendation } from "./ThreadEpiphanyCrrcRecommendation"; +import type { ThreadEpiphanyJob } from "./ThreadEpiphanyJob"; +import type { ThreadEpiphanyPressure } from "./ThreadEpiphanyPressure"; +import type { ThreadEpiphanyReorientDecision } from "./ThreadEpiphanyReorientDecision"; +import type { ThreadEpiphanyReorientFinding } from "./ThreadEpiphanyReorientFinding"; +import type { ThreadEpiphanyReorientResultStatus } from "./ThreadEpiphanyReorientResultStatus"; +import type { ThreadEpiphanyReorientSource } from "./ThreadEpiphanyReorientSource"; +import type { ThreadEpiphanyReorientStateStatus } from "./ThreadEpiphanyReorientStateStatus"; +import type { ThreadEpiphanySceneAction } from "./ThreadEpiphanySceneAction"; + +export type ThreadEpiphanyViewCrrc = { threadId: string, source: ThreadEpiphanyReorientSource, stateStatus: ThreadEpiphanyReorientStateStatus, stateRevision?: bigint | null, pressure: ThreadEpiphanyPressure, decision: ThreadEpiphanyReorientDecision, recommendation: ThreadEpiphanyCrrcRecommendation, reorientBindingId: string, reorientResultStatus: ThreadEpiphanyReorientResultStatus, reorientJob?: ThreadEpiphanyJob | null, reorientFinding?: ThreadEpiphanyReorientFinding | null, availableActions?: Array, note: string, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewLens.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewLens.ts index e66dfb5a..6bcf5dfa 100644 --- a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewLens.ts +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewLens.ts @@ -2,4 +2,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type ThreadEpiphanyViewLens = "scene" | "jobs" | "pressure"; +export type ThreadEpiphanyViewLens = "scene" | "jobs" | "roles" | "planning" | "pressure" | "reorient" | "crrc" | "coordinator"; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewPlanning.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewPlanning.ts new file mode 100644 index 00000000..8dc0e239 --- /dev/null +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewPlanning.ts @@ -0,0 +1,9 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { EpiphanyPlanningState } from "../EpiphanyPlanningState"; +import type { ThreadEpiphanyContextSource } from "./ThreadEpiphanyContextSource"; +import type { ThreadEpiphanyContextStateStatus } from "./ThreadEpiphanyContextStateStatus"; +import type { ThreadEpiphanyPlanningSummary } from "./ThreadEpiphanyPlanningSummary"; + +export type ThreadEpiphanyViewPlanning = { threadId: string, source: ThreadEpiphanyContextSource, stateStatus: ThreadEpiphanyContextStateStatus, stateRevision?: bigint | null, planning: EpiphanyPlanningState, summary: ThreadEpiphanyPlanningSummary, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewReorient.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewReorient.ts new file mode 100644 index 00000000..6c8ac8db --- /dev/null +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewReorient.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ThreadEpiphanyReorientDecision } from "./ThreadEpiphanyReorientDecision"; +import type { ThreadEpiphanyReorientSource } from "./ThreadEpiphanyReorientSource"; +import type { ThreadEpiphanyReorientStateStatus } from "./ThreadEpiphanyReorientStateStatus"; + +export type ThreadEpiphanyViewReorient = { threadId: string, source: ThreadEpiphanyReorientSource, stateStatus: ThreadEpiphanyReorientStateStatus, stateRevision?: bigint | null, decision: ThreadEpiphanyReorientDecision, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewRoles.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewRoles.ts new file mode 100644 index 00000000..f1790e76 --- /dev/null +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/ThreadEpiphanyViewRoles.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ThreadEpiphanyReorientStateStatus } from "./ThreadEpiphanyReorientStateStatus"; +import type { ThreadEpiphanyRoleLane } from "./ThreadEpiphanyRoleLane"; +import type { ThreadEpiphanyRolesSource } from "./ThreadEpiphanyRolesSource"; + +export type ThreadEpiphanyViewRoles = { threadId: string, source: ThreadEpiphanyRolesSource, stateStatus: ThreadEpiphanyReorientStateStatus, stateRevision?: bigint | null, roles: Array, note: string, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index e626bfaa..8c5bcbfd 100644 --- a/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/vendor/codex/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -387,7 +387,12 @@ export type { ThreadEpiphanyStateUpdatedField } from "./ThreadEpiphanyStateUpdat export type { ThreadEpiphanyStateUpdatedNotification } from "./ThreadEpiphanyStateUpdatedNotification"; export type { ThreadEpiphanyStateUpdatedSource } from "./ThreadEpiphanyStateUpdatedSource"; export type { ThreadEpiphanyUpdatePatch } from "./ThreadEpiphanyUpdatePatch"; +export type { ThreadEpiphanyViewCoordinator } from "./ThreadEpiphanyViewCoordinator"; +export type { ThreadEpiphanyViewCrrc } from "./ThreadEpiphanyViewCrrc"; export type { ThreadEpiphanyViewLens } from "./ThreadEpiphanyViewLens"; +export type { ThreadEpiphanyViewPlanning } from "./ThreadEpiphanyViewPlanning"; +export type { ThreadEpiphanyViewReorient } from "./ThreadEpiphanyViewReorient"; +export type { ThreadEpiphanyViewRoles } from "./ThreadEpiphanyViewRoles"; export type { ThreadForkParams } from "./ThreadForkParams"; export type { ThreadForkResponse } from "./ThreadForkResponse"; export type { ThreadInjectItemsParams } from "./ThreadInjectItemsParams"; diff --git a/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs b/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs index 57552d7b..18cc6fc3 100644 --- a/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs @@ -1914,6 +1914,8 @@ mod tests { lenses: vec![v2::ThreadEpiphanyViewLens::Pressure], scene: None, jobs: Vec::new(), + roles: None, + planning: None, pressure: Some(v2::ThreadEpiphanyPressure { status: v2::ThreadEpiphanyPressureStatus::Ready, level: v2::ThreadEpiphanyPressureLevel::Low, @@ -1927,6 +1929,9 @@ mod tests { note: "Context window usage is below the compaction prep threshold." .to_string(), }), + reorient: None, + crrc: None, + coordinator: None, }, }; diff --git a/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs b/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs index 6bfa6839..384f0ac7 100644 --- a/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -3946,7 +3946,12 @@ pub struct ThreadEpiphanySceneResponse { pub enum ThreadEpiphanyViewLens { Scene, Jobs, + Roles, + Planning, Pressure, + Reorient, + Crrc, + Coordinator, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] @@ -3958,23 +3963,6 @@ pub struct ThreadEpiphanyViewParams { pub lenses: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export_to = "v2/")] -pub struct ThreadEpiphanyViewResponse { - pub thread_id: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub lenses: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional = nullable)] - pub scene: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub jobs: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional = nullable)] - pub pressure: Option, -} - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] @@ -5203,6 +5191,130 @@ pub struct ThreadEpiphanyCrrcRecommendation { pub reason: String, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewResponse { + pub thread_id: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub lenses: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub scene: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub jobs: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub roles: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub planning: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub pressure: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub reorient: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub crrc: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub coordinator: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewRoles { + pub thread_id: String, + pub source: ThreadEpiphanyRolesSource, + pub state_status: ThreadEpiphanyReorientStateStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub state_revision: Option, + pub roles: Vec, + pub note: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewPlanning { + pub thread_id: String, + pub source: ThreadEpiphanyContextSource, + pub state_status: ThreadEpiphanyContextStateStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub state_revision: Option, + pub planning: CoreEpiphanyPlanningState, + pub summary: ThreadEpiphanyPlanningSummary, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewReorient { + pub thread_id: String, + pub source: ThreadEpiphanyReorientSource, + pub state_status: ThreadEpiphanyReorientStateStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub state_revision: Option, + pub decision: ThreadEpiphanyReorientDecision, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewCrrc { + pub thread_id: String, + pub source: ThreadEpiphanyReorientSource, + pub state_status: ThreadEpiphanyReorientStateStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub state_revision: Option, + pub pressure: ThreadEpiphanyPressure, + pub decision: ThreadEpiphanyReorientDecision, + pub recommendation: ThreadEpiphanyCrrcRecommendation, + pub reorient_binding_id: String, + pub reorient_result_status: ThreadEpiphanyReorientResultStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub reorient_job: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub reorient_finding: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub available_actions: Vec, + pub note: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadEpiphanyViewCoordinator { + pub thread_id: String, + pub source: ThreadEpiphanyRolesSource, + pub state_status: ThreadEpiphanyReorientStateStatus, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub state_revision: Option, + pub action: ThreadEpiphanyCoordinatorAction, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub target_role: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional = nullable)] + pub recommended_scene_action: Option, + pub requires_review: bool, + pub can_auto_run: bool, + pub reason: String, + pub source_signals: ThreadEpiphanyCoordinatorSignals, + pub roles: Vec, + pub note: String, +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] diff --git a/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs b/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs index 6a2f5304..b1023bef 100644 --- a/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs +++ b/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs @@ -266,9 +266,14 @@ use codex_app_server_protocol::ThreadEpiphanyStateUpdatedSource; use codex_app_server_protocol::ThreadEpiphanyUpdateParams; use codex_app_server_protocol::ThreadEpiphanyUpdatePatch; use codex_app_server_protocol::ThreadEpiphanyUpdateResponse; +use codex_app_server_protocol::ThreadEpiphanyViewCoordinator; +use codex_app_server_protocol::ThreadEpiphanyViewCrrc; use codex_app_server_protocol::ThreadEpiphanyViewLens; use codex_app_server_protocol::ThreadEpiphanyViewParams; +use codex_app_server_protocol::ThreadEpiphanyViewPlanning; +use codex_app_server_protocol::ThreadEpiphanyViewReorient; use codex_app_server_protocol::ThreadEpiphanyViewResponse; +use codex_app_server_protocol::ThreadEpiphanyViewRoles; use codex_app_server_protocol::ThreadForkParams; use codex_app_server_protocol::ThreadForkResponse; use codex_app_server_protocol::ThreadIncrementElicitationParams; @@ -4307,7 +4312,12 @@ impl CodexMessageProcessor { vec![ ThreadEpiphanyViewLens::Scene, ThreadEpiphanyViewLens::Jobs, + ThreadEpiphanyViewLens::Roles, + ThreadEpiphanyViewLens::Planning, ThreadEpiphanyViewLens::Pressure, + ThreadEpiphanyViewLens::Reorient, + ThreadEpiphanyViewLens::Crrc, + ThreadEpiphanyViewLens::Coordinator, ] } else { lenses @@ -4336,7 +4346,17 @@ impl CodexMessageProcessor { } }; - let retrieval_override = if lenses.contains(&ThreadEpiphanyViewLens::Jobs) + let needs_jobs = lenses.contains(&ThreadEpiphanyViewLens::Jobs) + || lenses.contains(&ThreadEpiphanyViewLens::Roles) + || lenses.contains(&ThreadEpiphanyViewLens::Crrc) + || lenses.contains(&ThreadEpiphanyViewLens::Coordinator); + let needs_reorientation_inputs = lenses.contains(&ThreadEpiphanyViewLens::Roles) + || lenses.contains(&ThreadEpiphanyViewLens::Reorient) + || lenses.contains(&ThreadEpiphanyViewLens::Crrc) + || lenses.contains(&ThreadEpiphanyViewLens::Coordinator); + let needs_pressure = + lenses.contains(&ThreadEpiphanyViewLens::Pressure) || needs_reorientation_inputs; + let retrieval_override = if (needs_jobs || needs_reorientation_inputs) && thread .epiphany_state .as_ref() @@ -4351,9 +4371,288 @@ impl CodexMessageProcessor { } else { None }; - let token_usage_info = if lenses.contains(&ThreadEpiphanyViewLens::Pressure) { + let watcher_snapshot = if needs_reorientation_inputs { + if let Some(loaded_thread) = loaded_thread.as_ref() { + let config_snapshot = loaded_thread.config_snapshot().await; + self.epiphany_invalidation_manager + .ensure_thread_watch(&thread_id, &config_snapshot.cwd) + .await; + Some( + self.epiphany_invalidation_manager + .snapshot(&thread_id) + .await, + ) + } else { + None + } + } else { + None + }; + let token_usage_info = if needs_pressure { if let Some(loaded_thread) = loaded_thread.as_ref() { loaded_thread.token_usage_info().await + } else { + match thread.path.as_deref() { + Some(path) => latest_token_usage_info_from_rollout_path(path).await, + None => None, + } + } + } else { + None + }; + let pressure = needs_pressure.then(|| map_epiphany_pressure(token_usage_info.as_ref())); + let freshness = needs_reorientation_inputs.then(|| { + map_epiphany_freshness( + thread.epiphany_state.as_ref(), + retrieval_override.as_ref(), + watcher_snapshot.as_ref(), + ) + }); + let (state_revision, reorient_state_status, reorient_decision) = + if let (Some((state_revision, retrieval, graph, watcher)), Some(pressure)) = + (freshness.as_ref(), pressure.as_ref()) + { + let (state_status, decision) = map_epiphany_reorient( + thread.epiphany_state.as_ref(), + pressure, + retrieval, + graph, + watcher, + ); + (*state_revision, state_status, Some(decision)) + } else { + (None, ThreadEpiphanyReorientStateStatus::Missing, None) + }; + let jobs = if needs_jobs { + map_epiphany_jobs(thread.epiphany_state.as_ref(), retrieval_override.as_ref()) + } else { + Vec::new() + }; + let runtime_store_path = if lenses.contains(&ThreadEpiphanyViewLens::Roles) + || lenses.contains(&ThreadEpiphanyViewLens::Crrc) + || lenses.contains(&ThreadEpiphanyViewLens::Coordinator) + { + if let Some(loaded_thread) = loaded_thread.as_ref() { + Some(loaded_thread.epiphany_runtime_spine_store_path().await) + } else { + None + } + } else { + None + }; + let reorient_job = jobs + .iter() + .find(|job| job.id == EPIPHANY_REORIENT_LAUNCH_BINDING_ID) + .cloned(); + let (reorient_result_status, reorient_finding, reorient_result_note) = if runtime_store_path + .is_some() + || lenses.contains(&ThreadEpiphanyViewLens::Crrc) + || lenses.contains(&ThreadEpiphanyViewLens::Coordinator) + { + load_epiphany_reorient_result_snapshot( + thread.epiphany_state.as_ref(), + runtime_store_path.as_deref(), + EPIPHANY_REORIENT_LAUNCH_BINDING_ID, + ) + .await + } else { + ( + ThreadEpiphanyReorientResultStatus::MissingState, + None, + "Reorient result was not requested.".to_string(), + ) + }; + let checkpoint_present = thread + .epiphany_state + .as_ref() + .and_then(|state| state.investigation_checkpoint.as_ref()) + .is_some(); + let reorient_finding_accepted = reorient_finding.as_ref().is_some_and(|finding| { + thread + .epiphany_state + .as_ref() + .is_some_and(|state| epiphany_reorient_finding_already_accepted(state, finding)) + }); + let recommendation = if let (Some(pressure), Some(decision)) = + (pressure.as_ref(), reorient_decision.as_ref()) + { + Some(map_epiphany_crrc_recommendation( + loaded, + reorient_state_status, + pressure, + decision, + reorient_result_status, + checkpoint_present, + reorient_finding.is_some(), + reorient_finding_accepted, + )) + } else { + None + }; + let roles = if let (Some(pressure), Some(decision), Some(recommendation)) = ( + pressure.as_ref(), + reorient_decision.as_ref(), + recommendation.as_ref(), + ) { + Some(map_epiphany_roles( + thread.epiphany_state.as_ref(), + &jobs, + decision, + pressure, + recommendation, + reorient_result_status, + reorient_job.as_ref(), + )) + } else { + None + }; + let coordinator_response = if lenses.contains(&ThreadEpiphanyViewLens::Coordinator) { + if let (Some(pressure), Some(recommendation), Some(roles)) = + (pressure.as_ref(), recommendation.as_ref(), roles.clone()) + { + let (modeling_result_status, modeling_finding, _) = + if let Some(state) = thread.epiphany_state.as_ref() { + load_epiphany_role_result_snapshot( + state, + runtime_store_path.as_deref(), + ThreadEpiphanyRoleId::Modeling, + EPIPHANY_MODELING_ROLE_BINDING_ID, + ) + .await + } else { + ( + ThreadEpiphanyRoleResultStatus::MissingState, + None, + "No authoritative Epiphany state exists for this thread.".to_string(), + ) + }; + let modeling_result_accepted = modeling_finding.as_ref().is_some_and(|finding| { + thread + .epiphany_state + .as_ref() + .is_some_and(|state| epiphany_role_finding_already_accepted(state, finding)) + }); + let modeling_result_reviewable = modeling_finding + .as_ref() + .is_some_and(epiphany_modeling_finding_has_reviewable_state_patch); + let (verification_result_status, verification_finding, _) = + if let Some(state) = thread.epiphany_state.as_ref() { + load_epiphany_role_result_snapshot( + state, + runtime_store_path.as_deref(), + ThreadEpiphanyRoleId::Verification, + EPIPHANY_VERIFICATION_ROLE_BINDING_ID, + ) + .await + } else { + ( + ThreadEpiphanyRoleResultStatus::MissingState, + None, + "No authoritative Epiphany state exists for this thread.".to_string(), + ) + }; + let verification_result_accepted = + verification_finding.as_ref().is_some_and(|finding| { + thread.epiphany_state.as_ref().is_some_and(|state| { + epiphany_role_finding_already_accepted(state, finding) + }) + }); + let verification_result_covers_current_modeling = + thread.epiphany_state.as_ref().is_none_or(|state| { + epiphany_verification_finding_covers_current_modeling( + state, + modeling_result_accepted, + modeling_finding.as_ref(), + verification_finding.as_ref(), + ) + }); + let modeling_result_accepted_after_verification = + thread.epiphany_state.as_ref().is_some_and(|state| { + role_finding_accepted_after( + state, + modeling_finding.as_ref(), + verification_finding.as_ref(), + ) + }); + let implementation_evidence_after_verification = + thread.epiphany_state.as_ref().is_some_and(|state| { + implementation_evidence_after_role_finding( + state, + verification_finding.as_ref(), + ) + }); + let verification_result_cites_implementation_evidence = + thread.epiphany_state.as_ref().is_some_and(|state| { + epiphany_role_finding_cites_implementation_evidence( + state, + verification_finding.as_ref(), + ) + }); + let verification_result_allows_implementation = verification_result_accepted + && verification_finding + .as_ref() + .is_some_and(epiphany_verification_finding_allows_implementation); + let verification_result_needs_evidence = verification_result_accepted + && verification_finding + .as_ref() + .is_some_and(epiphany_verification_finding_needs_evidence); + let source_signals = ThreadEpiphanyCoordinatorSignals { + pressure_level: pressure.level, + should_prepare_compaction: pressure.should_prepare_compaction, + reorient_action: reorient_decision + .as_ref() + .map(|decision| decision.action) + .unwrap_or(ThreadEpiphanyReorientAction::Resume), + crrc_action: recommendation.action, + modeling_result_status, + verification_result_status, + reorient_result_status, + }; + let coordinator = map_epiphany_coordinator( + reorient_state_status, + checkpoint_present, + pressure, + recommendation, + &roles, + &source_signals, + modeling_result_accepted, + modeling_result_reviewable, + modeling_result_accepted_after_verification, + implementation_evidence_after_verification, + verification_result_cites_implementation_evidence, + verification_result_covers_current_modeling, + verification_result_accepted, + verification_result_allows_implementation, + verification_result_needs_evidence, + reorient_finding_accepted, + ); + let note = render_epiphany_coordinator_note( + recommendation.action, + pressure.level, + modeling_result_status, + verification_result_status, + reorient_result_status, + coordinator.action, + ); + Some(ThreadEpiphanyViewCoordinator { + thread_id: thread_id.clone(), + source: if loaded { + ThreadEpiphanyRolesSource::Live + } else { + ThreadEpiphanyRolesSource::Stored + }, + state_status: reorient_state_status, + state_revision, + action: coordinator.action, + target_role: coordinator.target_role, + recommended_scene_action: coordinator.recommended_scene_action, + requires_review: coordinator.requires_review, + can_auto_run: coordinator.can_auto_run, + reason: coordinator.reason, + source_signals, + roles, + note, + }) } else { None } @@ -4362,18 +4661,113 @@ impl CodexMessageProcessor { }; let response = ThreadEpiphanyViewResponse { - thread_id, + thread_id: thread_id.clone(), scene: lenses .contains(&ThreadEpiphanyViewLens::Scene) .then(|| map_epiphany_scene(thread.epiphany_state.as_ref(), loaded)), jobs: if lenses.contains(&ThreadEpiphanyViewLens::Jobs) { - map_epiphany_jobs(thread.epiphany_state.as_ref(), retrieval_override.as_ref()) + jobs.clone() } else { Vec::new() }, + roles: lenses.contains(&ThreadEpiphanyViewLens::Roles).then(|| { + let roles = roles.clone().unwrap_or_default(); + ThreadEpiphanyViewRoles { + thread_id: thread_id.clone(), + source: if loaded { + ThreadEpiphanyRolesSource::Live + } else { + ThreadEpiphanyRolesSource::Stored + }, + state_status: reorient_state_status, + state_revision, + note: render_epiphany_roles_note( + &roles, + reorient_state_status, + recommendation + .as_ref() + .map(|recommendation| recommendation.action) + .unwrap_or(ThreadEpiphanyCrrcAction::Continue), + ), + roles, + } + }), + planning: lenses.contains(&ThreadEpiphanyViewLens::Planning).then(|| { + let (state_status, state_revision, planning, summary) = + map_epiphany_planning(thread.epiphany_state.as_ref()); + ThreadEpiphanyViewPlanning { + thread_id: thread_id.clone(), + source: if loaded { + ThreadEpiphanyContextSource::Live + } else { + ThreadEpiphanyContextSource::Stored + }, + state_status, + state_revision, + planning, + summary, + } + }), pressure: lenses .contains(&ThreadEpiphanyViewLens::Pressure) - .then(|| map_epiphany_pressure(token_usage_info.as_ref())), + .then(|| pressure.clone()) + .flatten(), + reorient: lenses + .contains(&ThreadEpiphanyViewLens::Reorient) + .then(|| { + reorient_decision + .clone() + .map(|decision| ThreadEpiphanyViewReorient { + thread_id: thread_id.clone(), + source: if loaded { + ThreadEpiphanyReorientSource::Live + } else { + ThreadEpiphanyReorientSource::Stored + }, + state_status: reorient_state_status, + state_revision, + decision, + }) + }) + .flatten(), + crrc: lenses + .contains(&ThreadEpiphanyViewLens::Crrc) + .then(|| { + let pressure = pressure.clone()?; + let decision = reorient_decision.clone()?; + let recommendation = recommendation.clone()?; + let available_actions = epiphany_scene_available_actions( + loaded, + thread.epiphany_state.is_some(), + checkpoint_present, + reorient_job.is_some(), + ); + let note = format!( + "{} Result status: {:?}. {}", + recommendation.reason, reorient_result_status, reorient_result_note + ); + Some(ThreadEpiphanyViewCrrc { + thread_id: thread_id.clone(), + source: if loaded { + ThreadEpiphanyReorientSource::Live + } else { + ThreadEpiphanyReorientSource::Stored + }, + state_status: reorient_state_status, + state_revision, + pressure, + decision, + recommendation, + reorient_binding_id: EPIPHANY_REORIENT_LAUNCH_BINDING_ID.to_string(), + reorient_result_status, + reorient_job: reorient_job.clone(), + reorient_finding: reorient_finding.clone(), + available_actions, + note, + }) + }) + .flatten(), + coordinator: coordinator_response, lenses, }; self.outgoing.send_response(request_id, response).await;