blob: 910b72ed4b10b196cd40f86f33ce6d7608325ca4 [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 { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import {
decodeRuntimeEvent,
decodeRuntimeInvocationOpened,
runtimeEventHasModelVisibleContent,
runtimeEventInvocationOpening,
RUNTIME_EVENT_CONTENT_KINDS,
type RuntimeEvent,
type RuntimeEventInvocationOpenedContent,
} from '../runtime-event.js';
const DIGEST = `sha256:${'a'.repeat(64)}` as const;
function opening(
overrides: Partial<RuntimeEventInvocationOpenedContent> = {},
): RuntimeEventInvocationOpenedContent {
return {
kind: 'invocation_opened',
protocol: 'invocation_opened_v1',
route: {
provenance: 'runtime',
backendKind: 'ai-sdk',
llmConnectionId: 'conn-1',
llmConnectionSlug: 'anthropic',
modelId: 'claude-x',
providerStateIdentity: DIGEST,
},
configuration: {
cwd: '/repo',
permissionMode: 'ask',
collaborationMode: 'agent',
orchestrationMode: 'default',
orchestrationSource: 'session',
toolMode: 'direct',
},
root: { kind: 'user' },
source: { kind: 'fresh' },
...overrides,
};
}
function openingEvent(content: unknown): unknown {
return {
id: 'evt-open',
invocationId: 'inv-1',
runId: 'inv-1',
sessionId: 'sess-1',
turnId: 'turn-1',
ts: 10,
partial: false,
role: 'system',
author: 'system',
modelVisibility: 'hidden',
content,
};
}
describe('invocation_opened content contract', () => {
test('is a runtime event content kind', () => {
assert.ok(RUNTIME_EVENT_CONTENT_KINDS.includes('invocation_opened'));
});
test('decodes as RuntimeEvent content and narrows back out', () => {
const event = decodeRuntimeEvent(openingEvent(opening()));
const fact = runtimeEventInvocationOpening(event);
assert.ok(fact);
assert.equal(fact.protocol, 'invocation_opened_v1');
assert.equal(fact.route.provenance, 'runtime');
assert.equal(fact.route.modelId, 'claude-x');
});
test('is never model visible', () => {
const event = decodeRuntimeEvent(openingEvent(opening())) as RuntimeEvent;
assert.equal(runtimeEventHasModelVisibleContent(event), false);
});
test('binds connection identity to where the route came from, both ways', () => {
const unknownRoute = {
provenance: 'unknown',
backendKind: 'ai-sdk',
llmConnectionSlug: 'legacy',
modelId: 'legacy-model',
} as const;
assert.equal(
decodeRuntimeInvocationOpened(opening({ route: unknownRoute })).route.provenance,
'unknown',
);
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({ route: { ...unknownRoute, llmConnectionId: 'conn-1' } as never }),
),
);
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({ route: { ...unknownRoute, provenance: 'runtime' } as never }),
),
);
});
test('binds a plugin executor route to its exact activation generation', () => {
const route = {
provenance: 'runtime',
backendKind: 'plugin-executor',
executorId: 'codex.app-server',
llmConnectionSlug: 'executor:codex.app-server',
modelId: 'codex.app-server',
providerStateIdentity: DIGEST,
} as const;
assert.deepEqual(decodeRuntimeInvocationOpened(opening({ route })).route, route);
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({ route: { ...route, providerStateIdentity: undefined } as never }),
),
);
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({ route: { ...route, llmConnectionId: 'not-an-executor-route' } as never }),
),
);
});
test('accepts every root authority the runtime can open, and no mixture of them', () => {
for (const root of [
{ kind: 'user' },
{ kind: 'context_compact' },
{ kind: 'scheduled_task', scheduledTaskId: 'task-1' },
{ kind: 'goal', goalId: 'goal-1' },
{ kind: 'agent_graph_supervisor_wake', wakeId: 'w1', attemptId: 'a1' },
{ kind: 'legacy_automation', legacyAutomationId: 'auto-1' },
] as const) {
assert.equal(decodeRuntimeInvocationOpened(opening({ root })).root.kind, root.kind);
}
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({ root: { kind: 'goal', goalId: 'g1', scheduledTaskId: 's1' } as never }),
),
);
});
test('carries a continuation source only with the boundary position it resumes from', () => {
const source = {
kind: 'continuation',
sourceInvocationId: 'inv-0',
sourceRunId: 'inv-0',
sourceTurnId: 'turn-0',
} as const;
const fact = decodeRuntimeInvocationOpened(
opening({
source: {
...source,
sourceRuntimeEventHighWater: 7,
claimId: 'claim-1',
boundaryDigest: DIGEST,
},
}),
);
assert.equal(fact.source.kind, 'continuation');
assert.throws(() => decodeRuntimeInvocationOpened(opening({ source: source as never })));
});
test('rejects anything the closed shape does not name', () => {
assert.throws(() =>
decodeRuntimeInvocationOpened({ ...opening(), runComposition: {} } as never),
);
assert.throws(() =>
decodeRuntimeInvocationOpened(
opening({
configuration: { ...opening().configuration, sessionMode: 'agent' } as never,
}),
),
);
});
test('a malformed opening fact fails the whole RuntimeEvent decode', () => {
assert.throws(() =>
decodeRuntimeEvent(
openingEvent({ kind: 'invocation_opened', protocol: 'invocation_opened_v1' }),
),
);
});
});