import * as NodeCrypto from "@effect/platform-node/NodeCrypto";import { expect, it } from "@effect/vitest";import { EnvironmentId, ProviderInstanceId, ThreadId } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer"; import { OrchestratorProjectionError } from "../orchestration-v2/Orchestrator.ts";import * as ThreadManagement from "../orchestration-v2/ThreadManagementService.ts";import type * as McpInvocationContext from "./McpInvocationContext.ts";import * as ThreadMetadataMcp from "./ThreadMetadataMcpService.ts"; const threadId = ThreadId.make("thread:metadata-caller");const scope: McpInvocationContext.McpInvocationScope = { environmentId: EnvironmentId.make("environment:metadata-test"), threadId, providerSessionId: "provider-session:metadata-test", providerInstanceId: ProviderInstanceId.make("codex"), capabilities: new Set(["orchestration"]), issuedAt: 1,}; function serviceLayer( getThreadShell: ThreadManagement.ThreadManagementService["Service"]["getThreadShell"],) { return ThreadMetadataMcp.layer.pipe( Layer.provide( Layer.merge( Layer.mock(ThreadManagement.ThreadManagementService)({ getThreadShell, getThreadProjection: () => Effect.die("projection must not load after shell failure"), } satisfies Partial<ThreadManagement.ThreadManagementService["Service"]>), NodeCrypto.layer, ), ), );} const updateCallingThread = Effect.gen(function* () { const service = yield* ThreadMetadataMcp.ThreadMetadataMcpService; return yield* service.update(scope, { action: "rename", title: "Renamed thread", clientRequestId: "metadata-caller-classification", });}); it.effect("reports an absent calling thread as thread_not_found", () => Effect.gen(function* () { const error = yield* updateCallingThread.pipe( Effect.provide(serviceLayer(() => Effect.succeed(null))), Effect.flip, ); expect(error.code).toBe("thread_not_found"); }),); it.effect("keeps calling-thread storage failures as orchestration errors", () => Effect.gen(function* () { const error = yield* updateCallingThread.pipe( Effect.provide( serviceLayer(() => Effect.fail( new OrchestratorProjectionError({ threadId, cause: new Error("storage unavailable"), }), ), ), ), Effect.flip, ); expect(error.code).toBe("orchestration_error"); }),);
import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
import { expect, it } from "@effect/vitest";
import { EnvironmentId, ProviderInstanceId, ThreadId } from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import { OrchestratorProjectionError } from "../orchestration-v2/Orchestrator.ts";
import * as ThreadManagement from "../orchestration-v2/ThreadManagementService.ts";
import type * as McpInvocationContext from "./McpInvocationContext.ts";
import * as ThreadMetadataMcp from "./ThreadMetadataMcpService.ts";
const threadId = ThreadId.make("thread:metadata-caller");
const scope: McpInvocationContext.McpInvocationScope = {
environmentId: EnvironmentId.make("environment:metadata-test"),
threadId,
providerSessionId: "provider-session:metadata-test",
providerInstanceId: ProviderInstanceId.make("codex"),
capabilities: new Set(["orchestration"]),
issuedAt: 1,
};
function serviceLayer(
getThreadShell: ThreadManagement.ThreadManagementService["Service"]["getThreadShell"],
) {
return ThreadMetadataMcp.layer.pipe(
Layer.provide(
Layer.merge(
Layer.mock(ThreadManagement.ThreadManagementService)({
getThreadShell,
getThreadProjection: () => Effect.die("projection must not load after shell failure"),
} satisfies Partial<ThreadManagement.ThreadManagementService["Service"]>),
NodeCrypto.layer,
),
),
);
}
const updateCallingThread = Effect.gen(function* () {
const service = yield* ThreadMetadataMcp.ThreadMetadataMcpService;
return yield* service.update(scope, {
action: "rename",
title: "Renamed thread",
clientRequestId: "metadata-caller-classification",
});
});
it.effect("reports an absent calling thread as thread_not_found", () =>
Effect.gen(function* () {
const error = yield* updateCallingThread.pipe(
Effect.provide(serviceLayer(() => Effect.succeed(null))),
Effect.flip,
);
expect(error.code).toBe("thread_not_found");
}),
);
it.effect("keeps calling-thread storage failures as orchestration errors", () =>
Effect.gen(function* () {
const error = yield* updateCallingThread.pipe(
Effect.provide(
serviceLayer(() =>
Effect.fail(
new OrchestratorProjectionError({
threadId,
cause: new Error("storage unavailable"),
}),
),
),
),
Effect.flip,
);
expect(error.code).toBe("orchestration_error");
}),
);