源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
+310
@@ -0,0 +1,310 @@
|
||||
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>;
|
||||
Reference in New Issue
Block a user