@axiom-lattice/client-sdk 5.0.1 → 7.0.0

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.
Files changed (70) hide show
  1. package/dist/__tests__/commands.test.d.ts +2 -0
  2. package/dist/__tests__/commands.test.d.ts.map +1 -0
  3. package/dist/__tests__/commands.test.js +96 -0
  4. package/dist/__tests__/commands.test.js.map +1 -0
  5. package/dist/__tests__/crons.test.d.ts +2 -0
  6. package/dist/__tests__/crons.test.d.ts.map +1 -0
  7. package/dist/__tests__/crons.test.js +103 -0
  8. package/dist/__tests__/crons.test.js.map +1 -0
  9. package/dist/__tests__/info.test.d.ts +2 -0
  10. package/dist/__tests__/info.test.d.ts.map +1 -0
  11. package/dist/__tests__/info.test.js +109 -0
  12. package/dist/__tests__/info.test.js.map +1 -0
  13. package/dist/__tests__/mcpApps.test.js +16 -0
  14. package/dist/__tests__/mcpApps.test.js.map +1 -1
  15. package/dist/__tests__/project-rooms.test.js +12 -0
  16. package/dist/__tests__/project-rooms.test.js.map +1 -1
  17. package/dist/__tests__/resume-last-event-id.test.d.ts +2 -0
  18. package/dist/__tests__/resume-last-event-id.test.d.ts.map +1 -0
  19. package/dist/__tests__/resume-last-event-id.test.js +111 -0
  20. package/dist/__tests__/resume-last-event-id.test.js.map +1 -0
  21. package/dist/__tests__/resume-stream-http-error.test.d.ts +2 -0
  22. package/dist/__tests__/resume-stream-http-error.test.d.ts.map +1 -0
  23. package/dist/__tests__/resume-stream-http-error.test.js +45 -0
  24. package/dist/__tests__/resume-stream-http-error.test.js.map +1 -0
  25. package/dist/__tests__/runs-task-queue.test.d.ts +2 -0
  26. package/dist/__tests__/runs-task-queue.test.d.ts.map +1 -0
  27. package/dist/__tests__/runs-task-queue.test.js +159 -0
  28. package/dist/__tests__/runs-task-queue.test.js.map +1 -0
  29. package/dist/__tests__/runs.test.d.ts +2 -0
  30. package/dist/__tests__/runs.test.d.ts.map +1 -0
  31. package/dist/__tests__/runs.test.js +135 -0
  32. package/dist/__tests__/runs.test.js.map +1 -0
  33. package/dist/__tests__/runtime-client.test.js +29 -0
  34. package/dist/__tests__/runtime-client.test.js.map +1 -1
  35. package/dist/__tests__/store.test.d.ts +2 -0
  36. package/dist/__tests__/store.test.d.ts.map +1 -0
  37. package/dist/__tests__/store.test.js +100 -0
  38. package/dist/__tests__/store.test.js.map +1 -0
  39. package/dist/__tests__/thread-event-stream.test.d.ts +2 -0
  40. package/dist/__tests__/thread-event-stream.test.d.ts.map +1 -0
  41. package/dist/__tests__/thread-event-stream.test.js +109 -0
  42. package/dist/__tests__/thread-event-stream.test.js.map +1 -0
  43. package/dist/__tests__/thread-maintenance.test.d.ts +2 -0
  44. package/dist/__tests__/thread-maintenance.test.d.ts.map +1 -0
  45. package/dist/__tests__/thread-maintenance.test.js +98 -0
  46. package/dist/__tests__/thread-maintenance.test.js.map +1 -0
  47. package/dist/abstract-client.d.ts +234 -1
  48. package/dist/abstract-client.d.ts.map +1 -1
  49. package/dist/abstract-client.js +406 -1
  50. package/dist/abstract-client.js.map +1 -1
  51. package/dist/client.d.ts +9 -0
  52. package/dist/client.d.ts.map +1 -1
  53. package/dist/client.js +35 -5
  54. package/dist/client.js.map +1 -1
  55. package/dist/index.d.ts +600 -3
  56. package/dist/index.js +622 -121
  57. package/dist/index.js.map +1 -1
  58. package/dist/index.mjs +622 -121
  59. package/dist/index.mjs.map +1 -1
  60. package/dist/project-rooms.d.ts +3 -0
  61. package/dist/project-rooms.d.ts.map +1 -1
  62. package/dist/project-rooms.js +1 -0
  63. package/dist/project-rooms.js.map +1 -1
  64. package/dist/runtime-client.d.ts.map +1 -1
  65. package/dist/runtime-client.js +2 -6
  66. package/dist/runtime-client.js.map +1 -1
  67. package/dist/types.d.ts +354 -2
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/types.js.map +1 -1
  70. package/package.json +9 -2
