blob: ba57727829f4b138c5b224cf6961577528cbbb7e [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { assertSafeSessionId } from './session-store-contract.js';
import {
AGENT_GRAPH_SUPERVISOR_WAKE_SCHEMA_VERSION,
type ClaimAgentGraphSupervisorWakeRequest,
type BeginAgentGraphSupervisorWakeAttemptRequest,
type CompleteAgentGraphSupervisorWakeAttemptRequest,
} from '@maka/core/agent-graph-supervisor-wake';
import {
AGENT_GRAPH_CLIENT_PROJECTION_SCHEMA_VERSION,
type CommitAgentGraphClientProjectionRequest,
} from '@maka/core/agent-graph-client-projection';
export function assertGraphLookupIdentity(value: string, name: string): void {
if (
typeof value !== 'string' ||
value.length === 0 ||
value.length > 256 ||
value.trim() !== value ||
/[\u0000-\u001f\u007f]/.test(value)
) {
throw new Error(`Invalid agent graph ${name}`);
}
}
export function assertAgentGraphSupervisorWakeClaim(
request: ClaimAgentGraphSupervisorWakeRequest,
): void {
if (request.schemaVersion !== AGENT_GRAPH_SUPERVISOR_WAKE_SCHEMA_VERSION) {
throw new Error('Invalid agent graph supervisor wake schema');
}
assertGraphLookupIdentity(request.graphId, 'graph id');
assertGraphLookupIdentity(request.wakeId, 'supervisor wake id');
assertGraphLookupIdentity(request.snapshotVersion, 'snapshot version');
assertSafeSessionId(request.rootSessionId);
}
export function assertAgentGraphSupervisorWakeAttempt(
request: BeginAgentGraphSupervisorWakeAttemptRequest,
): void {
assertGraphLookupIdentity(request.graphId, 'graph id');
assertGraphLookupIdentity(request.wakeId, 'supervisor wake id');
assertGraphLookupIdentity(request.attemptId, 'supervisor wake attempt id');
assertGraphLookupIdentity(request.turnId, 'supervisor wake turn id');
}
export function assertAgentGraphSupervisorWakeCompletion(
request: CompleteAgentGraphSupervisorWakeAttemptRequest,
): void {
assertGraphLookupIdentity(request.graphId, 'graph id');
assertGraphLookupIdentity(request.wakeId, 'supervisor wake id');
assertGraphLookupIdentity(request.attemptId, 'supervisor wake attempt id');
if (
request.status !== 'waiting_permission' &&
request.status !== 'delivered' &&
request.status !== 'superseded' &&
request.status !== 'retryable_failed'
) {
throw new Error('Invalid agent graph supervisor wake completion status');
}
if (
(request.status === 'retryable_failed' || request.status === 'superseded') &&
(!request.failureReason?.trim() || request.failureReason.length > 4_000)
) {
throw new Error('Agent graph supervisor wake failure reason must be non-empty and bounded');
}
}
export function assertAgentGraphClientProjectionRequest(
request: CommitAgentGraphClientProjectionRequest,
): void {
if (
request.schemaVersion !== AGENT_GRAPH_CLIENT_PROJECTION_SCHEMA_VERSION ||
(request.expectedSnapshotVersion !== null &&
typeof request.expectedSnapshotVersion !== 'string') ||
typeof request.replaceOperators !== 'boolean' ||
!Array.isArray(request.operators) ||
!Array.isArray(request.terminalActivities) ||
!Array.isArray(request.activityRecords)
) {
throw new Error('Invalid agent graph client projection request');
}
assertGraphLookupIdentity(request.graphId, 'graph id');
assertSafeSessionId(request.rootSessionId);
if (request.expectedSnapshotVersion !== null) {
assertGraphLookupIdentity(request.expectedSnapshotVersion, 'expected snapshot version');
}
assertGraphLookupIdentity(request.snapshotVersion, 'snapshot version');
const operatorIds = new Set<string>();
for (const operator of request.operators) {
assertGraphLookupIdentity(operator.operatorId, 'operator id');
if (operatorIds.has(operator.operatorId)) {
throw new Error(`Duplicate agent graph client operator ${operator.operatorId}`);
}
operatorIds.add(operator.operatorId);
}
const terminalIds = new Set<string>();
for (const terminal of request.terminalActivities) {
assertGraphLookupIdentity(terminal.recordId, 'terminal record id');
assertGraphEventTime(terminal.eventTime);
if (terminalIds.has(terminal.recordId)) {
throw new Error(`Duplicate agent graph terminal activity ${terminal.recordId}`);
}
terminalIds.add(terminal.recordId);
}
const activityIds = new Set<string>();
for (const record of request.activityRecords) {
assertGraphLookupIdentity(record.recordId, 'activity record id');
assertGraphEventTime(record.eventTime);
if (activityIds.has(record.recordId)) {
throw new Error(`Duplicate agent graph activity ${record.recordId}`);
}
activityIds.add(record.recordId);
}
if (request.incrementalRecordId !== undefined) {
assertGraphLookupIdentity(request.incrementalRecordId, 'incremental record id');
if (request.expectedSnapshotVersion === null || !activityIds.has(request.incrementalRecordId)) {
throw new Error('Invalid incremental agent graph projection record');
}
}
}
export function encodeProjectionPayload(payload: unknown, name: string): string {
const encoded = JSON.stringify(payload);
if (encoded === undefined) {
throw new Error(`Invalid agent graph ${name} payload`);
}
return encoded;
}
export function assertGraphEventTime(value: number): void {
if (!Number.isSafeInteger(value) || value < 0) {
throw new Error('Invalid agent graph terminal activity event time');
}
}
export function assertGraphIntentId(value: string): void {
if (!/^graph_intent_[a-f0-9]{32}$/.test(value)) {
throw new Error('Invalid agent graph intent id');
}
}