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

159 lines
5.2 KiB
TypeScript

import type { AgentActivitySessionDetailSnapshot } from "@tutti-os/agent-activity-core";
import type { WorkspaceAgentSessionDetailResponse } from "@tutti-os/client-tuttid-ts";
import {
agentActivityEditRetryAvailabilityFromTuttid,
agentActivitySessionFromTuttidSession,
agentActivityTurnFromTuttidTurn,
type AgentActivitySessionMappingOptions
} from "./mappers.ts";
/**
* Maps one authoritative tuttid detail response without performing transport
* or dispatch work. Hosts feed the returned aggregate to the engine through a
* single `session/detailSnapshotReceived` intent so root, child, and Turn
* state cannot become observably half-applied.
*/
export function agentActivitySessionDetailFromTuttid(
workspaceId: string,
expectedAgentSessionId: string,
detail: WorkspaceAgentSessionDetailResponse,
options: AgentActivitySessionMappingOptions
): AgentActivitySessionDetailSnapshot {
assertTuttidSessionDetailContract(expectedAgentSessionId, detail);
const projectionOptions = {
...options,
lifecycleCapabilitiesProjected: detail.lifecycleCapabilitiesProjected
};
return {
projection:
detail.projection === "full" ? "authoritative" : "message_hydration",
lifecycleCapabilitiesProjected: detail.lifecycleCapabilitiesProjected,
editRetry: agentActivityEditRetryAvailabilityFromTuttid(detail.editRetry),
session: agentActivitySessionFromTuttidSession(
workspaceId,
detail.session,
projectionOptions
),
childSessions: detail.childSessions.map((session) =>
agentActivitySessionFromTuttidSession(
workspaceId,
session,
projectionOptions
)
),
turns: detail.turns.map(agentActivityTurnFromTuttidTurn)
};
}
function assertTuttidSessionDetailContract(
expectedAgentSessionId: string,
detail: WorkspaceAgentSessionDetailResponse
): void {
if (
detail.projection !== "full" &&
detail.projection !== "messageHydration"
) {
throw detailContractError(
`projection ${JSON.stringify(detail.projection)} is invalid`
);
}
const capabilitiesShouldBeProjected = detail.projection === "full";
if (detail.lifecycleCapabilitiesProjected !== capabilitiesShouldBeProjected) {
throw detailContractError(
`lifecycle capability projection does not match detail projection ${JSON.stringify(detail.projection)}`
);
}
const expectedId = trimmedString(expectedAgentSessionId);
const rootId = trimmedString(detail.session?.id);
if (!expectedId || rootId !== expectedId) {
throw detailContractError(
`root Session id ${JSON.stringify(rootId)} does not match requested id ${JSON.stringify(expectedId)}`
);
}
if (!Array.isArray(detail.childSessions) || !Array.isArray(detail.turns)) {
throw detailContractError(
"childSessions and turns must be authoritative arrays"
);
}
const hierarchyRootId =
detail.session.kind === "root"
? rootId
: trimmedString(detail.session.rootAgentSessionId);
if (
(detail.session.kind !== "root" && detail.session.kind !== "child") ||
!hierarchyRootId
) {
throw detailContractError(
"requested Session hierarchy identity is invalid"
);
}
const childrenById = new Map<
string,
WorkspaceAgentSessionDetailResponse["childSessions"][number]
>();
for (const child of detail.childSessions) {
const childId = trimmedString(child.id);
if (
!childId ||
childId === rootId ||
child.kind !== "child" ||
trimmedString(child.rootAgentSessionId) !== hierarchyRootId ||
childrenById.has(childId)
) {
throw detailContractError(
`child Session identity ${JSON.stringify(childId)} is invalid`
);
}
childrenById.set(childId, child);
}
for (const child of detail.childSessions) {
assertDescendsFromRequestedSession(child, rootId, childrenById);
}
for (const turn of detail.turns) {
const turnId = trimmedString(turn.turnId);
const ownerId = trimmedString(turn.agentSessionId);
if (!turnId || ownerId !== rootId) {
throw detailContractError(
`Turn ${JSON.stringify(turnId)} must be owned by requested Session ${JSON.stringify(rootId)}`
);
}
}
}
function assertDescendsFromRequestedSession(
child: WorkspaceAgentSessionDetailResponse["childSessions"][number],
requestedSessionId: string,
childrenById: ReadonlyMap<
string,
WorkspaceAgentSessionDetailResponse["childSessions"][number]
>
): void {
const childId = trimmedString(child.id);
const visited = new Set<string>([childId]);
let parentId = trimmedString(child.parentAgentSessionId);
while (parentId && parentId !== requestedSessionId) {
if (visited.has(parentId)) {
throw detailContractError(
`child Session ${JSON.stringify(childId)} contains a parent cycle`
);
}
visited.add(parentId);
parentId = trimmedString(childrenById.get(parentId)?.parentAgentSessionId);
}
if (parentId !== requestedSessionId) {
throw detailContractError(
`child Session ${JSON.stringify(childId)} is outside the requested Session hierarchy`
);
}
}
function detailContractError(reason: string): Error {
return new Error(`Protocol v2 contract error: ${reason}`);
}
function trimmedString(value: unknown): string {
return typeof value === "string" ? value.trim() : "";
}