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

311 lines
12 KiB
TypeScript

import {
pendingSubmitRecordListsEqual,
selectEngineActiveTurn,
selectEngineCancelState,
selectEngineHasPendingInteractions,
selectEngineInteractionResponseError,
selectEngineLatestTurn,
selectEnginePendingInteractions,
selectEnginePromptQueue,
selectEnginePromptQueueError,
selectEngineSession,
selectEngineSessionDeleted,
selectEngineSessionDetailHydrated,
selectEngineSessionDetailLoading,
selectEngineSessionOperationError,
selectEngineSessionRuntimeAvailability,
selectEngineSessionRuntimeActivity,
selectEngineSessionIsRespondingToInteraction,
selectEngineSessionReconcile,
selectEngineSessionSettingsUpdate,
selectEngineSubmitAvailability,
selectLatestActivationForSession,
selectLatestPendingSubmitForSession,
selectPendingSubmitsForSession,
selectSessionHasUnconfirmedSubmit,
selectSessionHasPendingSubmitStopTarget,
selectSessionGoalControlPresentation,
selectSessionIsSubmitting,
sessionGoalControlPresentationsEqual,
type AgentSessionEngine,
type EngineQueuedPrompt,
type SessionSettingsUpdateStatus
} from "@tutti-os/agent-activity-core";
import { useMemo } from "react";
import type {
AgentSessionComposerSettings,
AgentSessionReasoningEffort,
AgentSessionSpeed,
AgentSessionState
} from "../../../shared/agentSessionTypes";
import { useEngineSelector } from "../../../shared/engine/useEngineSelector";
import { EMPTY_QUEUED_PROMPTS } from "./agentGuiController.draftMessageHelpers";
import { agentActivityInteractionListsEqual } from "./agentGuiController.providerHelpers";
import { agentGUIQueueStatusFromPromptQueue } from "./agentGuiQueueStatus";
import { isPendingNewConversationActivation } from "./useAgentGUIActivation";
export function useAgentGUISessionEngineState(input: {
activeConversationId: string | null;
sessionEngine: AgentSessionEngine;
}) {
const { activeConversationId, sessionEngine } = input;
const activeQueuedPromptSnapshot = useEngineSelector(sessionEngine, (state) =>
selectEnginePromptQueue(state, activeConversationId)
);
const activeQueuedPrompts = useMemo<readonly EngineQueuedPrompt[]>(
() =>
activeQueuedPromptSnapshot?.prompts.filter(
(prompt) =>
prompt.visibleInQueue !== false &&
prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId &&
prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
) ?? EMPTY_QUEUED_PROMPTS,
[activeQueuedPromptSnapshot]
);
const activePendingSubmits = useEngineSelector(
sessionEngine,
(state) => selectPendingSubmitsForSession(state, activeConversationId),
pendingSubmitRecordListsEqual
);
const activeLatestPendingSubmit = useEngineSelector(sessionEngine, (state) =>
selectLatestPendingSubmitForSession(state, activeConversationId)
);
const activePendingActivation = useEngineSelector(sessionEngine, (state) =>
selectLatestActivationForSession(state, activeConversationId)
);
const isCreatingConversation = isPendingNewConversationActivation(
activePendingActivation
);
const isSubmitting = useEngineSelector(sessionEngine, (state) =>
selectSessionIsSubmitting(state, activeConversationId)
);
const hasUnconfirmedSubmit = useEngineSelector(sessionEngine, (state) =>
selectSessionHasUnconfirmedSubmit(state, activeConversationId)
);
const activeHasPendingSubmitStopTarget = useEngineSelector(
sessionEngine,
(state) =>
selectSessionHasPendingSubmitStopTarget(state, activeConversationId)
);
const activeCancelState = useEngineSelector(sessionEngine, (state) =>
selectEngineCancelState(state, activeConversationId)
);
const activeEngineSession = useEngineSelector(sessionEngine, (state) =>
selectEngineSession(state, activeConversationId)
);
const activeGoalControlPresentation = useEngineSelector(
sessionEngine,
(state) =>
selectSessionGoalControlPresentation(state, activeConversationId),
sessionGoalControlPresentationsEqual
);
const activeSessionReconcile = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionReconcile(state, activeConversationId)
);
const activeSessionDetailLoading = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionDetailLoading(state, activeConversationId)
);
const activeSessionDetailHydrated = useEngineSelector(
sessionEngine,
(state) => selectEngineSessionDetailHydrated(state, activeConversationId)
);
const activeEngineSessionDeleted = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionDeleted(state, activeConversationId)
);
const activeEngineActiveTurn = useEngineSelector(sessionEngine, (state) =>
selectEngineActiveTurn(state, activeConversationId)
);
const activeEngineLatestTurn = useEngineSelector(sessionEngine, (state) =>
selectEngineLatestTurn(state, activeConversationId)
);
const activeEngineSettingsUpdate = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionSettingsUpdate(state, activeConversationId)
);
const activeCanonicalComposerSettings = useMemo<AgentSessionComposerSettings>(
() =>
mergeOptimisticSessionSettings(
{
model: activeEngineSession?.settings?.model ?? undefined,
permissionModeId:
activeEngineSession?.settings?.permissionModeId ?? undefined,
planMode: activeEngineSession?.settings?.planMode ?? undefined,
browserUse: activeEngineSession?.settings?.browserUse ?? undefined,
computerUse: activeEngineSession?.settings?.computerUse ?? undefined,
reasoningEffort:
(activeEngineSession?.settings?.reasoningEffort as
| AgentSessionReasoningEffort
| null
| undefined) ?? undefined,
speed:
(activeEngineSession?.settings?.speed as
| AgentSessionSpeed
| null
| undefined) ?? undefined
},
activeEngineSettingsUpdate
),
[activeEngineSession?.settings, activeEngineSettingsUpdate]
);
const activeSessionState = useMemo<AgentSessionState | null>(() => {
if (!activeEngineSession) return null;
return {
workspaceId: activeEngineSession.workspaceId,
agentSessionId: activeEngineSession.agentSessionId,
agentTargetId: activeEngineSession.agentTargetId,
provider: activeEngineSession.provider as AgentSessionState["provider"],
providerSessionId: activeEngineSession.providerSessionId ?? undefined,
resumable: activeEngineSession.resumable,
status:
activeEngineActiveTurn && activeEngineActiveTurn.phase !== "settled"
? "working"
: "ready",
permissionModeId:
activeEngineSession.settings?.permissionModeId ?? undefined,
permissionConfig: activeEngineSession.permissionConfig,
settings: activeCanonicalComposerSettings,
pinnedAtUnixMs: activeEngineSession.pinnedAtUnixMs,
updatedAtUnixMs:
activeEngineSession.updatedAtUnixMs ??
activeEngineSession.lastEventUnixMs ??
activeEngineSession.createdAtUnixMs ??
0
};
}, [
activeCanonicalComposerSettings,
activeEngineActiveTurn,
activeEngineSession
]);
const activeEngineOperationError = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionOperationError(state, activeConversationId)
);
const activeEngineQueueError = useEngineSelector(sessionEngine, (state) =>
selectEnginePromptQueueError(state, activeConversationId)
);
const activeEngineInteractionError = useEngineSelector(
sessionEngine,
(state) => selectEngineInteractionResponseError(state, activeConversationId)
);
const activeEngineError =
activeEngineOperationError ??
activeEngineInteractionError ??
activeEngineQueueError;
const isRespondingToInteraction = useEngineSelector(sessionEngine, (state) =>
selectEngineSessionIsRespondingToInteraction(state, activeConversationId)
);
const activeEngineAvailability: "available" | "blocked" | "missing" =
useEngineSelector(
sessionEngine,
(state) =>
selectEngineSubmitAvailability(state, activeConversationId)?.state ??
"missing"
);
const activeEngineRuntimeAvailability = useEngineSelector(
sessionEngine,
(state) =>
selectEngineSessionRuntimeAvailability(state, activeConversationId)
);
const activeEngineRuntimeActivity = useEngineSelector(
sessionEngine,
(state) => selectEngineSessionRuntimeActivity(state, activeConversationId)
);
const activeEngineHasPendingInteractions = useEngineSelector(
sessionEngine,
(state) => selectEngineHasPendingInteractions(state, activeConversationId)
);
const activeEnginePendingInteractions = useEngineSelector(
sessionEngine,
(state) => selectEnginePendingInteractions(state, activeConversationId),
agentActivityInteractionListsEqual
);
return {
activeCancelState,
activeCanonicalComposerSettings,
activeEngineActiveTurn,
activeEngineAvailability,
activeEngineError,
activeEngineHasPendingInteractions,
activeEngineLatestTurn,
activeEnginePendingInteractions,
activeEngineRuntimeAvailability,
activeEngineRuntimeActivity,
activeEngineSession,
activeEngineSessionDeleted,
activeEngineSettingsUpdate,
activeGoalControlPresentation,
activeHasPendingSubmitStopTarget,
activeLatestPendingSubmit,
activePendingActivation,
activePendingSubmits,
activeQueuedPromptInFlight: activeQueuedPromptSnapshot?.inFlight ?? null,
activeQueuedPrompts,
activeQueueStatus: agentGUIQueueStatusFromPromptQueue(
activeQueuedPromptSnapshot
),
activeSessionState,
activeSessionDetailLoading,
activeSessionReconcileErrorCode: activeSessionReconcile?.errorCode ?? null,
activeSessionReconcileError: activeSessionDetailHydrated
? null
: (activeSessionReconcile?.errorMessage ?? null),
isCreatingConversation,
hasUnconfirmedSubmit,
isRespondingToInteraction,
isSubmitting
};
}
function mergeOptimisticSessionSettings(
canonical: AgentSessionComposerSettings,
update: ReturnType<typeof selectEngineSessionSettingsUpdate>
): AgentSessionComposerSettings {
if (
!update ||
!SESSION_SETTINGS_STATUS_SHOWS_OPTIMISTIC_VALUE[update.status]
) {
return canonical;
}
const optimistic = {
...(update.settings ?? {}),
...(update.queuedSettings ?? {})
};
return {
...canonical,
...(typeof optimistic.model === "string"
? { model: optimistic.model }
: {}),
...(typeof optimistic.permissionModeId === "string"
? { permissionModeId: optimistic.permissionModeId }
: {}),
...(typeof optimistic.planMode === "boolean"
? { planMode: optimistic.planMode }
: {}),
...(typeof optimistic.browserUse === "boolean"
? { browserUse: optimistic.browserUse }
: {}),
...(typeof optimistic.computerUse === "boolean"
? { computerUse: optimistic.computerUse }
: {}),
...(typeof optimistic.reasoningEffort === "string"
? {
reasoningEffort:
optimistic.reasoningEffort as AgentSessionReasoningEffort
}
: {}),
...(typeof optimistic.speed === "string"
? { speed: optimistic.speed as AgentSessionSpeed }
: {})
};
}
const SESSION_SETTINGS_STATUS_SHOWS_OPTIMISTIC_VALUE = {
failed: false,
idle: false,
inFlight: true,
// Timed-out updates must not keep showing the optimistic value (e.g. High)
// or the composer looks settled while the durable session is still medium.
unknown: false,
waitingForPromptSend: true,
waitingForRuntime: true
} satisfies Record<SessionSettingsUpdateStatus, boolean>;