1import * as Schema from "effect/Schema";
2
3import {
4 IsoDateTime,
5 MessageId,
6 ProjectId,
7 ThreadId,
8 TrimmedNonEmptyString,
9 TrimmedString,
10} from "./baseSchemas.ts";
11
12export const OrchestrationThreadSearchSource = Schema.Literals(["user", "assistant"]);
13export type OrchestrationThreadSearchSource = typeof OrchestrationThreadSearchSource.Type;
14
15/** Longer queries are cut to this before they are sent. */
16export const THREAD_SEARCH_QUERY_MAX_LENGTH = 200;
17
18// The server's SQLite client is synchronous and single-connection. Bound both
19// scan input and response size so a search cannot monopolize that connection.
20export const OrchestrationSearchThreadsInput = Schema.Struct({
21 query: TrimmedString.check(
22 Schema.isMinLength(2),
23 Schema.isMaxLength(THREAD_SEARCH_QUERY_MAX_LENGTH),
24 ),
25 limit: Schema.optionalKey(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 50 }))),
26});
27export type OrchestrationSearchThreadsInput = typeof OrchestrationSearchThreadsInput.Type;
28
29export const OrchestrationThreadSearchMatch = Schema.Struct({
30 threadId: ThreadId,
31 projectId: ProjectId,
32 source: OrchestrationThreadSearchSource,
33 snippet: Schema.String.check(Schema.isMaxLength(240)),
34 messageCreatedAt: Schema.NullOr(IsoDateTime),
35 /**
36 * How well the message matches: 1 for whole words, 0.8 when a word only
37 * starts one, 0.3 when one only appears inside words, 0.25 more when the
38 * words are written together as typed, else 0.1 more when they are near.
39 * Older servers omit it.
40 */
41 quality: Schema.optionalKey(Schema.Finite),
42 /** How many of the thread's newest messages match. Older servers omit it. */
43 hits: Schema.optionalKey(Schema.Int),
44 /** The message the snippet is from. Older servers omit it. */
45 messageId: Schema.optionalKey(MessageId),
46});
47export type OrchestrationThreadSearchMatch = typeof OrchestrationThreadSearchMatch.Type;
48
49export const OrchestrationSearchThreadsResult = Schema.Struct({
50 matches: Schema.Array(OrchestrationThreadSearchMatch),
51});
52export type OrchestrationSearchThreadsResult = typeof OrchestrationSearchThreadsResult.Type;
53
54export class OrchestrationSearchThreadsError extends Schema.TaggedError<OrchestrationSearchThreadsError>()(
55 "OrchestrationSearchThreadsError",
56 {
57 message: TrimmedNonEmptyString,
58 cause: Schema.optional(Schema.Defect()),
59 },
60) {}