Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

768 lines
28 KiB
TypeScript

import {
isPendingActivationViable,
selectPlanDecisionForTurn,
selectPlanTurnDismissed,
type AgentActivityDisplayStatus,
type AgentActivityMessage,
type AgentActivitySessionGoalSyncState,
type AgentActivityTurn,
type CanonicalAgentSession,
type PendingActivationIntentRecord,
type SessionGoalControlPresentation,
type SessionRuntimeAvailability,
type AgentSessionEngine
} from "@tutti-os/agent-activity-core";
import { useEffect, useMemo } from "react";
import type { AgentGUIRuntime } from "../../../agentActivityRuntime";
import { translate } from "../../../i18n/index";
import type { AgentConversationVM } from "../../../shared/agentConversation/contracts/agentConversationVM";
import type { AgentApprovalItemVM } from "../../../shared/agentConversation/contracts/agentApprovalItemVM";
import {
latestPlanTurnId,
planImplementationPromptFromPlanTurn
} from "../../../shared/agentConversation/planImplementationPresentation";
import type { AgentSessionState } from "../../../shared/agentSessionTypes";
import type { AppErrorCode } from "../../../shared/contracts/dto";
import type {
AgentGUIObservationGapSource,
AgentGUIInteractionReadinessReason,
AgentGUIInteractionReadinessSource,
AgentGUITargetConnectionSource
} from "../../../types";
import { useEngineSelector } from "../../../shared/engine/useEngineSelector";
import type {
AgentGUIConversationSummary,
AgentGUIInteractivePrompt
} from "../model/agentGuiConversationModel";
import {
isDifferentKnownConversationOwner,
resolveAgentGUIComposerGate
} from "../model/agentGuiComposerGate";
import type { AgentGUISessionChrome } from "../model/agentGuiNodeTypes";
import { composerSettingsSupportFromOptions } from "../model/composerSettingsSupport";
import {
agentActivityDisplayStatusBusy,
conversationBusyStatus
} from "./agentGuiController.draftMessageHelpers";
import { isNonRetryableResumeErrorCode } from "./agentGuiController.errors";
import { projectAgentGUIMessagesToTimelineItems } from "./agentGuiController.promptHelpers";
import { promptRequestId } from "./agentGuiController.diagnostics";
import { reportAgentGUIRenderStateDiagnostic } from "./agentGuiController.reporting";
import { useAgentGUITargetConnectionState } from "./useAgentGUITargetConnectionState";
import { useAgentObservationGap } from "../../../shared/agentConversation/AgentObservationGapContext";
import { resolveAgentGUIInteractionReadinessIdentity } from "./agentGuiController.interactionHelpers";
import { useAgentGUIInteractionReadiness } from "./useAgentGUIInteractionReadiness";
interface CurrentValue<T> {
current: T;
}
interface ExactInteractionPromptIdentity {
agentSessionId?: string | null;
requestId?: string | null;
turnId?: string | null;
}
function useExactInteractionReadiness(input: {
prompt: ExactInteractionPromptIdentity | null;
source?: AgentGUIInteractionReadinessSource | null;
workspaceId: string;
}) {
const identity = useMemo(
() =>
resolveAgentGUIInteractionReadinessIdentity({
agentSessionId: input.prompt?.agentSessionId,
requestId: input.prompt?.requestId,
turnId: input.prompt?.turnId,
workspaceId: input.workspaceId
}),
[
input.prompt?.agentSessionId,
input.prompt?.requestId,
input.prompt?.turnId,
input.workspaceId
]
);
const readiness = useAgentGUIInteractionReadiness({
identity,
required: input.prompt !== null,
source: input.source
});
return {
block: readiness?.status === "blocked" ? readiness : null,
ownsInteraction: input.source != null && input.prompt !== null
};
}
export function resolveAgentGUISharingRevokedRecovery(input: {
activeConversationId: string | null;
selectedAgentTargetOwnerLabel: string | null;
selectedAgentTargetUnavailable: boolean;
selectedAgentTargetUnavailableReason: string | null;
sessionRuntimeBlock: Extract<
SessionRuntimeAvailability,
{ state: "blocked" }
> | null;
}): AgentGUISessionChrome["recovery"] {
const selectedTargetSharingRevoked =
input.activeConversationId === null &&
input.selectedAgentTargetUnavailable &&
input.selectedAgentTargetUnavailableReason === "agent_sharing_revoked";
if (
input.sessionRuntimeBlock?.reason !== "agent_sharing_revoked" &&
!selectedTargetSharingRevoked
) {
return null;
}
return {
kind: "agent-sharing-revoked",
message: translate("agentHost.agentGui.agentSharingRevoked", {
owner:
(input.sessionRuntimeBlock?.reason === "agent_sharing_revoked"
? input.sessionRuntimeBlock.ownerLabel
: null) ??
input.selectedAgentTargetOwnerLabel ??
translate("agentHost.agentGui.sharedDeviceLabel")
}),
canRetry: false
};
}
interface UseAgentGUISessionPresentationInput {
activeConversation: AgentGUIConversationSummary | null;
activeConversationId: string | null;
activeEngineActiveTurn: AgentActivityTurn | null;
activeEngineAvailability: "available" | "blocked" | "missing";
activeEngineHasPendingInteractions: boolean;
activeHasPendingSubmitStopTarget: boolean;
activeEngineLatestTurn: AgentActivityTurn | null;
activeEngineRuntimeAvailability: SessionRuntimeAvailability | null;
activeEngineRuntimeActivity: "idle" | "running";
activeEngineSession: CanonicalAgentSession | null;
/** In-flight / waiting session settings update; blocks submit until settled. */
activeEngineSettingsUpdate: {
status: string;
} | null;
activeGoalControlPresentation: SessionGoalControlPresentation;
activeLatestPendingSubmitTurnId: string | null;
activeLiveState: "inactive" | "activating" | "active" | "failed";
activeMessages: readonly AgentActivityMessage[];
activePendingActivation: PendingActivationIntentRecord | null;
activeSessionState: AgentSessionState | null;
activeTimelineItems: ReturnType<
typeof projectAgentGUIMessagesToTimelineItems
>;
activationError: string | null;
activationErrorCode: AppErrorCode | null;
activationState: "inactive" | "activating" | "active" | "failed" | null;
activityDisplayStatus: AgentActivityDisplayStatus | null;
agentActivityRuntime: AgentGUIRuntime;
composerSupport: ReturnType<typeof composerSettingsSupportFromOptions>;
conversation: AgentConversationVM | null;
currentUserId?: string | null;
hasUnconfirmedSubmit: boolean;
isCreatingConversation: boolean;
isInterrupting: boolean;
isLoadingMessages: boolean;
isRespondingToInteraction: boolean;
isSubmitting: boolean;
lastRenderStateDiagnosticKeyRef: CurrentValue<string | null>;
pendingApproval: AgentApprovalItemVM | null;
planImplementationTurnIdRef: CurrentValue<string | null>;
providerReadinessGate:
| import("../../../types").AgentGUIProviderReadinessGate
| null;
selectedAgentTargetUnavailable: boolean;
selectedAgentTargetUnavailableReason: string | null;
selectedAgentTargetOwnerLabel: string | null;
agentTargetsLoading: boolean;
ownerDeviceLabel?: string | null;
serverInteractivePrompt: AgentGUIInteractivePrompt | null;
sessionEngine: AgentSessionEngine;
targetConnectionAgentTargetId?: string | null;
targetConnectionSource?: AgentGUITargetConnectionSource | null;
interactionReadinessSource?: AgentGUIInteractionReadinessSource | null;
observationGapSource?: AgentGUIObservationGapSource | null;
workspaceId: string;
}
export function useAgentGUISessionPresentation(
input: UseAgentGUISessionPresentationInput
) {
const latestTimelinePlanTurnId = latestPlanTurnId(input.activeTimelineItems);
const planImplementationTurnId =
input.activeConversationId !== null &&
input.composerSupport.planImplementation &&
input.composerSupport.plan &&
input.activeEngineLatestTurn?.phase === "settled" &&
input.activeEngineLatestTurn.outcome === "completed" &&
input.activeEngineLatestTurn.turnId === latestTimelinePlanTurnId
? latestTimelinePlanTurnId
: null;
const activePlanDecision = useEngineSelector(input.sessionEngine, (state) =>
selectPlanDecisionForTurn(
state,
input.activeConversationId,
planImplementationTurnId
)
);
const activePlanTurnDismissed = useEngineSelector(
input.sessionEngine,
(state) =>
selectPlanTurnDismissed(
state,
input.activeConversationId,
planImplementationTurnId
)
);
input.planImplementationTurnIdRef.current = planImplementationTurnId;
const planImplementationPrompt =
planImplementationTurnId !== null &&
input.activeConversationId !== null &&
!activePlanTurnDismissed
? planImplementationPromptFromPlanTurn(
planImplementationTurnId,
input.activeConversation?.title ?? ""
)
: null;
const unresolvedInteractivePrompt =
input.serverInteractivePrompt ?? planImplementationPrompt;
const interactiveReadinessPrompt =
unresolvedInteractivePrompt?.kind === "plan-implementation"
? null
: unresolvedInteractivePrompt;
const interactiveReadiness = useExactInteractionReadiness({
prompt: interactiveReadinessPrompt,
source: input.interactionReadinessSource,
workspaceId: input.workspaceId
});
const approvalReadiness = useExactInteractionReadiness({
prompt: input.pendingApproval,
source: input.interactionReadinessSource,
workspaceId: input.workspaceId
});
const pendingInteractivePrompt =
interactiveReadiness.block?.reason === "binding_revoked"
? null
: unresolvedInteractivePrompt;
const pendingApproval =
approvalReadiness.block?.reason === "binding_revoked"
? null
: input.pendingApproval;
const activeInteractionReadiness =
pendingInteractivePrompt !== null
? interactiveReadiness
: pendingApproval !== null
? approvalReadiness
: unresolvedInteractivePrompt !== null
? interactiveReadiness
: approvalReadiness;
const interactionReadinessBlock = activeInteractionReadiness.block;
const interactionReadinessOwnsInteraction =
activeInteractionReadiness.ownsInteraction;
const interactivePromptResponsePending =
input.isRespondingToInteraction ||
interactiveReadiness.block !== null ||
activePlanDecision?.status === "requested" ||
activePlanDecision?.status === "unknown";
const approvalResponsePending =
input.isRespondingToInteraction || approvalReadiness.block !== null;
const activeActivationAwaitsInitialTurn = Boolean(
input.activeConversationId &&
input.activePendingActivation?.mode === "new" &&
input.activePendingActivation.agentSessionId ===
input.activeConversationId &&
input.activePendingActivation.initialTurnExpected &&
isPendingActivationViable(input.activePendingActivation) &&
!input.activeEngineLatestTurn
);
const activeInitialGoalSetHasPendingOperation = Boolean(
input.activeConversationId &&
input.activePendingActivation?.mode === "new" &&
input.activePendingActivation.agentSessionId ===
input.activeConversationId &&
input.activePendingActivation.initialGoalControl?.action === "set" &&
isPendingActivationViable(input.activePendingActivation) &&
input.activeGoalControlPresentation.goal?.status === "active" &&
initialGoalHasPendingOperationEvidence({
goalIsOptimistic: input.activeGoalControlPresentation.optimistic,
syncState: input.activeEngineSession?.goalSyncState ?? null
}) &&
!input.activeEngineLatestTurn
);
const hasPendingTurnStartEvidence = Boolean(
input.activeConversationId &&
(activeActivationAwaitsInitialTurn ||
activeInitialGoalSetHasPendingOperation ||
input.hasUnconfirmedSubmit ||
input.isSubmitting ||
(!input.activeEngineSession && input.activeLatestPendingSubmitTurnId))
);
const activeSubmitBlocked = input.activeEngineAvailability === "blocked";
const sessionRuntimeBlock =
input.activeEngineRuntimeAvailability?.state === "blocked"
? input.activeEngineRuntimeAvailability
: null;
const sessionRuntimeBlockedReason = sessionRuntimeBlock?.reason ?? null;
const targetConnection = useAgentGUITargetConnectionState({
agentTargetId: input.targetConnectionAgentTargetId,
source: input.targetConnectionSource
});
const observationGap = useAgentObservationGap(
input.activeEngineSession?.agentSessionId ?? input.activeConversationId,
input.activeEngineActiveTurn?.turnId,
input.observationGapSource
);
const hasCanonicalTerminalActivity =
input.activityDisplayStatus === "completed" ||
input.activityDisplayStatus === "failed" ||
input.activityDisplayStatus === "canceled";
const executing =
!hasCanonicalTerminalActivity &&
(agentActivityDisplayStatusBusy(input.activityDisplayStatus) ||
(input.activeEngineActiveTurn !== null &&
input.activeEngineActiveTurn.phase !== "settled") ||
(!input.activeEngineSession &&
input.activeEngineRuntimeActivity === "running"));
const isAwaitingTurnStart = hasPendingTurnStartEvidence && !executing;
const activeConversationBusy =
!hasCanonicalTerminalActivity &&
(executing ||
(!input.activeEngineSession &&
conversationBusyStatus(input.activeConversation?.status ?? null)));
const activeSessionResumable =
input.activeEngineSession?.resumable ??
input.activeConversation?.resumable ??
input.activeSessionState?.resumable;
const activeConversationRequiresResume =
input.activeConversationId !== null && input.activationState !== "active";
const activeConversationResumeUnavailable =
activeConversationRequiresResume && activeSessionResumable === false;
const sessionChromeRawState = useMemo<
AgentGUISessionChrome["rawState"]
>(() => {
const agentSessionId =
input.activeEngineSession?.agentSessionId ??
input.activeGoalControlPresentation.agentSessionId ??
input.activeConversationId;
if (!agentSessionId) {
return null;
}
return {
agentSessionId,
goal: input.activeGoalControlPresentation.goal,
goalControlStatus: input.activeGoalControlPresentation.status,
goalIsOptimistic: input.activeGoalControlPresentation.optimistic
};
}, [
input.activeConversationId,
input.activeEngineSession?.agentSessionId,
input.activeGoalControlPresentation
]);
const sessionChrome = useMemo<AgentGUISessionChrome>(() => {
if (interactionReadinessBlock?.reason === "binding_revoked") {
return {
auth: null,
approval: null,
recovery: {
kind: "agent-sharing-revoked",
message: translate("agentHost.agentGui.agentSharingRevoked", {
owner:
input.selectedAgentTargetOwnerLabel ??
translate("agentHost.agentGui.sharedDeviceLabel")
}),
canRetry: false
},
rawState: sessionChromeRawState
};
}
if (interactionReadinessBlock !== null) {
const synchronizing =
interactionReadinessBlock.reason === "synchronizing";
const device =
input.ownerDeviceLabel?.trim() ||
translate("agentHost.agentGui.sharedDeviceLabel");
return {
auth: null,
approval: pendingApproval,
recovery: {
kind: synchronizing
? "transport-connecting"
: "transport-unavailable",
message: translate(
synchronizing
? "agentHost.agentGui.runtimeSynchronizingProgress"
: input.activeEngineActiveTurn !== null
? "agentHost.agentGui.runtimeUnavailableActive"
: "agentHost.agentGui.runtimeUnavailable",
{ device }
),
canRetry: false,
interactionScoped: true
},
rawState: sessionChromeRawState
};
}
if (!interactionReadinessOwnsInteraction) {
const sharingRevokedRecovery = resolveAgentGUISharingRevokedRecovery({
activeConversationId: input.activeConversationId,
selectedAgentTargetOwnerLabel: input.selectedAgentTargetOwnerLabel,
selectedAgentTargetUnavailable: input.selectedAgentTargetUnavailable,
selectedAgentTargetUnavailableReason:
input.selectedAgentTargetUnavailableReason,
sessionRuntimeBlock
});
if (sharingRevokedRecovery) {
return {
auth: null,
approval: null,
recovery: sharingRevokedRecovery,
rawState: sessionChromeRawState
};
}
}
if (
!interactionReadinessOwnsInteraction &&
(targetConnection.visibleState?.status === "connecting" ||
targetConnection.visibleState?.status === "unavailable")
) {
const device =
input.ownerDeviceLabel?.trim() ||
translate("agentHost.agentGui.sharedDeviceLabel");
const reconnecting =
targetConnection.visibleState.status === "connecting";
const retryAttempt = targetConnection.visibleState.retryAttempt;
return {
auth: null,
approval: null,
recovery: {
kind: reconnecting ? "transport-connecting" : "transport-unavailable",
message: translate(
reconnecting
? retryAttempt > 0
? "agentHost.agentGui.runtimeReconnectingAttempt"
: "agentHost.agentGui.runtimeConnecting"
: input.activeEngineActiveTurn !== null
? "agentHost.agentGui.runtimeUnavailableActive"
: "agentHost.agentGui.runtimeUnavailable",
{ attempt: retryAttempt, device }
),
canRetry: false
},
rawState: sessionChromeRawState
};
}
if (!interactionReadinessOwnsInteraction && observationGap !== null) {
return {
auth: null,
approval: null,
recovery: {
kind: "transport-connecting",
message: translate("agentHost.agentGui.runtimeSynchronizingProgress"),
canRetry: false
},
rawState: sessionChromeRawState
};
}
const normalizedError = input.activationError?.trim() ?? "";
const authState = input.activeSessionState?.authState?.trim() ?? "";
const providerSessionMissing = isNonRetryableResumeErrorCode(
input.activationErrorCode
);
const isAuthError =
!providerSessionMissing &&
(authState !== "" ||
(normalizedError !== "" &&
/auth|sign in|log in|login|unauthorized|authenticated/i.test(
normalizedError
)));
const isResumeNotLocalRecovery =
providerSessionMissing || activeConversationResumeUnavailable;
const recoveryMessage = isResumeNotLocalRecovery
? translate(
input.activeConversation?.isImported === true
? "messages.agentImportedSessionResumeUnavailable"
: "messages.agentResumeSessionNotLocal"
)
: normalizedError;
return {
auth: providerSessionMissing
? null
: authState !== ""
? { message: authState }
: isAuthError
? { message: normalizedError }
: null,
approval: pendingApproval,
recovery:
input.activeLiveState === "activating" &&
input.activePendingActivation?.mode !== "new"
? {
kind: "activating",
message: translate("messages.agentSessionReconnecting")
}
: !isAuthError && recoveryMessage
? isResumeNotLocalRecovery
? {
kind: "resume-unavailable",
message: recoveryMessage,
followupAction: "continue-in-new-conversation" as const
}
: {
kind: "failed",
message: recoveryMessage,
canRetry: false
}
: null,
rawState: sessionChromeRawState
};
}, [
activeConversationResumeUnavailable,
input.activeConversation,
input.activationError,
input.activationErrorCode,
input.activeConversationId,
input.activeEngineActiveTurn,
input.activeLiveState,
input.activeSessionState,
input.activePendingActivation?.mode,
input.ownerDeviceLabel,
input.selectedAgentTargetOwnerLabel,
input.selectedAgentTargetUnavailable,
input.selectedAgentTargetUnavailableReason,
interactionReadinessBlock,
interactionReadinessOwnsInteraction,
pendingApproval,
sessionRuntimeBlock,
targetConnection.visibleState,
observationGap,
sessionChromeRawState
]);
const hasNonRetryableRecoveryFailure =
(sessionChrome.recovery?.kind === "failed" &&
sessionChrome.recovery.canRetry === false) ||
sessionChrome.recovery?.kind === "resume-unavailable";
const authBlocked = sessionChrome.auth !== null;
const isCollaboratorConversation = isDifferentKnownConversationOwner({
conversationUserId: input.activeConversation?.userId,
currentUserId: input.currentUserId
});
const hasPendingApproval = pendingApproval !== null;
const hasPendingInteractivePrompt = pendingInteractivePrompt !== null;
const settingsUpdateStatus = input.activeEngineSettingsUpdate?.status;
const settingsUpdatePending =
settingsUpdateStatus === "inFlight" ||
settingsUpdateStatus === "waitingForRuntime" ||
settingsUpdateStatus === "unknown" ||
settingsUpdateStatus === "failed";
const composerGate = useMemo(
() =>
resolveAgentGUIComposerGate({
activeConversationBusy,
activeConversationId: input.activeConversationId,
activeEngineHasPendingInteractions:
input.activeEngineHasPendingInteractions,
activeLiveState: input.activeLiveState,
activeConversationResumeUnavailable,
agentTargetsLoading: input.agentTargetsLoading,
authBlocked,
hasNonRetryableRecoveryFailure,
isCollaboratorConversation,
isCreatingConversation: input.isCreatingConversation,
isInterrupting: input.isInterrupting,
isAwaitingTurnStart,
isSubmitting: input.isSubmitting,
pendingApproval: hasPendingApproval,
pendingInteractivePrompt: hasPendingInteractivePrompt,
providerReadinessGate: input.providerReadinessGate,
selectedAgentTargetUnavailable: input.selectedAgentTargetUnavailable,
settingsUpdatePending,
sessionRuntimeBlockedReason,
targetConnectionBlocked:
targetConnection.blocked ||
observationGap !== null ||
interactionReadinessBlock !== null
}),
[
activeConversationBusy,
activeConversationResumeUnavailable,
authBlocked,
hasNonRetryableRecoveryFailure,
hasPendingInteractivePrompt,
input.activeConversationId,
input.activeEngineHasPendingInteractions,
input.activeLiveState,
input.agentTargetsLoading,
input.isCreatingConversation,
input.isInterrupting,
input.isSubmitting,
input.providerReadinessGate,
input.selectedAgentTargetUnavailable,
isCollaboratorConversation,
isAwaitingTurnStart,
hasPendingApproval,
sessionRuntimeBlockedReason,
settingsUpdatePending,
targetConnection.blocked,
observationGap,
interactionReadinessBlock
]
);
const isRespondingApproval =
approvalResponsePending ||
(!approvalReadiness.ownsInteraction &&
composerGate.runtime.status === "blocked");
const isRespondingInteractivePrompt =
interactivePromptResponsePending ||
(!interactiveReadiness.ownsInteraction &&
composerGate.runtime.status === "blocked");
const canSubmit = composerGate.submission.status === "ready";
const canQueueWhileBusy = composerGate.submission.status === "queue";
const hasSentUserMessage = input.activeTimelineItems.some(
(item) => item.role === "user"
);
useEffect(() => {
const diagnosticKey = [
input.activeConversationId ?? "",
input.activeConversation?.status ?? "",
input.activityDisplayStatus ?? "",
input.activeLiveState,
input.activeEngineActiveTurn?.phase ??
input.activeEngineLatestTurn?.phase ??
"",
input.activeEngineActiveTurn?.outcome ??
input.activeEngineLatestTurn?.outcome ??
"",
input.activeEngineActiveTurn?.turnId ?? "",
input.activeEngineAvailability,
input.activeEngineRuntimeActivity,
activeConversationBusy ? "busy" : "ready",
isAwaitingTurnStart ? "awaiting-turn-start" : "turn-start-observed",
activeSubmitBlocked ? "submit-blocked" : "submit-open",
pendingApproval?.requestId ?? "",
promptRequestId(pendingInteractivePrompt) ?? "",
input.conversation?.activity.status ?? "",
input.conversation?.sourceDetail.showProcessingIndicator
? "show-processing"
: "hide-processing",
input.conversation?.rows
.filter((row) => row.kind === "processing")
.map((row) => `${row.id}:${row.turnId ?? ""}`)
.join(",") ?? "",
input.isCreatingConversation ? "creating" : "",
input.isLoadingMessages ? "loading-messages" : "",
input.isSubmitting ? "submitting" : "",
canSubmit ? "can-submit" : "cannot-submit",
canQueueWhileBusy ? "can-queue" : "cannot-queue",
composerGate.editor.status,
composerGate.editor.reason ?? "",
composerGate.submission.reason ?? "",
composerGate.runtime.reason ?? ""
].join(":");
if (input.lastRenderStateDiagnosticKeyRef.current === diagnosticKey) return;
input.lastRenderStateDiagnosticKeyRef.current = diagnosticKey;
reportAgentGUIRenderStateDiagnostic({
activeActivityDisplayStatus: input.activityDisplayStatus,
activeConversation: input.activeConversation,
activeConversationBusy,
activeConversationId: input.activeConversationId,
activeEngineActiveTurn: input.activeEngineActiveTurn,
activeEngineAvailability: input.activeEngineAvailability,
activeEngineLatestTurn: input.activeEngineLatestTurn,
activeEngineRuntimeActivity: input.activeEngineRuntimeActivity,
isAwaitingTurnStart,
activeLiveState: input.activeLiveState,
activeRuntimeSession: input.activeEngineSession,
activeSessionState: input.activeSessionState,
activeSubmitBlocked,
canQueueWhileBusy,
canSubmit,
conversation: input.conversation,
isCreatingConversation: input.isCreatingConversation,
isLoadingMessages: input.isLoadingMessages,
isSubmitting: input.isSubmitting,
pendingApproval,
pendingInteractivePrompt,
runtime: input.agentActivityRuntime,
workspaceId: input.workspaceId
});
}, [
activeConversationBusy,
isAwaitingTurnStart,
activeSubmitBlocked,
canQueueWhileBusy,
canSubmit,
composerGate,
input.activeConversation,
input.activeConversationId,
input.activeEngineActiveTurn,
input.activeEngineAvailability,
input.activeEngineLatestTurn,
input.activeEngineRuntimeActivity,
input.activeEngineSession,
input.activeLiveState,
input.activeSessionState,
input.activityDisplayStatus,
input.agentActivityRuntime,
input.conversation,
input.isCreatingConversation,
input.isLoadingMessages,
input.isSubmitting,
input.lastRenderStateDiagnosticKeyRef,
input.workspaceId,
pendingApproval,
pendingInteractivePrompt
]);
return {
approvalDisabledReason: approvalReadiness.block
? interactionReadinessReasonMessage(approvalReadiness.block.reason)
: null,
activeConversationBusy,
composerGate,
hasPendingSubmitStopTarget: input.activeHasPendingSubmitStopTarget,
hasSentUserMessage,
interactivePromptDisabledReason: interactiveReadiness.block
? interactionReadinessReasonMessage(interactiveReadiness.block.reason)
: null,
isRespondingApproval,
isRespondingInteractivePrompt,
isAwaitingTurnStart,
pendingApproval,
pendingInteractivePrompt,
sessionChrome
};
}
function initialGoalHasPendingOperationEvidence(input: {
goalIsOptimistic: boolean;
syncState: AgentActivitySessionGoalSyncState | null;
}): boolean {
if (input.goalIsOptimistic) return true;
switch (input.syncState?.syncStatus) {
case "pending":
case "applying":
case "unknown":
return Boolean(input.syncState.pendingOperationId?.trim());
case "synced":
return input.syncState.executionPending === true;
default:
return false;
}
}
function interactionReadinessReasonMessage(
reason: AgentGUIInteractionReadinessReason
): string {
switch (reason) {
case "owner_offline":
return translate("agentHost.agentGui.interactionOwnerOffline");
case "binding_revoked":
return translate("agentHost.agentGui.interactionBindingRevoked");
case "synchronizing":
default:
return translate("agentHost.agentGui.interactionSynchronizing");
}
}