Files
pikasTech-HWLAB/web/hwlab-cloud-web/composer-policy.ts
T
2026-06-02 12:25:16 +08:00

92 lines
3.4 KiB
TypeScript

const ACTIVE_STATUSES = Object.freeze(["running", "pending", "accepted", "processing"]);
const TERMINAL_STATUSES = Object.freeze(["completed", "source", "failed", "timeout", "canceled", "cancelled", "error", "blocked"]);
export function computeCodeAgentComposerState(input = {}) {
const latest = latestAgentMessage(input.messages ?? input.chatMessages);
const current = input.currentRequest && typeof input.currentRequest === "object" ? input.currentRequest : null;
const workspace = input.workspace && typeof input.workspace === "object" ? input.workspace : null;
const explicitStatus = normalizedStatus(input.status ?? input.sessionStatus ?? workspace?.sessionStatus);
const traceId = firstNonEmptyString(
input.targetTraceId,
current?.traceId,
runningTraceId(input.messages ?? input.chatMessages),
workspace?.activeTraceId,
latest?.status === "running" ? latest?.traceId : null
);
const active = Boolean(traceId) && (
activeStatus(current?.status) ||
activeStatus(latest?.status) ||
activeStatus(explicitStatus) ||
(firstNonEmptyString(input.activeTraceId, workspace?.activeTraceId) === traceId && !terminalStatus(explicitStatus)) ||
input.chatPending === true
);
const mode = active ? "steer" : "turn";
return pruneUndefined({
contract: "hwlab-code-agent-composer-policy-v1",
webEquivalent: true,
locked: false,
disabled: false,
submitMode: mode,
mode,
route: mode === "steer" ? "/v1/agent/chat/steer" : "/v1/agent/chat",
method: "POST",
targetTraceId: active ? traceId : null,
conversationId: firstNonEmptyString(input.conversationId, current?.conversationId, latest?.conversationId, workspace?.selectedConversationId),
sessionId: firstNonEmptyString(input.sessionId, current?.sessionId, latest?.sessionId, workspace?.selectedAgentSessionId),
threadId: firstNonEmptyString(input.threadId, current?.threadId, latest?.threadId, workspace?.threadId),
workspaceId: firstNonEmptyString(input.workspaceId, workspace?.workspaceId),
workspaceRevision: integerOrNull(input.workspaceRevision ?? workspace?.revision),
reason: active ? "active-turn-steer" : terminalStatus(explicitStatus) ? "terminal-turn" : "idle-turn"
});
}
export function latestAgentMessage(messages = []) {
if (!Array.isArray(messages)) return null;
for (const message of [...messages].reverse()) {
if (message?.role === "agent") return message;
}
return null;
}
function runningTraceId(messages = []) {
if (!Array.isArray(messages)) return null;
for (const message of [...messages].reverse()) {
if (message?.status !== "running") continue;
const traceId = firstNonEmptyString(message?.traceId, message?.runnerTrace?.traceId);
if (traceId) return traceId;
}
return null;
}
function activeStatus(value) {
return ACTIVE_STATUSES.includes(normalizedStatus(value));
}
function terminalStatus(value) {
return TERMINAL_STATUSES.includes(normalizedStatus(value));
}
function normalizedStatus(value) {
return String(value ?? "").trim().toLowerCase();
}
function firstNonEmptyString(...values) {
for (const value of values) {
const text = String(value ?? "").trim();
if (text) return text;
}
return null;
}
function integerOrNull(value) {
return Number.isInteger(value) ? value : null;
}
function pruneUndefined(value) {
const out = {};
for (const [key, item] of Object.entries(value)) {
if (item !== undefined) out[key] = item;
}
return out;
}