{"version":3,"file":"in-memory.cjs","names":["AgentRunner","EventType","ReplaySubject"],"sources":["../../../../src/v2/runtime/runner/in-memory.ts"],"sourcesContent":["import {\n  AgentRunner,\n  AgentRunnerConnectRequest,\n  AgentRunnerIsRunningRequest,\n  AgentRunnerRunRequest,\n  type AgentRunnerStopRequest,\n} from \"./agent-runner\";\nimport { Observable, ReplaySubject } from \"rxjs\";\nimport {\n  AbstractAgent,\n  BaseEvent,\n  EventType,\n  MessagesSnapshotEvent,\n  RunStartedEvent,\n  compactEvents,\n} from \"@ag-ui/client\";\nimport { finalizeRunEvents } from \"@copilotkit/shared\";\n\ninterface HistoricRun {\n  threadId: string;\n  runId: string;\n  parentRunId: string | null;\n  events: BaseEvent[];\n  createdAt: number;\n}\n\nclass InMemoryEventStore {\n  constructor(public threadId: string) {}\n\n  /** The subject that current consumers subscribe to. */\n  subject: ReplaySubject<BaseEvent> | null = null;\n\n  /** True while a run is actively producing events. */\n  isRunning = false;\n\n  /** Current run ID */\n  currentRunId: string | null = null;\n\n  /** Historic completed runs */\n  historicRuns: HistoricRun[] = [];\n\n  /** Currently running agent instance (if any). */\n  agent: AbstractAgent | null = null;\n\n  /** Subject returned from run() while the run is active. */\n  runSubject: ReplaySubject<BaseEvent> | null = null;\n\n  /** True once stop() has been requested but the run has not yet finalized. */\n  stopRequested = false;\n\n  /** Reference to the events emitted in the current run. */\n  currentEvents: BaseEvent[] | null = null;\n}\n\n// Use a symbol key on globalThis to survive hot reloads in development\nconst GLOBAL_STORE_KEY = Symbol.for(\"@copilotkit/runtime/in-memory-store\");\n\ninterface GlobalStoreData {\n  stores: Map<string, InMemoryEventStore>;\n  historicRunsBackup: Map<string, HistoricRun[]>;\n}\n\nfunction getGlobalStore(): Map<string, InMemoryEventStore> {\n  const globalAny = globalThis as unknown as Record<symbol, GlobalStoreData>;\n\n  if (!globalAny[GLOBAL_STORE_KEY]) {\n    globalAny[GLOBAL_STORE_KEY] = {\n      stores: new Map<string, InMemoryEventStore>(),\n      historicRunsBackup: new Map<string, HistoricRun[]>(),\n    };\n  }\n\n  const data = globalAny[GLOBAL_STORE_KEY];\n\n  // Restore historic runs from backup after hot reload\n  // (when stores map is empty but backup has data)\n  if (data.stores.size === 0 && data.historicRunsBackup.size > 0) {\n    for (const [threadId, historicRuns] of data.historicRunsBackup) {\n      const store = new InMemoryEventStore(threadId);\n      store.historicRuns = historicRuns;\n      data.stores.set(threadId, store);\n    }\n  }\n\n  return data.stores;\n}\n\nfunction backupHistoricRuns(\n  threadId: string,\n  historicRuns: HistoricRun[],\n): void {\n  const globalAny = globalThis as unknown as Record<symbol, GlobalStoreData>;\n  if (globalAny[GLOBAL_STORE_KEY]) {\n    globalAny[GLOBAL_STORE_KEY].historicRunsBackup.set(threadId, historicRuns);\n  }\n}\n\nconst GLOBAL_STORE = getGlobalStore();\n\nexport class InMemoryAgentRunner extends AgentRunner {\n  run(request: AgentRunnerRunRequest): Observable<BaseEvent> {\n    let existingStore = GLOBAL_STORE.get(request.threadId);\n    if (!existingStore) {\n      existingStore = new InMemoryEventStore(request.threadId);\n      GLOBAL_STORE.set(request.threadId, existingStore);\n    }\n    const store = existingStore; // Now store is const and non-null\n\n    if (store.isRunning) {\n      throw new Error(\"Thread already running\");\n    }\n    store.isRunning = true;\n    store.currentRunId = request.input.runId;\n    store.agent = request.agent;\n    store.stopRequested = false;\n\n    // Track seen message IDs and current run events for this run\n    const seenMessageIds = new Set<string>();\n    const currentRunEvents: BaseEvent[] = [];\n    store.currentEvents = currentRunEvents;\n\n    // Get all previously seen message IDs from historic runs\n    const historicMessageIds = new Set<string>();\n    for (const run of store.historicRuns) {\n      for (const event of run.events) {\n        if (\"messageId\" in event && typeof event.messageId === \"string\") {\n          historicMessageIds.add(event.messageId);\n        }\n        if (event.type === EventType.RUN_STARTED) {\n          const runStarted = event as RunStartedEvent;\n          const messages = runStarted.input?.messages ?? [];\n          for (const message of messages) {\n            historicMessageIds.add(message.id);\n          }\n        }\n      }\n    }\n\n    const nextSubject = new ReplaySubject<BaseEvent>(Infinity);\n    const prevSubject = store.subject;\n\n    // Update the store's subject immediately\n    store.subject = nextSubject;\n\n    // Create a subject for run() return value\n    const runSubject = new ReplaySubject<BaseEvent>(Infinity);\n    store.runSubject = runSubject;\n\n    // Helper function to run the agent and handle errors\n    const runAgent = async () => {\n      // Get parent run ID for chaining\n      const lastRun = store.historicRuns[store.historicRuns.length - 1];\n      const parentRunId = lastRun?.runId ?? null;\n\n      try {\n        await request.agent.runAgent(request.input, {\n          onEvent: ({ event }) => {\n            let processedEvent: BaseEvent = event;\n            if (event.type === EventType.RUN_STARTED) {\n              const runStartedEvent = event as RunStartedEvent;\n              if (!runStartedEvent.input) {\n                const sanitizedMessages = request.input.messages\n                  ? request.input.messages.filter(\n                      (message) => !historicMessageIds.has(message.id),\n                    )\n                  : undefined;\n                const updatedInput = {\n                  ...request.input,\n                  ...(sanitizedMessages !== undefined\n                    ? { messages: sanitizedMessages }\n                    : {}),\n                };\n                processedEvent = {\n                  ...runStartedEvent,\n                  input: updatedInput,\n                } as RunStartedEvent;\n              }\n            }\n\n            runSubject.next(processedEvent); // For run() return - only agent events\n            nextSubject.next(processedEvent); // For connect() / store - all events\n            currentRunEvents.push(processedEvent); // Accumulate for storage\n          },\n          onNewMessage: ({ message }) => {\n            // Called for each new message\n            if (!seenMessageIds.has(message.id)) {\n              seenMessageIds.add(message.id);\n            }\n          },\n          onRunStartedEvent: () => {\n            // Mark any messages from the input as seen so they aren't emitted twice\n            if (request.input.messages) {\n              for (const message of request.input.messages) {\n                if (!seenMessageIds.has(message.id)) {\n                  seenMessageIds.add(message.id);\n                }\n              }\n            }\n          },\n        });\n\n        const appendedEvents = finalizeRunEvents(currentRunEvents, {\n          stopRequested: store.stopRequested,\n        });\n        for (const event of appendedEvents) {\n          runSubject.next(event);\n          nextSubject.next(event);\n        }\n\n        // Store the completed run in memory with ONLY its events\n        if (store.currentRunId) {\n          // Compact the events before storing (like SQLite does)\n          const compactedEvents = compactEvents(currentRunEvents);\n\n          store.historicRuns.push({\n            threadId: request.threadId,\n            runId: store.currentRunId,\n            parentRunId,\n            events: compactedEvents,\n            createdAt: Date.now(),\n          });\n\n          // Backup for hot reload survival\n          backupHistoricRuns(request.threadId, store.historicRuns);\n        }\n\n        // Complete the run\n        store.currentEvents = null;\n        store.currentRunId = null;\n        store.agent = null;\n        store.runSubject = null;\n        store.stopRequested = false;\n        store.isRunning = false;\n        runSubject.complete();\n        nextSubject.complete();\n      } catch (error) {\n        const interruptionMessage =\n          error instanceof Error ? error.message : String(error);\n        const appendedEvents = finalizeRunEvents(currentRunEvents, {\n          stopRequested: store.stopRequested,\n          interruptionMessage,\n        });\n        for (const event of appendedEvents) {\n          runSubject.next(event);\n          nextSubject.next(event);\n        }\n\n        // Store the run even if it failed (partial events)\n        if (store.currentRunId && currentRunEvents.length > 0) {\n          // Compact the events before storing (like SQLite does)\n          const compactedEvents = compactEvents(currentRunEvents);\n          store.historicRuns.push({\n            threadId: request.threadId,\n            runId: store.currentRunId,\n            parentRunId,\n            events: compactedEvents,\n            createdAt: Date.now(),\n          });\n\n          // Backup for hot reload survival\n          backupHistoricRuns(request.threadId, store.historicRuns);\n        }\n\n        // Complete the run\n        store.currentEvents = null;\n        store.currentRunId = null;\n        store.agent = null;\n        store.runSubject = null;\n        store.stopRequested = false;\n        store.isRunning = false;\n        runSubject.complete();\n        nextSubject.complete();\n      }\n    };\n\n    // Bridge previous events if they exist\n    if (prevSubject) {\n      prevSubject.subscribe({\n        next: (e) => nextSubject.next(e),\n        error: (err) => nextSubject.error(err),\n        complete: () => {\n          // Don't complete nextSubject here - it needs to stay open for new events\n        },\n      });\n    }\n\n    // Start the agent execution immediately (not lazily)\n    runAgent();\n\n    // Return the run subject (only agent events, no injected messages)\n    return runSubject.asObservable();\n  }\n\n  connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {\n    const store = GLOBAL_STORE.get(request.threadId);\n    const connectionSubject = new ReplaySubject<BaseEvent>(Infinity);\n\n    if (!store) {\n      // No store means no events\n      connectionSubject.complete();\n      return connectionSubject.asObservable();\n    }\n\n    // Collect all historic events from memory\n    const allHistoricEvents: BaseEvent[] = [];\n    for (const run of store.historicRuns) {\n      allHistoricEvents.push(...run.events);\n    }\n\n    // Apply compaction to all historic events together (like SQLite)\n    const compactedEvents = compactEvents(allHistoricEvents);\n\n    // Emit compacted events and track message IDs\n    const emittedMessageIds = new Set<string>();\n    for (const event of compactedEvents) {\n      connectionSubject.next(event);\n      if (\"messageId\" in event && typeof event.messageId === \"string\") {\n        emittedMessageIds.add(event.messageId);\n      }\n    }\n\n    // Bridge active run to connection if exists\n    if (store.subject && (store.isRunning || store.stopRequested)) {\n      store.subject.subscribe({\n        next: (event) => {\n          // Skip message events that we've already emitted from historic\n          if (\n            \"messageId\" in event &&\n            typeof event.messageId === \"string\" &&\n            emittedMessageIds.has(event.messageId)\n          ) {\n            return;\n          }\n          connectionSubject.next(event);\n        },\n        complete: () => connectionSubject.complete(),\n        error: (err) => connectionSubject.error(err),\n      });\n    } else {\n      // No active run, complete after historic events\n      connectionSubject.complete();\n    }\n\n    return connectionSubject.asObservable();\n  }\n\n  isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {\n    const store = GLOBAL_STORE.get(request.threadId);\n    return Promise.resolve(store?.isRunning ?? false);\n  }\n\n  stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {\n    const store = GLOBAL_STORE.get(request.threadId);\n    if (!store || !store.isRunning) {\n      return Promise.resolve(false);\n    }\n    if (store.stopRequested) {\n      return Promise.resolve(false);\n    }\n\n    store.stopRequested = true;\n    store.isRunning = false;\n\n    const agent = store.agent;\n    if (!agent) {\n      store.stopRequested = false;\n      store.isRunning = false;\n      return Promise.resolve(false);\n    }\n\n    try {\n      agent.abortRun();\n      return Promise.resolve(true);\n    } catch (error) {\n      console.error(\"Failed to abort agent run\", error);\n      store.stopRequested = false;\n      store.isRunning = true;\n      return Promise.resolve(false);\n    }\n  }\n}\n"],"mappings":"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"}