{"version":3,"file":"in-memory.mjs","names":[],"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  Message,\n  RunStartedEvent,\n  StateSnapshotEvent,\n  compactEvents,\n} from \"@ag-ui/client\";\nimport { finalizeRunEvents } from \"@copilotkit/shared\";\n\ninterface HistoricRun {\n  threadId: string;\n  runId: string;\n  /** ID of the agent that executed this run. */\n  agentId: string;\n  parentRunId: string | null;\n  events: BaseEvent[];\n  /**\n   * Snapshot of all messages (input + generated) at the end of this run.\n   * Used by the local thread-messages fallback endpoint.\n   */\n  messages: Message[];\n  createdAt: number;\n}\n\n/**\n * Lightweight thread summary returned by {@link InMemoryAgentRunner.listThreads}.\n * Shape matches the Intelligence platform's ThreadRecord so the same HTTP\n * response envelope can be used for both backends.\n */\nexport interface InMemoryThread {\n  id: string;\n  name: string | null;\n  agentId: string;\n  organizationId: \"\"; // always empty in in-memory mode\n  createdById: \"\"; // always empty in in-memory mode\n  archived: false; // always false in in-memory mode\n  createdAt: string;\n  updatedAt: string;\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\nconst GLOBAL_STORE = new Map<string, InMemoryEventStore>();\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            agentId: request.agent.agentId ?? \"default\",\n            parentRunId,\n            events: compactedEvents,\n            // Snapshot all messages (input + generated) for the thread-messages endpoint\n            messages: Array.isArray(request.agent.messages)\n              ? [...request.agent.messages]\n              : [],\n            createdAt: Date.now(),\n          });\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            agentId: request.agent.agentId ?? \"default\",\n            parentRunId,\n            events: compactedEvents,\n            messages: Array.isArray(request.agent.messages)\n              ? [...request.agent.messages]\n              : [],\n            createdAt: Date.now(),\n          });\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  /**\n   * Returns a summary of every thread that has been run through this runner.\n   *\n   * This powers the local-dev fallback for `GET /threads` when the Intelligence\n   * platform is not configured. Each entry mirrors the shape of a platform\n   * `ThreadRecord` so the HTTP handler can use the same response envelope.\n   */\n  listThreads(): InMemoryThread[] {\n    const threads: InMemoryThread[] = [];\n    for (const [threadId, store] of GLOBAL_STORE) {\n      if (store.historicRuns.length === 0) continue;\n      const firstRun = store.historicRuns[0]!;\n      const lastRun = store.historicRuns[store.historicRuns.length - 1]!;\n      threads.push({\n        id: threadId,\n        name: null,\n        agentId: lastRun.agentId,\n        organizationId: \"\",\n        createdById: \"\",\n        archived: false,\n        createdAt: new Date(firstRun.createdAt).toISOString(),\n        updatedAt: new Date(lastRun.createdAt).toISOString(),\n      });\n    }\n    // Most recently updated first\n    return threads.sort(\n      (a, b) =>\n        new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),\n    );\n  }\n\n  /**\n   * Returns all messages for a thread, using the snapshot captured at the end\n   * of the most recent run.\n   *\n   * This powers the local-dev fallback for `GET /threads/:threadId/messages`\n   * when the Intelligence platform is not configured. The returned `Message[]`\n   * objects come directly from the ag-ui agent, so their shape is compatible\n   * with the Intelligence platform's `ThreadMessage` type.\n   */\n  getThreadMessages(threadId: string): Message[] {\n    const store = GLOBAL_STORE.get(threadId);\n    if (!store || store.historicRuns.length === 0) return [];\n    // The last run's snapshot has the complete conversation history\n    return store.historicRuns[store.historicRuns.length - 1]!.messages;\n  }\n\n  /**\n   * Returns all AG-UI events for a thread, compacted across historic runs.\n   *\n   * Powers the local-dev fallback for `GET /threads/:threadId/events` when the\n   * Intelligence platform is not configured. The compaction logic matches\n   * the connection-replay path in {@link connect}, so the stream a\n   * late-joining inspector sees matches what this method returns.\n   */\n  getThreadEvents(threadId: string): BaseEvent[] {\n    const store = GLOBAL_STORE.get(threadId);\n    if (!store || store.historicRuns.length === 0) return [];\n    const all: BaseEvent[] = [];\n    for (const run of store.historicRuns) all.push(...run.events);\n    return compactEvents(all);\n  }\n\n  /**\n   * Returns the agent state snapshot for a thread.\n   *\n   * Derived from the last `STATE_SNAPSHOT` in the compacted event stream. The\n   * AG-UI `compactEvents` helper consolidates STATE_DELTA events and produces\n   * a single trailing STATE_SNAPSHOT when state changes exist, so this is a\n   * faithful view of state at the end of the most recent run.\n   *\n   * Returns `null` when the thread has never emitted a STATE_SNAPSHOT.\n   */\n  getThreadState(threadId: string): Record<string, unknown> | null {\n    const events = this.getThreadEvents(threadId);\n    // Walk backwards — the last snapshot wins.\n    for (let i = events.length - 1; i >= 0; i--) {\n      const event = events[i]!;\n      if (event.type === EventType.STATE_SNAPSHOT) {\n        const snapshot = (event as StateSnapshotEvent).snapshot;\n        if (snapshot && typeof snapshot === \"object\") {\n          return snapshot as Record<string, unknown>;\n        }\n        return null;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Clears all in-memory thread history.\n   *\n   * Powers the local-dev fallback for `POST /threads/clear`, letting consumers\n   * (e.g. the demo's Clear button) reset to an empty thread list without\n   * restarting the runtime. Intentionally not exposed on the Intelligence\n   * platform path: there, thread history lives in a real database and must\n   * not be wiped this way.\n   */\n  clearThreads(): void {\n    GLOBAL_STORE.clear();\n  }\n}\n"],"mappings":"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"}