Buckets:
| import { Effect, Layer, Ref } from "effect" | |
| import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" | |
| import { LLMClient, RequestExecutor, WebSocketExecutor } from "../../src/route" | |
| import type { Service as LLMClientService } from "../../src/route/client" | |
| import type { Service as RequestExecutorService } from "../../src/route/executor" | |
| import type { Service as WebSocketExecutorService } from "../../src/route/transport/websocket" | |
| export type HandlerInput = { | |
| readonly request: HttpClientRequest.HttpClientRequest | |
| readonly text: string | |
| readonly respond: ( | |
| body: ConstructorParameters<typeof Response>[0], | |
| init?: ResponseInit, | |
| ) => HttpClientResponse.HttpClientResponse | |
| } | |
| export type Handler = (input: HandlerInput) => Effect.Effect<HttpClientResponse.HttpClientResponse> | |
| const handlerLayer = (handler: Handler): Layer.Layer<HttpClient.HttpClient> => | |
| Layer.succeed( | |
| HttpClient.HttpClient, | |
| HttpClient.make((request) => | |
| Effect.gen(function* () { | |
| const web = yield* HttpClientRequest.toWeb(request).pipe(Effect.orDie) | |
| const text = yield* Effect.promise(() => web.text()) | |
| return yield* handler({ | |
| request, | |
| text, | |
| respond: (body, init) => HttpClientResponse.fromWeb(request, new Response(body, init)), | |
| }) | |
| }), | |
| ), | |
| ) | |
| export type RuntimeEnv = RequestExecutorService | WebSocketExecutorService | LLMClientService | |
| export const runtimeLayer = (layer: Layer.Layer<HttpClient.HttpClient>): Layer.Layer<RuntimeEnv> => { | |
| const requestExecutorLayer = RequestExecutor.layer.pipe(Layer.provide(layer)) | |
| const deps = Layer.mergeAll(requestExecutorLayer, WebSocketExecutor.layer) | |
| const llmClientLayer = LLMClient.layer.pipe(Layer.provide(deps)) | |
| return Layer.mergeAll(deps, llmClientLayer) | |
| } | |
| const SSE_HEADERS = { "content-type": "text/event-stream" } as const | |
| /** | |
| * Layer that returns a single fixed response body. Use for stream-parser | |
| * fixture tests where the request shape is irrelevant. The body type widens | |
| * to whatever `Response` accepts so binary fixtures (`Uint8Array`, | |
| * `ReadableStream`, etc.) flow through without casts. | |
| */ | |
| export const fixedResponse = ( | |
| body: ConstructorParameters<typeof Response>[0], | |
| init: ResponseInit = { headers: SSE_HEADERS }, | |
| ) => runtimeLayer(handlerLayer((input) => Effect.succeed(input.respond(body, init)))) | |
| /** | |
| * Layer that builds a response per request. Useful for echo servers. | |
| */ | |
| export const dynamicResponse = (handler: Handler) => runtimeLayer(handlerLayer(handler)) | |
| /** | |
| * Layer that emits the supplied SSE chunks and then aborts mid-stream. Used to | |
| * exercise transport errors that surface during parsing. | |
| */ | |
| export const truncatedStream = (chunks: ReadonlyArray<string>) => | |
| dynamicResponse((input) => | |
| Effect.sync(() => { | |
| const encoder = new TextEncoder() | |
| const stream = new ReadableStream({ | |
| start(controller) { | |
| for (const chunk of chunks) controller.enqueue(encoder.encode(chunk)) | |
| controller.error(new Error("connection reset")) | |
| }, | |
| }) | |
| return input.respond(stream, { headers: SSE_HEADERS }) | |
| }), | |
| ) | |
| /** | |
| * Layer that returns successive bodies on each request. Useful for scripting | |
| * multi-step model exchanges (e.g. tool-call loops). The last body in the | |
| * array is reused if the test makes more requests than scripted. | |
| */ | |
| export const scriptedResponses = (bodies: ReadonlyArray<string>, init: ResponseInit = { headers: SSE_HEADERS }) => { | |
| if (bodies.length === 0) throw new Error("scriptedResponses requires at least one body") | |
| return Layer.unwrap( | |
| Effect.gen(function* () { | |
| const cursor = yield* Ref.make(0) | |
| return dynamicResponse((input) => | |
| Effect.gen(function* () { | |
| const index = yield* Ref.getAndUpdate(cursor, (n) => n + 1) | |
| return input.respond(bodies[index] ?? bodies[bodies.length - 1], init) | |
| }), | |
| ) | |
| }), | |
| ) | |
| } | |
Xet Storage Details
- Size:
- 3.95 kB
- Xet hash:
- 7e653cd3da220fe5b35f782abaa71787b0467298a3508026517258671cc0d783
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.