Add exact runtime conformance lookup and agent-visible language limits
This commit is contained in:
+41
-39
@@ -42,7 +42,7 @@ import {
|
||||
PackageRuntime,
|
||||
WatchEventSchema,
|
||||
} from "./quixos/runtime_pb.js";
|
||||
import { CapabilityRefSchema } from "./quixos/refs_pb.js";
|
||||
import { CapabilityRefSchema, type ConformanceWitness } from "./quixos/refs_pb.js";
|
||||
|
||||
export type CaminoClient = Client<typeof CaminoService>;
|
||||
export type OrchClient = Client<typeof OrchestratorRuntime>;
|
||||
@@ -200,6 +200,7 @@ export type ConstructorPort = {
|
||||
export type RuntimePort = StatePort | EdgePort | InterfacePort | ConstructorPort;
|
||||
|
||||
export type RuntimeContext = {
|
||||
tryConform(object: QxObjectRef, interfaceRevisionId: string): Promise<InterfacePort | undefined>;
|
||||
/** Cooperative cancellation. Completion is acknowledged only after the handler returns. */
|
||||
signal?: AbortSignal;
|
||||
openSession?: () => Promise<RuntimeSession>;
|
||||
@@ -238,6 +239,37 @@ export const createRuntimeContext = (
|
||||
orch: OrchClient,
|
||||
request: RuntimeRequest,
|
||||
): RuntimeContext => {
|
||||
const acquiredPort = (
|
||||
objectId: string,
|
||||
interfaceRevisionId: string,
|
||||
conformance?: ConformanceWitness,
|
||||
): InterfacePort => {
|
||||
const invoke = async (operationId: string, input: Record<string, unknown> = {}) => {
|
||||
const response = await orch.invokeCapability({
|
||||
objectId,
|
||||
capability: create(CapabilityRefSchema, { interfaceRevisionId, operationId, conformance }),
|
||||
input: Object.fromEntries(Object.entries(input).map(([key, value]) => [key, jsToProtoValue(value)])),
|
||||
});
|
||||
if (!response.ok) throw new Error(response.error || "Capability invocation failed");
|
||||
for (const dependency of response.dependencies) {
|
||||
if (dependency.kind === "state" || dependency.kind === "edge")
|
||||
await recordDependency({
|
||||
kind: dependency.kind,
|
||||
objectId: dependency.objectId,
|
||||
attachmentId: dependency.attachmentId,
|
||||
...(dependency.kind === "edge" ? { projectionId: dependency.projectionId } : {}),
|
||||
} as RuntimeDependency);
|
||||
}
|
||||
if (!response.result) throw new Error("Capability returned no value");
|
||||
return response.result;
|
||||
};
|
||||
return {
|
||||
objectId: referenceFromWire(objectId),
|
||||
interfaceRevisionId,
|
||||
invoke: async (operation, input) => protoValueToJs(await invoke(operation, input)),
|
||||
live: async (operation, input) => liveValue(await invoke(operation, input)),
|
||||
};
|
||||
};
|
||||
const ports = new Map<string, RuntimePort>();
|
||||
for (const dependency of request.dependencies) {
|
||||
switch (dependency.binding.case) {
|
||||
@@ -346,44 +378,7 @@ export const createRuntimeContext = (
|
||||
case "interfaceRevisionId": {
|
||||
const interfaceRevisionId = dependency.binding.value;
|
||||
const dependencyObjectId = dependency.objectId || request.objectId;
|
||||
const invoke = async (operationId: string, input: Record<string, unknown>) => {
|
||||
const response = await orch.invokeCapability({
|
||||
capability: create(CapabilityRefSchema, { interfaceRevisionId, operationId }),
|
||||
objectId: dependencyObjectId,
|
||||
input: Object.fromEntries(Object.entries(input).map(([key, value]) => [key, jsToProtoValue(value)])),
|
||||
});
|
||||
if (!response.ok) throw new Error(response.error || `Capability ${operationId} failed`);
|
||||
for (const dependency of response.dependencies) {
|
||||
if (dependency.kind === "state") {
|
||||
await recordDependency({
|
||||
kind: "state",
|
||||
objectId: dependency.objectId,
|
||||
attachmentId: dependency.attachmentId,
|
||||
});
|
||||
} else if (dependency.kind === "edge") {
|
||||
await recordDependency({
|
||||
kind: "edge",
|
||||
objectId: dependency.objectId,
|
||||
attachmentId: dependency.attachmentId,
|
||||
projectionId: dependency.projectionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
return response.result;
|
||||
};
|
||||
const capability: InterfacePort = {
|
||||
objectId: referenceFromWire(dependencyObjectId),
|
||||
interfaceRevisionId,
|
||||
async invoke(operationId, input = {}) {
|
||||
return protoValueToJs(await invoke(operationId, input));
|
||||
},
|
||||
async live(operationId, input = {}) {
|
||||
const value = await invoke(operationId, input);
|
||||
if (!value) throw new Error(`Capability ${operationId} returned no value`);
|
||||
return liveValue(value);
|
||||
},
|
||||
};
|
||||
ports.set(dependency.portId, capability);
|
||||
ports.set(dependency.portId, acquiredPort(dependencyObjectId, interfaceRevisionId));
|
||||
break;
|
||||
}
|
||||
case "constructorAtomId": {
|
||||
@@ -409,6 +404,13 @@ export const createRuntimeContext = (
|
||||
return port as T;
|
||||
};
|
||||
return {
|
||||
async tryConform(object, interfaceRevisionId) {
|
||||
const objectId = referenceToWire(object);
|
||||
const { conformance } = await orch.tryConform({ objectId, interfaceRevisionId });
|
||||
if (conformance && (conformance.objectId !== objectId || conformance.interfaceRevisionId !== interfaceRevisionId))
|
||||
throw new Error("Conformance response does not match the requested view");
|
||||
return conformance ? acquiredPort(objectId, interfaceRevisionId, conformance) : undefined;
|
||||
},
|
||||
get objectId() {
|
||||
return referenceFromWire(request.objectId);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user