package/dist/index.mjs CHANGED
@@ -1857,6 +1857,116 @@ var ScheduledTaskStatus = /* @__PURE__ */ ((ScheduledTaskStatus2) => {
1857
1857
 
1858
1858
  // src/abstract-client.ts
1859
1859
  import { threadAffinityHeaders } from "@axiom-lattice/protocols";
1860
+
1861
+ // src/sse-parser.ts
1862
+ var SseParseError = class extends Error {
1863
+ constructor(message) {
1864
+ super(message);
1865
+ this.code = "INVALID_EVENT";
1866
+ this.name = "SseParseError";
1867
+ }
1868
+ };
1869
+ async function* parseSseBody(body, options = {}) {
1870
+ const reader = body.getReader();
1871
+ const decoder = new TextDecoder();
1872
+ let buffer = "";
1873
+ let event = "";
1874
+ let id;
1875
+ let retry;
1876
+ let data = [];
1877
+ const dispatch = () => {
1878
+ if (data.length === 0) {
1879
+ event = "";
1880
+ id = void 0;
1881
+ retry = void 0;
1882
+ return void 0;
1883
+ }
1884
+ let parsed;
1885
+ try {
1886
+ parsed = JSON.parse(data.join("\n"));
1887
+ } catch {
1888
+ throw new SseParseError("Invalid SSE JSON");
1889
+ }
1890
+ if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
1891
+ throw new SseParseError("SSE data must be an object");
1892
+ const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
1893
+ event = "";
1894
+ id = void 0;
1895
+ retry = void 0;
1896
+ data = [];
1897
+ return result;
1898
+ };
1899
+ const processLine = (raw) => {
1900
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
1901
+ if (line === "")
1902
+ return dispatch();
1903
+ if (line.startsWith(":"))
1904
+ return void 0;
1905
+ const separator = line.indexOf(":");
1906
+ const field = separator < 0 ? line : line.slice(0, separator);
1907
+ let value = separator < 0 ? "" : line.slice(separator + 1);
1908
+ if (value.startsWith(" "))
1909
+ value = value.slice(1);
1910
+ if (field === "event")
1911
+ event = value;
1912
+ else if (field === "data")
1913
+ data.push(value);
1914
+ else if (field === "id")
1915
+ id = value;
1916
+ else if (field === "retry") {
1917
+ const parsed = Number(value);
1918
+ if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
1919
+ throw new SseParseError("Invalid SSE retry");
1920
+ retry = parsed;
1921
+ }
1922
+ return void 0;
1923
+ };
1924
+ try {
1925
+ while (true) {
1926
+ const chunk = await reader.read();
1927
+ if (chunk.done) {
1928
+ buffer += decoder.decode();
1929
+ break;
1930
+ }
1931
+ buffer += decoder.decode(chunk.value, { stream: true });
1932
+ let index = findLineBreak(buffer);
1933
+ while (index >= 0) {
1934
+ if (buffer[index] === "\r" && index === buffer.length - 1)
1935
+ break;
1936
+ const frame2 = processLine(buffer.slice(0, index));
1937
+ buffer = buffer.slice(index + lineBreakLength(buffer, index));
1938
+ if (frame2)
1939
+ yield frame2;
1940
+ index = findLineBreak(buffer);
1941
+ }
1942
+ }
1943
+ if (buffer) {
1944
+ const frame2 = processLine(buffer);
1945
+ if (frame2)
1946
+ yield frame2;
1947
+ }
1948
+ const frame = processLine("");
1949
+ if (frame)
1950
+ yield frame;
1951
+ } finally {
1952
+ await reader.cancel().catch(() => void 0);
1953
+ reader.releaseLock();
1954
+ }
1955
+ }
1956
+ function findLineBreak(value) {
1957
+ const lf = value.indexOf("\n");
1958
+ const cr = value.indexOf("\r");
1959
+ if (lf < 0)
1960
+ return cr;
1961
+ if (cr < 0)
1962
+ return lf;
1963
+ return Math.min(lf, cr);
1964
+ }
1965
+ function lineBreakLength(value, index) {
1966
+ return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
1967
+ }
1968
+
1969
+ // src/abstract-client.ts
1860
1970
  var AbstractClient = class {
1861
1971
  /**
1862
1972
  * Creates a new AbstractClient instance
@@ -1924,7 +2034,7 @@ var AbstractClient = class {
1924
2034
  if (!response.success) {
1925
2035
  throw new Error(response.error || "Failed to enqueue message");
1926
2036
  }
1927
- return { messageId: response.messageId, queued: response.queued };
2037
+ return { messageId: response.messageId, queued: response.queued, ...response.runId ? { runId: response.runId } : {} };
1928
2038
  },
1929
2039
  /**
1930
2040
  * Sends a message to a thread and streams the response
@@ -2828,6 +2938,300 @@ var AbstractClient = class {
2828
2938
  return response.success;
2829
2939
  }
2830
2940
  };
2941
+ /**
2942
+ * Agent cron resources (`/api/runs/crons` and thread-bound crons).
2943
+ */
2944
+ this.crons = {
2945
+ /**
2946
+ * Creates a cron bound to an existing thread.
2947
+ * @param threadId - Thread that receives follow-up runs.
2948
+ * @param body - Cron definition.
2949
+ * @returns The created cron.
2950
+ */
2951
+ createForThread: async (threadId, body) => {
2952
+ const response = await this.makeRequest(
2953
+ `/api/threads/${threadId}/runs/crons`,
2954
+ { method: "POST", body }
2955
+ );
2956
+ return response.data;
2957
+ },
2958
+ /**
2959
+ * Creates a stateless cron that starts a fresh thread per fire.
2960
+ * @param body - Cron definition including the assistant id.
2961
+ * @returns The created cron.
2962
+ */
2963
+ createStateless: async (body) => {
2964
+ const response = await this.makeRequest(
2965
+ "/api/runs/crons",
2966
+ { method: "POST", body }
2967
+ );
2968
+ return response.data;
2969
+ },
2970
+ /**
2971
+ * Searches tenant-scoped Agent crons.
2972
+ * @param body - Optional assistant/thread/enabled/pagination filters.
2973
+ * @returns Matching crons.
2974
+ */
2975
+ search: async (body = {}) => {
2976
+ const response = await this.makeRequest("/api/runs/crons/search", { method: "POST", body });
2977
+ return response.data.items;
2978
+ },
2979
+ /**
2980
+ * Counts tenant-scoped Agent crons.
2981
+ * @param body - Optional assistant/thread/enabled filters.
2982
+ * @returns Matching cron count.
2983
+ */
2984
+ count: async (body = {}) => {
2985
+ const response = await this.makeRequest("/api/runs/crons/count", { method: "POST", body });
2986
+ return response.data.count;
2987
+ },
2988
+ /**
2989
+ * Reads one Agent cron.
2990
+ * @param cronId - Cron id.
2991
+ * @returns The cron resource.
2992
+ */
2993
+ get: async (cronId) => {
2994
+ const response = await this.makeRequest(
2995
+ `/api/runs/crons/${cronId}`
2996
+ );
2997
+ return response.data;
2998
+ },
2999
+ /**
3000
+ * Pauses or resumes a cron.
3001
+ * @param cronId - Cron id.
3002
+ * @param enabled - Desired enabled state.
3003
+ * @returns The updated cron.
3004
+ */
3005
+ updateEnabled: async (cronId, enabled) => {
3006
+ const body = { enabled };
3007
+ const response = await this.makeRequest(
3008
+ `/api/runs/crons/${cronId}`,
3009
+ { method: "PATCH", body }
3010
+ );
3011
+ return response.data;
3012
+ },
3013
+ /**
3014
+ * Cancels/deletes a cron.
3015
+ * @param cronId - Cron id.
3016
+ * @returns True when the gateway reports success.
3017
+ */
3018
+ delete: async (cronId) => {
3019
+ const response = await this.makeRequest(
3020
+ `/api/runs/crons/${cronId}`,
3021
+ { method: "DELETE" }
3022
+ );
3023
+ return response.success;
3024
+ }
3025
+ };
3026
+ /**
3027
+ * Thread command surface (`run.start`, `input.respond`, `agent.getTree`).
3028
+ */
3029
+ this.commands = {
3030
+ /**
3031
+ * Starts a run on a thread.
3032
+ * @param threadId - Thread id.
3033
+ * @param args - Input/config/metadata/strategy.
3034
+ * @returns Queued message id and mode.
3035
+ */
3036
+ runStart: async (threadId, args) => {
3037
+ const response = await this.makeRequest(
3038
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3039
+ { method: "POST", body: { command: "run.start", args } }
3040
+ );
3041
+ return response.data;
3042
+ },
3043
+ /**
3044
+ * Answers a pending interrupt.
3045
+ * @param threadId - Thread id.
3046
+ * @param args - Interrupt id and response/resume payload.
3047
+ * @returns Queued message id and interrupt id.
3048
+ */
3049
+ respond: async (threadId, args) => {
3050
+ const response = await this.makeRequest(
3051
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3052
+ { method: "POST", body: { command: "input.respond", args } }
3053
+ );
3054
+ return response.data;
3055
+ },
3056
+ /**
3057
+ * Reads the structured Agent graph.
3058
+ * @param threadId - Thread id.
3059
+ * @returns Nodes, edges, Mermaid, and namespace placeholder.
3060
+ */
3061
+ getTree: async (threadId) => {
3062
+ const response = await this.makeRequest(
3063
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3064
+ { method: "POST", body: { command: "agent.getTree" } }
3065
+ );
3066
+ return response.data;
3067
+ }
3068
+ };
3069
+ /**
3070
+ * Single-run surface (`POST/GET /threads/:id/runs`, cancellation).
3071
+ */
3072
+ this.runs = {
3073
+ /**
3074
+ * Enqueues one run-bound input or HITL resume command.
3075
+ * @param threadId - Thread id.
3076
+ * @param input - Message or messages accepted by the run API; omit for command runs.
3077
+ * @param options - Optional config, mode, command, and multitask strategy.
3078
+ * @param assistantId - Assistant id override (defaults to the client's).
3079
+ * @returns Pending run id and the optional input message id.
3080
+ */
3081
+ create: async (threadId, input, options, assistantId) => {
3082
+ const body = {};
3083
+ if (input !== void 0)
3084
+ body.input = input;
3085
+ if (options?.command !== void 0)
3086
+ body.command = options.command;
3087
+ if (options?.config !== void 0)
3088
+ body.config = options.config;
3089
+ if (options?.mode !== void 0)
3090
+ body.mode = options.mode;
3091
+ if (options?.multitaskStrategy !== void 0) {
3092
+ body.multitask_strategy = options.multitaskStrategy;
3093
+ }
3094
+ const response = await this.makeRequest(
3095
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs`,
3096
+ { method: "POST", body }
3097
+ );
3098
+ return response.data;
3099
+ },
3100
+ /**
3101
+ * Lists run ledger records for a thread.
3102
+ * @param threadId - Thread id.
3103
+ * @param assistantId - Assistant id override (defaults to the client's).
3104
+ * @returns Safe run records.
3105
+ */
3106
+ list: async (threadId, assistantId) => {
3107
+ const response = await this.makeRequest(
3108
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs`
3109
+ );
3110
+ return response.data.runs;
3111
+ },
3112
+ /**
3113
+ * Reads one run ledger record.
3114
+ * @param threadId - Thread id.
3115
+ * @param runId - Run id.
3116
+ * @param assistantId - Assistant id override (defaults to the client's).
3117
+ * @returns The safe run record.
3118
+ */
3119
+ get: async (threadId, runId, assistantId) => {
3120
+ const response = await this.makeRequest(
3121
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}`
3122
+ );
3123
+ return response.data;
3124
+ },
3125
+ /**
3126
+ * Waits for a run to reach a terminal status (server-capped).
3127
+ * @param threadId - Thread id.
3128
+ * @param runId - Run id.
3129
+ * @param assistantId - Assistant id override (defaults to the client's).
3130
+ * @returns The terminal run record.
3131
+ * @throws {ApiError} On `504 RUN_JOIN_TIMEOUT` or `404 RUN_NOT_FOUND`.
3132
+ */
3133
+ join: async (threadId, runId, assistantId) => {
3134
+ const response = await this.makeRequest(
3135
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}/join`
3136
+ );
3137
+ return response.data;
3138
+ },
3139
+ /**
3140
+ * Requests cancellation of one run.
3141
+ * @param threadId - Thread id.
3142
+ * @param runId - Run id.
3143
+ * @param options - Optional `wait` and `action` (`interrupt` or `rollback`).
3144
+ * @param assistantId - Assistant id override (defaults to the client's).
3145
+ * @returns Acceptance, terminal status, and optional latest run.
3146
+ */
3147
+ cancel: async (threadId, runId, options, assistantId) => {
3148
+ const params = new URLSearchParams();
3149
+ if (options?.action !== void 0)
3150
+ params.set("action", options.action);
3151
+ if (options?.wait !== void 0)
3152
+ params.set("wait", String(options.wait));
3153
+ const query = params.toString();
3154
+ const response = await this.makeRequest(
3155
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}/cancel${query ? `?${query}` : ""}`,
3156
+ { method: "POST" }
3157
+ );
3158
+ return response;
3159
+ }
3160
+ };
3161
+ /**
3162
+ * Tenant-scoped namespaced key-value store (viewer/editor surface).
3163
+ */
3164
+ this.store = {
3165
+ /**
3166
+ * Creates or replaces a store item.
3167
+ * @param input - Namespace, key, value, optional TTL/index hint.
3168
+ * @returns The persisted item.
3169
+ */
3170
+ put: async (input) => {
3171
+ const response = await this.makeRequest(
3172
+ "/api/store/items",
3173
+ { method: "PUT", body: input }
3174
+ );
3175
+ return response.data;
3176
+ },
3177
+ /**
3178
+ * Reads one item by namespace and key.
3179
+ * @param namespace - Namespace path.
3180
+ * @param key - Item key.
3181
+ * @returns The item.
3182
+ */
3183
+ get: async (namespace, key) => {
3184
+ const params = namespace.map((segment) => `namespace=${encodeURIComponent(segment)}`).concat(`key=${encodeURIComponent(key)}`).join("&");
3185
+ const response = await this.makeRequest(
3186
+ `/api/store/items?${params}`
3187
+ );
3188
+ return response.data;
3189
+ },
3190
+ /**
3191
+ * Deletes one item.
3192
+ * @param namespace - Namespace path.
3193
+ * @param key - Item key.
3194
+ * @returns True when deleted.
3195
+ */
3196
+ delete: async (namespace, key) => {
3197
+ const response = await this.makeRequest(
3198
+ "/api/store/items",
3199
+ { method: "DELETE", body: { namespace, key } }
3200
+ );
3201
+ return response.data?.deleted === true;
3202
+ },
3203
+ /**
3204
+ * Searches items under a namespace prefix.
3205
+ * @param input - Prefix/filter/query/pagination.
3206
+ * @returns Matching items.
3207
+ */
3208
+ search: async (input = {}) => {
3209
+ const response = await this.makeRequest(
3210
+ "/api/store/items/search",
3211
+ { method: "POST", body: input }
3212
+ );
3213
+ return response.data.items;
3214
+ },
3215
+ /**
3216
+ * Lists distinct namespace paths.
3217
+ * @param prefix - Optional namespace prefix.
3218
+ * @param limit - Optional result cap (gateway clamps).
3219
+ * @returns Namespace paths.
3220
+ */
3221
+ namespaces: async (prefix, limit) => {
3222
+ const response = await this.makeRequest(
3223
+ "/api/store/namespaces",
3224
+ {
3225
+ method: "POST",
3226
+ body: {
3227
+ ...prefix === void 0 ? {} : { prefix },
3228
+ ...limit === void 0 ? {} : { limit }
3229
+ }
3230
+ }
3231
+ );
3232
+ return response.data.namespaces;
3233
+ }
3234
+ };
2831
3235
  this.config = {
2832
3236
  timeout: 3e5,
2833
3237
  // Default timeout
@@ -3204,6 +3608,94 @@ var AbstractClient = class {
3204
3608
  });
3205
3609
  return clonedClient;
3206
3610
  }
3611
+ /**
3612
+ * Headers for thread event SSE requests. Concrete clients may add live
3613
+ * tenant/workspace/auth state.
3614
+ *
3615
+ * @returns Request headers.
3616
+ */
3617
+ getThreadEventHeaders() {
3618
+ return { ...this.config.headers ?? {} };
3619
+ }
3620
+ /**
3621
+ * Stream thread-wide projected events over SSE.
3622
+ *
3623
+ * The caller owns reconnection: pass the last `event.seq` as `since`.
3624
+ * There is no automatic retry. Browser WebSocket auth is not covered here;
3625
+ * this SSE path uses `fetch` and the normal Authorization headers.
3626
+ *
3627
+ * @param threadId - Thread id.
3628
+ * @param options - Channel/namespace/depth filters and resume cursor.
3629
+ * @param onEvent - Callback for each projected event.
3630
+ * @param onError - Callback for stream/cursor errors (stream stops).
3631
+ * @returns Abort function.
3632
+ */
3633
+ streamThreadEvents(threadId, options, onEvent, onError) {
3634
+ const controller = new AbortController();
3635
+ const headers = {
3636
+ "Content-Type": "application/json",
3637
+ Accept: "text/event-stream",
3638
+ ...this.getThreadEventHeaders()
3639
+ };
3640
+ void (async () => {
3641
+ try {
3642
+ const response = await fetch(
3643
+ `${this.config.baseURL}/api/assistants/${this.assistantId}/threads/${threadId}/stream/events`,
3644
+ {
3645
+ method: "POST",
3646
+ headers,
3647
+ body: JSON.stringify(options),
3648
+ signal: controller.signal
3649
+ }
3650
+ );
3651
+ if (!response.ok) {
3652
+ const errorData = await response.json().catch(() => ({}));
3653
+ throw Object.assign(
3654
+ new Error(
3655
+ errorData.error ?? errorData.message ?? `HTTP error! Status: ${response.status}`
3656
+ ),
3657
+ { status: response.status, responseBody: errorData }
3658
+ );
3659
+ }
3660
+ if (!response.body)
3661
+ throw new Error("Response body is null");
3662
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true })) {
3663
+ if (frame.event === "error") {
3664
+ const data = frame.data;
3665
+ const error = Object.assign(
3666
+ new Error(typeof data.message === "string" ? data.message : "Thread event stream error"),
3667
+ { code: typeof data.code === "string" ? data.code : "stream_error" }
3668
+ );
3669
+ onError?.(error);
3670
+ return;
3671
+ }
3672
+ const event = frame.data;
3673
+ if (event.type === "event") {
3674
+ onEvent(event);
3675
+ } else if (event.type === "error") {
3676
+ const data = event;
3677
+ const error = Object.assign(
3678
+ new Error(typeof data.message === "string" ? data.message : "Thread event stream error"),
3679
+ { code: typeof data.code === "string" ? data.code : "stream_error" }
3680
+ );
3681
+ onError?.(error);
3682
+ return;
3683
+ }
3684
+ }
3685
+ } catch (error) {
3686
+ if (controller.signal.aborted)
3687
+ return;
3688
+ if (error instanceof DOMException && error.name === "AbortError")
3689
+ return;
3690
+ if (error instanceof SseParseError) {
3691
+ onError?.(Object.assign(new Error(error.message), { code: "INVALID_EVENT" }));
3692
+ return;
3693
+ }
3694
+ onError?.(error instanceof Error ? error : new Error(String(error)));
3695
+ }
3696
+ })();
3697
+ return () => controller.abort();
3698
+ }
3207
3699
  /**
3208
3700
  * Abstract method for streaming API requests
3209
3701
  * To be implemented by concrete client classes
@@ -3278,6 +3770,98 @@ var AbstractClient = class {
3278
3770
  );
3279
3771
  return response.data.records;
3280
3772
  }
3773
+ /**
3774
+ * Reads a thread's run status, pending message count, and interrupts.
3775
+ * @param threadId - Thread identifier.
3776
+ * @returns Thread status projection.
3777
+ */
3778
+ async getThreadStatus(threadId) {
3779
+ const response = await this.makeRequest(
3780
+ `/api/assistants/${this.assistantId}/threads/${threadId}/status`
3781
+ );
3782
+ return response.data;
3783
+ }
3784
+ /**
3785
+ * Reads a page of thread checkpoint history.
3786
+ * @param threadId - Thread identifier.
3787
+ * @param options - Optional limit and before-checkpoint cursor.
3788
+ * @returns Checkpoint snapshots, newest first.
3789
+ */
3790
+ async getThreadHistory(threadId, options = {}) {
3791
+ const params = new URLSearchParams();
3792
+ if (options.limit !== void 0)
3793
+ params.append("limit", String(options.limit));
3794
+ if (options.before !== void 0)
3795
+ params.append("before", options.before);
3796
+ const query = params.toString();
3797
+ const response = await this.makeRequest(
3798
+ `/api/assistants/${this.assistantId}/threads/${threadId}/history${query ? `?${query}` : ""}`
3799
+ );
3800
+ return response.data.history;
3801
+ }
3802
+ /**
3803
+ * Reads the raw snapshot at one checkpoint.
3804
+ * @param threadId - Thread identifier.
3805
+ * @param checkpointId - Checkpoint identifier.
3806
+ * @returns The raw checkpoint snapshot.
3807
+ */
3808
+ async getThreadStateAtCheckpoint(threadId, checkpointId) {
3809
+ const response = await this.makeRequest(
3810
+ `/api/assistants/${this.assistantId}/threads/${threadId}/state/${encodeURIComponent(checkpointId)}`
3811
+ );
3812
+ return response.data;
3813
+ }
3814
+ /**
3815
+ * Reads checkpoint storage accounting for a thread.
3816
+ * @param threadId - Thread identifier.
3817
+ * @returns Storage byte/count projection.
3818
+ */
3819
+ async getThreadStorage(threadId) {
3820
+ const response = await this.makeRequest(
3821
+ `/api/assistants/${this.assistantId}/threads/${threadId}/storage`
3822
+ );
3823
+ return response.data;
3824
+ }
3825
+ /**
3826
+ * Copies a thread's checkpoints and row into a new thread.
3827
+ * @param threadId - Source thread identifier.
3828
+ * @returns The created thread.
3829
+ */
3830
+ async copyThread(threadId) {
3831
+ const response = await this.makeRequest(
3832
+ `/api/assistants/${this.assistantId}/threads/${threadId}/copy`,
3833
+ { method: "POST" }
3834
+ );
3835
+ return response.data;
3836
+ }
3837
+ /**
3838
+ * Prunes a thread's checkpoints or deletes the thread.
3839
+ * @param threadId - Thread identifier.
3840
+ * @param input - Prune strategy and optional keep count.
3841
+ * @returns Prune result.
3842
+ */
3843
+ async pruneThread(threadId, input) {
3844
+ const response = await this.makeRequest(
3845
+ `/api/assistants/${this.assistantId}/threads/${threadId}/prune`,
3846
+ { method: "POST", body: input }
3847
+ );
3848
+ return response.data;
3849
+ }
3850
+ /**
3851
+ * Reads the public gateway info surface.
3852
+ * @returns Service identity, flags, capabilities, endpoints, and metadata.
3853
+ */
3854
+ async getInfo() {
3855
+ const response = await this.makeRequest("/info");
3856
+ return response.data;
3857
+ }
3858
+ /**
3859
+ * Reads the current gateway replica's runtime metrics.
3860
+ * @returns Run counts, pending threads, worker posture, and chunk posture.
3861
+ */
3862
+ async getSystemMetrics() {
3863
+ return this.makeRequest("/metrics?format=json");
3864
+ }
3281
3865
  /**
3282
3866
  * Deletes a thread
3283
3867
  * @deprecated Use threads.delete() instead
@@ -3770,6 +4354,7 @@ var ProjectRoomsClient = class {
3770
4354
  method: "POST",
3771
4355
  body: {
3772
4356
  ...target,
4357
+ ...input.interruptId === void 0 ? {} : { interruptId: input.interruptId },
3773
4358
  ...input.answers === void 0 ? {} : { answers: input.answers }
3774
4359
  }
3775
4360
  });
@@ -3905,114 +4490,6 @@ var WorkspaceMembersClient = class {
3905
4490
  }
3906
4491
  };
3907
4492
 
3908
- // src/sse-parser.ts
3909
- var SseParseError = class extends Error {
3910
- constructor(message) {
3911
- super(message);
3912
- this.code = "INVALID_EVENT";
3913
- this.name = "SseParseError";
3914
- }
3915
- };
3916
- async function* parseSseBody(body, options = {}) {
3917
- const reader = body.getReader();
3918
- const decoder = new TextDecoder();
3919
- let buffer = "";
3920
- let event = "";
3921
- let id;
3922
- let retry;
3923
- let data = [];
3924
- const dispatch = () => {
3925
- if (data.length === 0) {
3926
- event = "";
3927
- id = void 0;
3928
- retry = void 0;
3929
- return void 0;
3930
- }
3931
- let parsed;
3932
- try {
3933
- parsed = JSON.parse(data.join("\n"));
3934
- } catch {
3935
- throw new SseParseError("Invalid SSE JSON");
3936
- }
3937
- if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
3938
- throw new SseParseError("SSE data must be an object");
3939
- const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
3940
- event = "";
3941
- id = void 0;
3942
- retry = void 0;
3943
- data = [];
3944
- return result;
3945
- };
3946
- const processLine = (raw) => {
3947
- const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
3948
- if (line === "")
3949
- return dispatch();
3950
- if (line.startsWith(":"))
3951
- return void 0;
3952
- const separator = line.indexOf(":");
3953
- const field = separator < 0 ? line : line.slice(0, separator);
3954
- let value = separator < 0 ? "" : line.slice(separator + 1);
3955
- if (value.startsWith(" "))
3956
- value = value.slice(1);
3957
- if (field === "event")
3958
- event = value;
3959
- else if (field === "data")
3960
- data.push(value);
3961
- else if (field === "id")
3962
- id = value;
3963
- else if (field === "retry") {
3964
- const parsed = Number(value);
3965
- if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
3966
- throw new SseParseError("Invalid SSE retry");
3967
- retry = parsed;
3968
- }
3969
- return void 0;
3970
- };
3971
- try {
3972
- while (true) {
3973
- const chunk = await reader.read();
3974
- if (chunk.done) {
3975
- buffer += decoder.decode();
3976
- break;
3977
- }
3978
- buffer += decoder.decode(chunk.value, { stream: true });
3979
- let index = findLineBreak(buffer);
3980
- while (index >= 0) {
3981
- if (buffer[index] === "\r" && index === buffer.length - 1)
3982
- break;
3983
- const frame2 = processLine(buffer.slice(0, index));
3984
- buffer = buffer.slice(index + lineBreakLength(buffer, index));
3985
- if (frame2)
3986
- yield frame2;
3987
- index = findLineBreak(buffer);
3988
- }
3989
- }
3990
- if (buffer) {
3991
- const frame2 = processLine(buffer);
3992
- if (frame2)
3993
- yield frame2;
3994
- }
3995
- const frame = processLine("");
3996
- if (frame)
3997
- yield frame;
3998
- } finally {
3999
- await reader.cancel().catch(() => void 0);
4000
- reader.releaseLock();
4001
- }
4002
- }
4003
- function findLineBreak(value) {
4004
- const lf = value.indexOf("\n");
4005
- const cr = value.indexOf("\r");
4006
- if (lf < 0)
4007
- return cr;
4008
- if (cr < 0)
4009
- return lf;
4010
- return Math.min(lf, cr);
4011
- }
4012
- function lineBreakLength(value, index) {
4013
- return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
4014
- }
4015
-
4016
4493
  // src/room-events.ts
4017
4494
  var invalidFrame = (message) => new ProjectRoomClientError(message, 200, "INVALID_EVENT", false);
4018
4495
  var requiredString3 = (row, field) => {
@@ -4150,6 +4627,8 @@ var _Client = class extends AbstractClient {
4150
4627
  */
4151
4628
  constructor(config) {
4152
4629
  super(config);
4630
+ /** Last SSE event id observed per thread, for automatic resume. */
4631
+ this.resumeEventIds = /* @__PURE__ */ new Map();
4153
4632
  this.headers = {
4154
4633
  "Content-Type": "application/json",
4155
4634
  Authorization: `Bearer ${this.config.apiKey}`,
@@ -4173,7 +4652,7 @@ var _Client = class extends AbstractClient {
4173
4652
  } else {
4174
4653
  const errorData = await response.json().catch(() => ({}));
4175
4654
  throw new ApiError(
4176
- errorData.message || "API Error",
4655
+ errorData.error ?? errorData.message ?? "API Error",
4177
4656
  response.status,
4178
4657
  errorData
4179
4658
  );
@@ -4283,6 +4762,14 @@ var _Client = class extends AbstractClient {
4283
4762
  getWorkspaceHeaders() {
4284
4763
  return { ..._Client.globalWorkspaceHeaders, ...this.workspaceHeaders };
4285
4764
  }
4765
+ /**
4766
+ * Instance-only workspace headers (never merged with the process-global
4767
+ * Console context). Runtime transports use this so a web-app scope cannot
4768
+ * inherit a Console tenant/project selection from another client.
4769
+ */
4770
+ getInstanceWorkspaceHeaders() {
4771
+ return { ...this.workspaceHeaders };
4772
+ }
4286
4773
  /**
4287
4774
  * Get global workspace headers (legacy static API)
4288
4775
  */
@@ -4344,11 +4831,13 @@ var _Client = class extends AbstractClient {
4344
4831
  * @returns A function that can be called to stop the stream
4345
4832
  */
4346
4833
  resumeStream(options, onEvent, onComplete, onError) {
4834
+ const lastEventId = options.lastEventId?.trim() || this.resumeEventIds.get(options.threadId);
4347
4835
  const headers = {
4348
4836
  "Content-Type": "application/json",
4349
4837
  Accept: "text/event-stream",
4350
4838
  ...this.getAllHeaders(),
4351
- ...threadAffinityHeaders2(options.threadId)
4839
+ ...threadAffinityHeaders2(options.threadId),
4840
+ ...lastEventId ? { "Last-Event-ID": lastEventId } : {}
4352
4841
  };
4353
4842
  const controller = new AbortController();
4354
4843
  const { signal } = controller;
@@ -4371,15 +4860,27 @@ var _Client = class extends AbstractClient {
4371
4860
  );
4372
4861
  if (!response.ok) {
4373
4862
  const errorData = await response.json().catch(() => ({}));
4374
- throw new Error(
4375
- errorData.error || errorData.message || `HTTP error! Status: ${response.status}`
4863
+ throw Object.assign(
4864
+ new Error(
4865
+ errorData.error || errorData.message || `HTTP error! Status: ${response.status}`
4866
+ ),
4867
+ { status: response.status, responseBody: errorData }
4376
4868
  );
4377
4869
  }
4378
4870
  if (!response.body) {
4379
4871
  throw new Error("Response body is null");
4380
4872
  }
4381
- for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4382
- onEvent(frame.data);
4873
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true })) {
4874
+ if (typeof frame.id === "string" && frame.id !== "") {
4875
+ this.resumeEventIds.set(options.threadId, frame.id);
4876
+ }
4877
+ const chunk = frame.data;
4878
+ if (chunk.type === "error" && chunk.data?.code === "CURSOR_EXPIRED") {
4879
+ this.resumeEventIds.delete(options.threadId);
4880
+ }
4881
+ onEvent(chunk);
4882
+ }
4883
+ this.resumeEventIds.delete(options.threadId);
4383
4884
  if (onComplete) {
4384
4885
  onComplete();
4385
4886
  }
@@ -4393,6 +4894,7 @@ var _Client = class extends AbstractClient {
4393
4894
  }
4394
4895
  })();
4395
4896
  return () => {
4897
+ this.resumeEventIds.delete(options.threadId);
4396
4898
  controller.abort();
4397
4899
  };
4398
4900
  }
@@ -4446,6 +4948,9 @@ var _Client = class extends AbstractClient {
4446
4948
  ...workspaceHeaders
4447
4949
  };
4448
4950
  }
4951
+ getThreadEventHeaders() {
4952
+ return this.getAllHeaders();
4953
+ }
4449
4954
  bodyAffinityHeaders(body) {
4450
4955
  if (!body || typeof body !== "object" || body instanceof FormData)
4451
4956
  return {};
@@ -4558,11 +5063,7 @@ var RuntimeAxiomClient = class extends Client {
4558
5063
  return { "X-Axiom-External-User-Id": this.identity.userId };
4559
5064
  }
4560
5065
  getAllHeaders() {
4561
- const workspace = this.getWorkspaceHeaders();
4562
- return {
4563
- ...this.identityHeaders(),
4564
- ...workspace
4565
- };
5066
+ return { ...this.identityHeaders() };
4566
5067
  }
4567
5068
  async makeRequest(url, options) {
4568
5069
  await this.primeToken();
@@ -4570,7 +5071,7 @@ var RuntimeAxiomClient = class extends Client {
4570
5071
  const affinity = this.bodyAffinityHeaders(options?.body);
4571
5072
  const headers = {
4572
5073
  "Content-Type": "application/json",
4573
- ...this.identityHeaders(),
5074
+ ...this.getAllHeaders(),
4574
5075
  ...affinity,
4575
5076
  ...options?.headers ?? {}
4576
5077
  };