@introspection-sdk/introspection-browser 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
1
 
2
- > @introspection-sdk/introspection-browser@0.5.1 build /home/runner/work/introspection-js-sdk/introspection-js-sdk/packages/introspection-browser
2
+ > @introspection-sdk/introspection-browser@0.5.3 build /home/runner/work/introspection-js-sdk/introspection-js-sdk/packages/introspection-browser
3
3
  > tsc
4
4
 
package/README.md CHANGED
@@ -30,3 +30,90 @@ client.feedback("thumbs_down", {
30
30
  comments: "Off topic",
31
31
  });
32
32
  ```
33
+
34
+ ## Client-side API (`/api`)
35
+
36
+ The `@introspection-sdk/introspection-browser/api` entry point lets a
37
+ single-page app **create and stream Introspection tasks directly from the
38
+ browser, with no API key in JavaScript**. Authentication is the standard B2B2C
39
+ flow (see the [`sample-auth`](../../examples/apps/sample-auth) example):
40
+
41
+ 1. The app's **own backend ("broker")** mints an Introspection access token —
42
+ via RFC 8693 token-exchange of the partner IdP token, a PKCE
43
+ `authorization_code`, or `client_credentials`. The IdP secret never leaves
44
+ the backend.
45
+ 2. `connect()` redeems that token at the Data Plane
46
+ (`POST /v1/oauth/exchange`) for the HttpOnly `intro_dp_session` cookie.
47
+ 3. Every subsequent call rides that cookie (`credentials: "include"`). When the
48
+ session expires, the client transparently re-mints it once on a `401`.
49
+
50
+ ```typescript
51
+ import { IntrospectionApiClient } from "@introspection-sdk/introspection-browser/api";
52
+
53
+ const client = new IntrospectionApiClient({
54
+ dpUrl: "https://dp.us.introspection.dev",
55
+ projectId: "proj_…",
56
+ // your backend returns a fresh Introspection access token
57
+ getToken: () => fetch("/api/introspection/token").then((r) => r.text()),
58
+ });
59
+
60
+ await client.connect(); // → intro_dp_session cookie
61
+
62
+ const run = await client.tasks.start({
63
+ prompt: "Summarize my latest order",
64
+ agent_name: "support-agent", // or runtime_id: "rt_…"
65
+ identity: { user_id: "u_42" }, // folded into metadata.identity
66
+ visibility: "identity", // sharing scope; defaults by credential
67
+ idle_timeout_seconds: 120, // idle window before the sandbox is torn down
68
+ });
69
+
70
+ for await (const ev of run.stream()) {
71
+ console.log(ev.event, ev.data);
72
+ }
73
+ ```
74
+
75
+ `client.tasks` exposes the full CRUD surface (`create` / `start` / `get` /
76
+ `list` / `update` / `delete` / `archive` / `unarchive`) plus per-run streaming
77
+ (`run.stream()`, `run.text()`, `run.cancel()`).
78
+
79
+ Both `create` and `start` accept two optional task controls:
80
+
81
+ - **`visibility`** (`"identity" | "member" | "project"`) — the task's minimum
82
+ sharing scope. Defaults to `"identity"` when the credential carries an
83
+ identity claim, else `"project"`. The owning `identity_key` is always derived
84
+ from the session JWT, never the request body.
85
+ - **`idle_timeout_seconds`** (`number`) — overrides the interactive idle window
86
+ before the sandbox is torn down. `0` tears it down as soon as it's
87
+ provisioned; omit to use the deployment default. Clamped to the task timeout.
88
+
89
+ ## Files and conversations
90
+
91
+ The same identity session also reaches `/v1/files` and (read-only)
92
+ `/v1/conversations` — no extra credential, just the cookie minted by
93
+ `connect()`:
94
+
95
+ ```typescript
96
+ // Files — CRUD + upload/download, all identity-scoped
97
+ await client.files.upload({ file: new Blob(["hi"]), name: "hi.txt" });
98
+ const page = await client.files.list({ visibility: "identity" });
99
+ const bytes = await client.files.download(page.records[0].id);
100
+
101
+ // Conversations — read-only projection over the telemetry store
102
+ for await (const summary of client.conversations.list()) {
103
+ console.log(summary.conversation_id);
104
+ }
105
+ // Resolve the latest turn of a conversation (Responses-API shape)
106
+ const turn = await client.conversations.retrieve(conversationId);
107
+ console.log(turn?.output_messages);
108
+ ```
109
+
110
+ `client.files` mirrors the Node SDK's `FilesApi` (`list` / `upload` /
111
+ `createText` / `get` / `update` / `delete` / `download` / `downloadStream`,
112
+ plus `files.versions`). `client.conversations` mirrors `ConversationsApi`
113
+ (`list`, `retrieve`, and `conversations.items.list()` / `.get()`). Both `list`
114
+ helpers return a `Paginator` — `await` it for the first page or `for await` it
115
+ to auto-page.
116
+
117
+ > **CORS:** the Data Plane authorizes browser origins against its configured
118
+ > allowlist (`CORS_ORIGINS`). A new SPA origin must be present there for the
119
+ > cross-origin cookie exchange and task/file/conversation calls to succeed.
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Browser-side Introspection API client.
3
+ *
4
+ * Lets a single-page app create and stream Introspection tasks directly
5
+ * from the browser, with no API key in JavaScript. The auth boundary:
6
+ *
7
+ * 1. The SPA's own backend ("broker") mints an Introspection access
8
+ * token — via RFC 8693 token-exchange of the partner IdP token, a
9
+ * PKCE `authorization_code`, or `client_credentials`. The IdP
10
+ * secret never leaves the backend. The SPA fetches that token
11
+ * through the `getToken` callback.
12
+ * 2. `connect()` redeems the token at the DP `POST /v1/oauth/exchange`
13
+ * for the HttpOnly `intro_dp_session` cookie.
14
+ * 3. Every subsequent call rides that cookie (`credentials: "include"`)
15
+ * — `client.tasks.start(...)`, `.get(...)`, run streaming, etc.
16
+ *
17
+ * When the session cookie expires, an in-flight request gets a 401, and
18
+ * the client transparently re-runs `getToken` + the DP exchange once
19
+ * before retrying.
20
+ */
21
+ import { TasksClient } from "./tasks.js";
22
+ import { FilesClient } from "./files.js";
23
+ import { ConversationsClient } from "./conversations.js";
24
+ export interface IntrospectionApiClientOptions {
25
+ /** Data Plane REST base URL (e.g. `https://dp.us.introspection.dev`). */
26
+ dpUrl: string;
27
+ /** Project the session is scoped to. */
28
+ projectId: string;
29
+ /**
30
+ * Returns a fresh Introspection access token from the app's broker
31
+ * (its own backend). Called on `connect()` and again whenever the DP
32
+ * session cookie needs re-minting after a 401.
33
+ */
34
+ getToken: () => string | Promise<string>;
35
+ /** Custom `fetch` (for tests or non-standard runtimes). */
36
+ fetch?: typeof fetch;
37
+ /** Extra headers merged into every DP request. */
38
+ additionalHeaders?: Record<string, string>;
39
+ }
40
+ export declare class IntrospectionApiClient {
41
+ private readonly opts;
42
+ /** `/v1/tasks` operations bound to the DP session cookie. */
43
+ readonly tasks: TasksClient;
44
+ /** `/v1/files` operations bound to the DP session cookie. */
45
+ readonly files: FilesClient;
46
+ /** Read-only `/v1/conversations` projection bound to the session cookie. */
47
+ readonly conversations: ConversationsClient;
48
+ private readonly fetchImpl;
49
+ constructor(opts: IntrospectionApiClientOptions);
50
+ /**
51
+ * Mint a token via `getToken` and redeem it at the DP for the
52
+ * `intro_dp_session` cookie. Call once before issuing task requests.
53
+ */
54
+ connect(): Promise<void>;
55
+ private exchange;
56
+ /** 401 recovery: re-exchange, reporting success so the call can retry. */
57
+ private reexchange;
58
+ }
59
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,6BAA6B;IAC5C,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,qBAAa,sBAAsB;IAUrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAE5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,IAAI,EAAE,6BAA6B;IAkBhE;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAIhB,QAAQ;IAiBtB,0EAA0E;YAC5D,UAAU;CAQzB"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Browser-side Introspection API client.
3
+ *
4
+ * Lets a single-page app create and stream Introspection tasks directly
5
+ * from the browser, with no API key in JavaScript. The auth boundary:
6
+ *
7
+ * 1. The SPA's own backend ("broker") mints an Introspection access
8
+ * token — via RFC 8693 token-exchange of the partner IdP token, a
9
+ * PKCE `authorization_code`, or `client_credentials`. The IdP
10
+ * secret never leaves the backend. The SPA fetches that token
11
+ * through the `getToken` callback.
12
+ * 2. `connect()` redeems the token at the DP `POST /v1/oauth/exchange`
13
+ * for the HttpOnly `intro_dp_session` cookie.
14
+ * 3. Every subsequent call rides that cookie (`credentials: "include"`)
15
+ * — `client.tasks.start(...)`, `.get(...)`, run streaming, etc.
16
+ *
17
+ * When the session cookie expires, an in-flight request gets a 401, and
18
+ * the client transparently re-runs `getToken` + the DP exchange once
19
+ * before retrying.
20
+ */
21
+ import { BrowserHttpClient, stripTrailingSlash, toApiError } from "./http.js";
22
+ import { TasksClient } from "./tasks.js";
23
+ import { FilesClient } from "./files.js";
24
+ import { ConversationsClient } from "./conversations.js";
25
+ export class IntrospectionApiClient {
26
+ opts;
27
+ /** `/v1/tasks` operations bound to the DP session cookie. */
28
+ tasks;
29
+ /** `/v1/files` operations bound to the DP session cookie. */
30
+ files;
31
+ /** Read-only `/v1/conversations` projection bound to the session cookie. */
32
+ conversations;
33
+ fetchImpl;
34
+ constructor(opts) {
35
+ this.opts = opts;
36
+ this.fetchImpl = opts.fetch ?? globalThis.fetch;
37
+ if (!this.fetchImpl) {
38
+ throw new Error("global fetch is unavailable; pass `fetch` or run in a modern browser");
39
+ }
40
+ const http = new BrowserHttpClient({
41
+ apiUrl: opts.dpUrl,
42
+ additionalHeaders: opts.additionalHeaders,
43
+ fetch: opts.fetch,
44
+ onUnauthorized: () => this.reexchange(),
45
+ });
46
+ this.tasks = new TasksClient(http);
47
+ this.files = new FilesClient(http);
48
+ this.conversations = new ConversationsClient(http);
49
+ }
50
+ /**
51
+ * Mint a token via `getToken` and redeem it at the DP for the
52
+ * `intro_dp_session` cookie. Call once before issuing task requests.
53
+ */
54
+ async connect() {
55
+ await this.exchange();
56
+ }
57
+ async exchange() {
58
+ const token = await this.opts.getToken();
59
+ const res = await this.fetchImpl(`${stripTrailingSlash(this.opts.dpUrl)}/v1/oauth/exchange`, {
60
+ method: "POST",
61
+ headers: {
62
+ "Content-Type": "application/json",
63
+ ...(this.opts.additionalHeaders ?? {}),
64
+ },
65
+ body: JSON.stringify({ token, project_id: this.opts.projectId }),
66
+ credentials: "include",
67
+ });
68
+ if (!res.ok)
69
+ throw await toApiError(res);
70
+ }
71
+ /** 401 recovery: re-exchange, reporting success so the call can retry. */
72
+ async reexchange() {
73
+ try {
74
+ await this.exchange();
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ }
82
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAmBzD,MAAM,OAAO,sBAAsB;IAUJ;IAT7B,6DAA6D;IACpD,KAAK,CAAc;IAC5B,6DAA6D;IACpD,KAAK,CAAc;IAC5B,4EAA4E;IACnE,aAAa,CAAsB;IAE3B,SAAS,CAAe;IAEzC,YAA6B,IAAmC;QAAnC,SAAI,GAAJ,IAAI,CAA+B;QAC9D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,iBAAiB,CAAC;YACjC,MAAM,EAAE,IAAI,CAAC,KAAK;YAClB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,aAAa,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAC9B,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAC1D;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC;aACvC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAChE,WAAW,EAAE,SAAS;SACvB,CACF,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,0EAA0E;IAClE,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Cookie-authenticated, read-only Conversations client for the browser
3
+ * (`/v1/conversations`).
4
+ *
5
+ * Mirrors the Node SDK's runner-bound `ConversationsApi`, but rides the
6
+ * DP `intro_dp_session` cookie via {@link BrowserHttpClient} instead of a
7
+ * bearer token — so a single-page app reads conversation history with the
8
+ * same identity session it uses for tasks and files. Conversations are a
9
+ * projection over the immutable telemetry store: list summaries, walk a
10
+ * conversation's items, or `retrieve()` the resolved state of one turn.
11
+ */
12
+ import type { ConversationItem, ConversationItemInclude, ConversationItemList, ConversationItemListParams, ConversationListParams, ConversationResponse, ConversationSummary } from "@introspection-sdk/types";
13
+ import { Paginator } from "@introspection-sdk/http";
14
+ import { BrowserHttpClient } from "./http.js";
15
+ /**
16
+ * Items of a conversation (`/v1/conversations/{id}/items`). Read-only.
17
+ *
18
+ * Paging is OpenAI-style underneath: the envelope has NO `next` token —
19
+ * `list()` drives `after` = the previous page's `last_id` while
20
+ * `has_more` is true.
21
+ */
22
+ export declare class ConversationItemsClient {
23
+ private readonly http;
24
+ constructor(http: BrowserHttpClient);
25
+ /**
26
+ * List items of a conversation. `await` the result for the first page
27
+ * (an OpenAI-style {@link ConversationItemList} envelope), or
28
+ * `for await` it to stream every item across pages (fetched lazily —
29
+ * `limit` sets the page size, `after` the starting cursor; stop early to
30
+ * stop fetching). Pass `order: "asc"` to walk the transcript from the
31
+ * start.
32
+ *
33
+ * Items carry the turn-local delta in `input_messages` — only the
34
+ * messages new to that turn. Use `get()` for the full input history.
35
+ */
36
+ list(conversationId: string, params?: ConversationItemListParams): Paginator<ConversationItem, ConversationItemList>;
37
+ /**
38
+ * Fetch a single conversation item. Unlike the list route, the
39
+ * detail's `input_messages` is the FULL input history for that span.
40
+ */
41
+ get(conversationId: string, itemId: string, params?: {
42
+ include?: ConversationItemInclude[];
43
+ }): Promise<ConversationItem>;
44
+ }
45
+ /**
46
+ * Read-only Conversations client (`/v1/conversations`).
47
+ *
48
+ * Both `list()` and `items.list()` are auto-paging, but they drive
49
+ * different wire protocols underneath: `list()` walks the standard
50
+ * Introspection cursor envelope's opaque `next` token, while
51
+ * `items.list()` walks an OpenAI-style envelope via `after` = the
52
+ * previous page's `last_id` while `has_more` is true.
53
+ */
54
+ export declare class ConversationsClient {
55
+ private readonly http;
56
+ /** Items of a conversation — `conversations.items.list(...)` etc. */
57
+ readonly items: ConversationItemsClient;
58
+ constructor(http: BrowserHttpClient);
59
+ /**
60
+ * List conversation summaries matching `params`. `await` the result for
61
+ * the first page, or `for await` it to stream every summary across
62
+ * pages (fetched lazily — `limit` sets the page size, `next` the
63
+ * starting cursor; stop early to stop fetching).
64
+ */
65
+ list(params?: ConversationListParams): Paginator<ConversationSummary>;
66
+ /**
67
+ * Responses-API-style retrieve: load the state of a conversation as of
68
+ * one item — the full input history, output, system instructions, and
69
+ * tool definitions of that turn.
70
+ *
71
+ * When `itemId` is omitted, the latest LLM turn is used: the first
72
+ * item (in descending order) whose `node_type` is `"assistant"` or
73
+ * whose `operation_name` is `"chat"`, falling back to the first item
74
+ * with a non-null `output_message`. Returns `null` when the
75
+ * conversation has no items.
76
+ *
77
+ * For the full per-turn transcript instead, iterate
78
+ * `items.list(conversationId, { order: "asc" })`.
79
+ */
80
+ retrieve(conversationId: string, itemId?: string): Promise<ConversationResponse | null>;
81
+ /** Scan items in descending order for the most recent LLM turn. */
82
+ private findLatestTurnId;
83
+ }
84
+ //# sourceMappingURL=conversations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/api/conversations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EAIpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAS9C;;;;;;GAMG;AACH,qBAAa,uBAAuB;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;IAEpD;;;;;;;;;;OAUG;IACH,IAAI,CACF,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,0BAA0B,GAClC,SAAS,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;IAiBpD;;;OAGG;IACH,GAAG,CACD,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAA;KAAE,GAC/C,OAAO,CAAC,gBAAgB,CAAC;CAO7B;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAIlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;gBAEX,IAAI,EAAE,iBAAiB;IAIpD;;;;;OAKG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC,mBAAmB,CAAC;IAYrE;;;;;;;;;;;;;OAaG;IACG,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA6BvC,mEAAmE;YACrD,gBAAgB;CAc/B"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Cookie-authenticated, read-only Conversations client for the browser
3
+ * (`/v1/conversations`).
4
+ *
5
+ * Mirrors the Node SDK's runner-bound `ConversationsApi`, but rides the
6
+ * DP `intro_dp_session` cookie via {@link BrowserHttpClient} instead of a
7
+ * bearer token — so a single-page app reads conversation history with the
8
+ * same identity session it uses for tasks and files. Conversations are a
9
+ * projection over the immutable telemetry store: list summaries, walk a
10
+ * conversation's items, or `retrieve()` the resolved state of one turn.
11
+ */
12
+ import { Paginator, cursorPaginate } from "@introspection-sdk/http";
13
+ /** Includes requested when building a {@link ConversationResponse}. */
14
+ const RESPONSE_INCLUDES = [
15
+ "gen_ai.input.messages",
16
+ "gen_ai.system_instructions",
17
+ "gen_ai.tool.definitions",
18
+ ];
19
+ /**
20
+ * Items of a conversation (`/v1/conversations/{id}/items`). Read-only.
21
+ *
22
+ * Paging is OpenAI-style underneath: the envelope has NO `next` token —
23
+ * `list()` drives `after` = the previous page's `last_id` while
24
+ * `has_more` is true.
25
+ */
26
+ export class ConversationItemsClient {
27
+ http;
28
+ constructor(http) {
29
+ this.http = http;
30
+ }
31
+ /**
32
+ * List items of a conversation. `await` the result for the first page
33
+ * (an OpenAI-style {@link ConversationItemList} envelope), or
34
+ * `for await` it to stream every item across pages (fetched lazily —
35
+ * `limit` sets the page size, `after` the starting cursor; stop early to
36
+ * stop fetching). Pass `order: "asc"` to walk the transcript from the
37
+ * start.
38
+ *
39
+ * Items carry the turn-local delta in `input_messages` — only the
40
+ * messages new to that turn. Use `get()` for the full input history.
41
+ */
42
+ list(conversationId, params) {
43
+ return new Paginator({
44
+ fetch: (after) => this.http.request({
45
+ method: "GET",
46
+ path: `/v1/conversations/${encodeURIComponent(conversationId)}/items`,
47
+ query: { ...params, after },
48
+ }),
49
+ items: (page) => page.data,
50
+ next: (page) => page.has_more && page.last_id !== null ? page.last_id : undefined,
51
+ }, params?.after);
52
+ }
53
+ /**
54
+ * Fetch a single conversation item. Unlike the list route, the
55
+ * detail's `input_messages` is the FULL input history for that span.
56
+ */
57
+ get(conversationId, itemId, params) {
58
+ return this.http.request({
59
+ method: "GET",
60
+ path: `/v1/conversations/${encodeURIComponent(conversationId)}/items/${encodeURIComponent(itemId)}`,
61
+ query: params,
62
+ });
63
+ }
64
+ }
65
+ /**
66
+ * Read-only Conversations client (`/v1/conversations`).
67
+ *
68
+ * Both `list()` and `items.list()` are auto-paging, but they drive
69
+ * different wire protocols underneath: `list()` walks the standard
70
+ * Introspection cursor envelope's opaque `next` token, while
71
+ * `items.list()` walks an OpenAI-style envelope via `after` = the
72
+ * previous page's `last_id` while `has_more` is true.
73
+ */
74
+ export class ConversationsClient {
75
+ http;
76
+ /** Items of a conversation — `conversations.items.list(...)` etc. */
77
+ items;
78
+ constructor(http) {
79
+ this.http = http;
80
+ this.items = new ConversationItemsClient(http);
81
+ }
82
+ /**
83
+ * List conversation summaries matching `params`. `await` the result for
84
+ * the first page, or `for await` it to stream every summary across
85
+ * pages (fetched lazily — `limit` sets the page size, `next` the
86
+ * starting cursor; stop early to stop fetching).
87
+ */
88
+ list(params) {
89
+ return cursorPaginate((next) => this.http.request({
90
+ method: "GET",
91
+ path: "/v1/conversations",
92
+ query: { ...params, next },
93
+ }), params?.next);
94
+ }
95
+ /**
96
+ * Responses-API-style retrieve: load the state of a conversation as of
97
+ * one item — the full input history, output, system instructions, and
98
+ * tool definitions of that turn.
99
+ *
100
+ * When `itemId` is omitted, the latest LLM turn is used: the first
101
+ * item (in descending order) whose `node_type` is `"assistant"` or
102
+ * whose `operation_name` is `"chat"`, falling back to the first item
103
+ * with a non-null `output_message`. Returns `null` when the
104
+ * conversation has no items.
105
+ *
106
+ * For the full per-turn transcript instead, iterate
107
+ * `items.list(conversationId, { order: "asc" })`.
108
+ */
109
+ async retrieve(conversationId, itemId) {
110
+ const targetId = itemId ?? (await this.findLatestTurnId(conversationId));
111
+ if (targetId === null)
112
+ return null;
113
+ const detail = await this.items.get(conversationId, targetId, {
114
+ include: RESPONSE_INCLUDES,
115
+ });
116
+ const outputMessages = detail.gen_ai_output_messages ??
117
+ (detail.output_message ? [detail.output_message] : []);
118
+ return {
119
+ conversation_id: conversationId,
120
+ response_id: detail.response_id ?? null,
121
+ item_id: detail.id,
122
+ created_at: detail.created_at,
123
+ model: detail.model_name ??
124
+ detail.response_model ??
125
+ detail.request_model ??
126
+ null,
127
+ provider_name: detail.provider_name ?? null,
128
+ // The single-item route returns the FULL input history here.
129
+ input_messages: normalizeMessages(detail.input_messages),
130
+ output_messages: normalizeMessages(outputMessages),
131
+ system_instructions: detail.system_instructions ?? null,
132
+ tool_definitions: detail.tool_definitions ?? null,
133
+ };
134
+ }
135
+ /** Scan items in descending order for the most recent LLM turn. */
136
+ async findLatestTurnId(conversationId) {
137
+ let fallback = null;
138
+ for await (const item of this.items.list(conversationId, {
139
+ order: "desc",
140
+ })) {
141
+ if (item.node_type === "assistant" || item.operation_name === "chat") {
142
+ return item.id;
143
+ }
144
+ if (fallback === null && item.output_message != null)
145
+ fallback = item;
146
+ }
147
+ return fallback?.id ?? null;
148
+ }
149
+ }
150
+ /**
151
+ * Defensive normalization for {@link ConversationsClient.retrieve} only:
152
+ * older DP deployments emitted `tool_call_response` parts with a legacy
153
+ * `result` key instead of the semconv `response` key. Map it across so
154
+ * replayed history is always semconv-shaped.
155
+ */
156
+ function normalizeMessages(messages) {
157
+ return messages.map((message) => ({
158
+ ...message,
159
+ parts: message.parts.map(normalizePart),
160
+ }));
161
+ }
162
+ function normalizePart(part) {
163
+ if (part.type !== "tool_call_response")
164
+ return part;
165
+ const legacy = part;
166
+ if (legacy.response !== undefined || legacy.result === undefined) {
167
+ return part;
168
+ }
169
+ const { result, ...rest } = legacy;
170
+ return { ...rest, response: result };
171
+ }
172
+ //# sourceMappingURL=conversations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/api/conversations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cookie-authenticated Files client for the browser (`/v1/files`).
3
+ *
4
+ * Mirrors the Node SDK's runner-bound `FilesApi`, but rides the DP
5
+ * `intro_dp_session` cookie via {@link BrowserHttpClient} instead of a
6
+ * bearer token — so a single-page app reads and writes files with the
7
+ * same identity session it uses for tasks and conversations. The DP
8
+ * derives the owning `identity_key` from the session JWT; per-identity
9
+ * file visibility is enforced server-side.
10
+ */
11
+ import type { File as FileResource, FileCreateOptions, FileCreateTextParams, FileListParams, FileType, FileUpdateParams, ListParams } from "@introspection-sdk/types";
12
+ import { Paginator } from "@introspection-sdk/http";
13
+ import { BrowserHttpClient } from "./http.js";
14
+ export type FileUploadBody = {
15
+ file: Blob;
16
+ name?: string;
17
+ file_type?: FileType;
18
+ } | {
19
+ file: Uint8Array;
20
+ name: string;
21
+ file_type?: FileType;
22
+ contentType?: string;
23
+ };
24
+ /** Versions of a file (`/v1/files/{id}/versions`). */
25
+ export declare class FileVersionsClient {
26
+ private readonly http;
27
+ constructor(http: BrowserHttpClient);
28
+ /**
29
+ * List versions of a file. `await` the result for the first page, or
30
+ * `for await` it to stream every version across pages (fetched lazily;
31
+ * stop early to stop fetching).
32
+ */
33
+ list(fileId: string, params?: ListParams): Paginator<FileResource>;
34
+ get(fileId: string, versionId: string): Promise<FileResource>;
35
+ create(fileId: string, body: FileUploadBody, options?: FileCreateOptions): Promise<FileResource>;
36
+ }
37
+ /**
38
+ * Cookie-authenticated `/v1/files` client. Mirrors the Node SDK's
39
+ * `FilesApi` shape but is bound to a DP session cookie rather than a
40
+ * bearer token.
41
+ */
42
+ export declare class FilesClient {
43
+ private readonly http;
44
+ readonly versions: FileVersionsClient;
45
+ constructor(http: BrowserHttpClient);
46
+ /**
47
+ * List files matching `params`. `await` the result for the first page,
48
+ * or `for await` it to stream every file across pages (fetched lazily —
49
+ * `limit` sets the page size, `next` the starting cursor; stop early to
50
+ * stop fetching).
51
+ */
52
+ list(params?: FileListParams): Paginator<FileResource>;
53
+ upload(body: FileUploadBody, options?: FileCreateOptions): Promise<FileResource>;
54
+ createText(body: FileCreateTextParams, options?: FileCreateOptions): Promise<FileResource>;
55
+ get(fileId: string): Promise<FileResource>;
56
+ update(fileId: string, body: FileUpdateParams): Promise<FileResource>;
57
+ delete(fileId: string): Promise<void>;
58
+ download(fileId: string): Promise<Uint8Array>;
59
+ downloadStream(fileId: string): Promise<ReadableStream<Uint8Array>>;
60
+ }
61
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/api/files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,IAAI,IAAI,YAAY,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,QAAQ,CAAA;CAAE,GACnD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,sDAAsD;AACtD,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;IAEpD;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,YAAY,CAAC;IAYlE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAO7D,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC;CAQzB;AAED;;;;GAIG;AACH,qBAAa,WAAW;IAGV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;gBAET,IAAI,EAAE,iBAAiB;IAIpD;;;;;OAKG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC,YAAY,CAAC;IAYtD,MAAM,CACJ,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC;IASxB,UAAU,CACR,IAAI,EAAE,oBAAoB,EAC1B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC;IAUxB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAO1C,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAQrE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQ7C,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;CAOpE"}