All files / llm-bridge/src protocol.ts

0% Statements 0/10
100% Branches 0/0
100% Functions 0/0
0% Lines 0/10

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88                                                                                                                                                                               
/**
 * Wire protocol for the LLM bridge.
 *
 * The bridge talks to its caller (the matcher vat, in this codebase)
 * over a Unix socket as line-delimited JSON. Two request kinds, three
 * possible reply kinds. The bridge owns conversation state; the caller
 * just sends digests of services as they register and free-text queries
 * as consumers ask for matches.
 */
 
import {
  array,
  exactOptional,
  literal,
  object,
  string,
  union,
} from '@metamask/superstruct';
import type { Infer } from '@metamask/superstruct';
 
/**
 * Per-method digest sent over the wire. The full `MethodSpec` type from
 * `@metamask/service-discovery-types` carries a recursive parameter/return
 * type tree we don't need the LLM to see.
 */
export const MethodDigestStruct = object({
  name: string(),
  description: exactOptional(string()),
});
export type MethodDigest = Infer<typeof MethodDigestStruct>;
 
/**
 * Compact projection of a `ServiceDescription` that the bridge actually
 * uses in its prompts. The caller supplies the opaque `id` (which the
 * LLM will cite back in its query replies).
 */
export const ServiceDigestStruct = object({
  id: string(),
  description: string(),
  methods: array(MethodDigestStruct),
});
export type ServiceDigest = Infer<typeof ServiceDigestStruct>;
 
export const IngestRequestStruct = object({
  kind: literal('ingest'),
  service: ServiceDigestStruct,
});
export type IngestRequest = Infer<typeof IngestRequestStruct>;
 
export const QueryRequestStruct = object({
  kind: literal('query'),
  query: string(),
});
export type QueryRequest = Infer<typeof QueryRequestStruct>;
 
export const RequestStruct = union([IngestRequestStruct, QueryRequestStruct]);
export type Request = Infer<typeof RequestStruct>;
 
export const IngestedReplyStruct = object({
  kind: literal('ingested'),
});
export type IngestedReply = Infer<typeof IngestedReplyStruct>;
 
export const MatchEntryStruct = object({
  id: string(),
  rationale: string(),
});
export type MatchEntry = Infer<typeof MatchEntryStruct>;
 
export const MatchesReplyStruct = object({
  kind: literal('matches'),
  matches: array(MatchEntryStruct),
});
export type MatchesReply = Infer<typeof MatchesReplyStruct>;
 
export const ErrorReplyStruct = object({
  kind: literal('error'),
  message: string(),
});
export type ErrorReply = Infer<typeof ErrorReplyStruct>;
 
export const ReplyStruct = union([
  IngestedReplyStruct,
  MatchesReplyStruct,
  ErrorReplyStruct,
]);
export type Reply = Infer<typeof ReplyStruct>;