/ src / assistant / sessionHistory.ts
sessionHistory.ts
 1  import axios from 'axios'
 2  import { getOauthConfig } from '../constants/oauth.js'
 3  import type { SDKMessage } from '../entrypoints/agentSdkTypes.js'
 4  import { logForDebugging } from '../utils/debug.js'
 5  import { getOAuthHeaders, prepareApiRequest } from '../utils/teleport/api.js'
 6  
 7  export const HISTORY_PAGE_SIZE = 100
 8  
 9  export type HistoryPage = {
10    /** Chronological order within the page. */
11    events: SDKMessage[]
12    /** Oldest event ID in this page → before_id cursor for next-older page. */
13    firstId: string | null
14    /** true = older events exist. */
15    hasMore: boolean
16  }
17  
18  type SessionEventsResponse = {
19    data: SDKMessage[]
20    has_more: boolean
21    first_id: string | null
22    last_id: string | null
23  }
24  
25  export type HistoryAuthCtx = {
26    baseUrl: string
27    headers: Record<string, string>
28  }
29  
30  /** Prepare auth + headers + base URL once, reuse across pages. */
31  export async function createHistoryAuthCtx(
32    sessionId: string,
33  ): Promise<HistoryAuthCtx> {
34    const { accessToken, orgUUID } = await prepareApiRequest()
35    return {
36      baseUrl: `${getOauthConfig().BASE_API_URL}/v1/sessions/${sessionId}/events`,
37      headers: {
38        ...getOAuthHeaders(accessToken),
39        'anthropic-beta': 'ccr-byoc-2025-07-29',
40        'x-organization-uuid': orgUUID,
41      },
42    }
43  }
44  
45  async function fetchPage(
46    ctx: HistoryAuthCtx,
47    params: Record<string, string | number | boolean>,
48    label: string,
49  ): Promise<HistoryPage | null> {
50    const resp = await axios
51      .get<SessionEventsResponse>(ctx.baseUrl, {
52        headers: ctx.headers,
53        params,
54        timeout: 15000,
55        validateStatus: () => true,
56      })
57      .catch(() => null)
58    if (!resp || resp.status !== 200) {
59      logForDebugging(`[${label}] HTTP ${resp?.status ?? 'error'}`)
60      return null
61    }
62    return {
63      events: Array.isArray(resp.data.data) ? resp.data.data : [],
64      firstId: resp.data.first_id,
65      hasMore: resp.data.has_more,
66    }
67  }
68  
69  /**
70   * Newest page: last `limit` events, chronological, via anchor_to_latest.
71   * has_more=true means older events exist.
72   */
73  export async function fetchLatestEvents(
74    ctx: HistoryAuthCtx,
75    limit = HISTORY_PAGE_SIZE,
76  ): Promise<HistoryPage | null> {
77    return fetchPage(ctx, { limit, anchor_to_latest: true }, 'fetchLatestEvents')
78  }
79  
80  /** Older page: events immediately before `beforeId` cursor. */
81  export async function fetchOlderEvents(
82    ctx: HistoryAuthCtx,
83    beforeId: string,
84    limit = HISTORY_PAGE_SIZE,
85  ): Promise<HistoryPage | null> {
86    return fetchPage(ctx, { limit, before_id: beforeId }, 'fetchOlderEvents')
87  }