Skip to content
Source
Sign inSign up

RuntimeRequestService.test.ts

100 lines3.3 KB

1import { assert, it, vi } from "@effect/vitest";
2import {
3 NodeId,
4 ProviderSessionId,
5 RuntimeRequestId,
6 ThreadId,
7 type OrchestrationV2ThreadProjection,
8} from "@t3tools/contracts";
9import * as DateTime from "effect/DateTime";
10import * as Effect from "effect/Effect";
11import * as Layer from "effect/Layer";
12​
13import type * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
14import * as ProjectionStore from "./ProjectionStore.ts";
15import * as ProviderSessionManager from "./ProviderSessionManager.ts";
16import * as RuntimeRequestService from "./RuntimeRequestService.ts";
17​
18it.effect.each(["expired", "resolved"] as const)(
19 "responds only to resolved requests and preserves feedback (%s)",
20 (status) => {
21 const threadId = ThreadId.make("thread-runtime-request-expired");
22 const providerSessionId = ProviderSessionId.make("provider-session-runtime-request-expired");
23 const requestId = RuntimeRequestId.make("request-expired");
24 const respondToRuntimeRequest = vi.fn(
25 (_input: ProviderAdapter.ProviderAdapterV2RuntimeRequestResponseInput) => Effect.void,
26 );
27 const getSession = vi.fn(() =>
28 Effect.succeedSome({
29 respondToRuntimeRequest,
30 } as never),
31 );
32 const projection = {
33 runtimeRequests: [
34 {
35 id: requestId,
36 nodeId: NodeId.make("node-runtime-request-expired"),
37 providerTurnId: null,
38 nativeRequestRef: null,
39 kind: "command",
40 status,
41 responseCapability: {
42 type: "live",
43 providerSessionId,
44 },
45 createdAt: DateTime.makeUnsafe("2026-07-29T00:00:00.000Z"),
46 resolvedAt: DateTime.makeUnsafe("2026-07-29T00:00:01.000Z"),
47 },
48 ],
49 } as unknown as OrchestrationV2ThreadProjection;
50 const layerTest = RuntimeRequestService.layer.pipe(
51 Layer.provide(
52 Layer.mergeAll(
53 Layer.mock(ProjectionStore.ProjectionStoreV2)({
54 getRuntimeRequest: (_threadId, requestId) =>
55 Effect.succeed(
56 projection.runtimeRequests.find((request) => request.id === requestId),
57 ),
58 }),
59 Layer.mock(ProviderSessionManager.ProviderSessionManagerV2)({
60 get: getSession,
61 }),
62 ),
63 ),
64 );
65​
66 return Effect.gen(function* () {
67 const service = yield* RuntimeRequestService.RuntimeRequestServiceV2;
68 const response = service.respond({
69 threadId,
70 providerSessionId,
71 requestId,
72 decision: "decline",
73 feedback: "Use an explicit path.",
74 });
75 if (status === "resolved") {
76 yield* response;
77 assert.deepEqual(respondToRuntimeRequest.mock.calls, [
78 [
79 {
80 requestId,
81 decision: "decline",
82 feedback: "Use an explicit path.",
83 },
84 ],
85 ]);
86 return;
87 }
88 const error = yield* response.pipe(Effect.flip);
89​
90 assert.equal(error.reason, "request-not-ready");
91 assert.equal(
92 error.message,
93 `Runtime request ${requestId} on thread ${threadId} is not ready for response execution.`,
94 );
95 assert.isUndefined(error.cause);
96 assert.equal(getSession.mock.calls.length, 0);
97 assert.equal(respondToRuntimeRequest.mock.calls.length, 0);
98 }).pipe(Effect.provide(layerTest));
99 },
100);