Parent directory

events.ts

2292 bytes
 1import type {
 2  Event,
 3  EventMessageUpdated,
 4  EventMessagePartUpdated,
 5  Part,
 6} from "@opencode-ai/sdk";
 7import * as log from "./log.js";
 8
 9// Server sends `permission.asked` with this shape, which diverges from the SDK's
10// v1 Permission type. Keep a local interface until the SDK aligns.
11export interface PermissionEvent {
12  id: string;
13  sessionID: string;
14  permission: string;
15  patterns: string[];
16  metadata: Record<string, unknown>;
17  always?: string[];
18  tool?: { messageID: string; callID: string };
19}
20
21export type PartHandler = (parts: Part[]) => void;
22export type PermissionHandler = (perm: PermissionEvent) => void;
23
24interface SessionHandler {
25  onPart: PartHandler;
26  onPermission: PermissionHandler;
27  parts: Map<string, Part>;
28  assistantMessageIDs: Set<string>;
29}
30
31const handlers = new Map<string, SessionHandler>();
32
33export function registerSession(
34  sessionId: string,
35  onPart: PartHandler,
36  onPermission: PermissionHandler,
37): void {
38  handlers.set(sessionId, {
39    onPart,
40    onPermission,
41    parts: new Map(),
42    assistantMessageIDs: new Set(),
43  });
44}
45
46export function unregisterSession(sessionId: string): void {
47  handlers.delete(sessionId);
48}
49
50export function handleEvent(event: Event): void {
51  const type = event.type as string;
52
53  if (type === "message.updated") {
54    const info = (event as EventMessageUpdated).properties.info;
55    if (info.role !== "assistant") return;
56    const handler = handlers.get(info.sessionID);
57    if (!handler) return;
58    handler.assistantMessageIDs.add(info.id);
59    return;
60  }
61
62  if (type === "message.part.updated") {
63    const part = (event as EventMessagePartUpdated).properties.part;
64    const handler = handlers.get(part.sessionID);
65    if (!handler) return;
66    if (!handler.assistantMessageIDs.has(part.messageID)) return;
67    handler.parts.set(part.id, part);
68    handler.onPart(Array.from(handler.parts.values()));
69    return;
70  }
71
72  if (type === "permission.asked" || type === "permission.updated") {
73    const perm = event.properties as unknown as PermissionEvent;
74    log.info(
75      `[events] ${type} session=${perm.sessionID} perm=${perm.id} permission=${perm.permission}`,
76    );
77    const handler = handlers.get(perm.sessionID);
78    if (!handler) return;
79    handler.onPermission(perm);
80    return;
81  }
82}