@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.js CHANGED
@@ -1888,6 +1888,116 @@ var ScheduledTaskStatus = /* @__PURE__ */ ((ScheduledTaskStatus2) => {
1888
1888
 
1889
1889
  // src/abstract-client.ts
1890
1890
  var import_protocols = require("@axiom-lattice/protocols");
1891
+
1892
+ // src/sse-parser.ts
1893
+ var SseParseError = class extends Error {
1894
+ constructor(message) {
1895
+ super(message);
1896
+ this.code = "INVALID_EVENT";
1897
+ this.name = "SseParseError";
1898
+ }
1899
+ };
1900
+ async function* parseSseBody(body, options = {}) {
1901
+ const reader = body.getReader();
1902
+ const decoder = new TextDecoder();
1903
+ let buffer = "";
1904
+ let event = "";
1905
+ let id;
1906
+ let retry;
1907
+ let data = [];
1908
+ const dispatch = () => {
1909
+ if (data.length === 0) {
1910
+ event = "";
1911
+ id = void 0;
1912
+ retry = void 0;
1913
+ return void 0;
1914
+ }
1915
+ let parsed;
1916
+ try {
1917
+ parsed = JSON.parse(data.join("\n"));
1918
+ } catch {
1919
+ throw new SseParseError("Invalid SSE JSON");
1920
+ }
1921
+ if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
1922
+ throw new SseParseError("SSE data must be an object");
1923
+ const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
1924
+ event = "";
1925
+ id = void 0;
1926
+ retry = void 0;
1927
+ data = [];
1928
+ return result;
1929
+ };
1930
+ const processLine = (raw) => {
1931
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
1932
+ if (line === "")
1933
+ return dispatch();
1934
+ if (line.startsWith(":"))
1935
+ return void 0;
1936
+ const separator = line.indexOf(":");
1937
+ const field = separator < 0 ? line : line.slice(0, separator);
1938
+ let value = separator < 0 ? "" : line.slice(separator + 1);
1939
+ if (value.startsWith(" "))
1940
+ value = value.slice(1);
1941
+ if (field === "event")
1942
+ event = value;
1943
+ else if (field === "data")
1944
+ data.push(value);
1945
+ else if (field === "id")
1946
+ id = value;
1947
+ else if (field === "retry") {
1948
+ const parsed = Number(value);
1949
+ if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
1950
+ throw new SseParseError("Invalid SSE retry");
1951
+ retry = parsed;
1952
+ }
1953
+ return void 0;
1954
+ };
1955
+ try {
1956
+ while (true) {
1957
+ const chunk = await reader.read();
1958
+ if (chunk.done) {
1959
+ buffer += decoder.decode();
1960
+ break;
1961
+ }
1962
+ buffer += decoder.decode(chunk.value, { stream: true });
1963
+ let index = findLineBreak(buffer);
1964
+ while (index >= 0) {
1965
+ if (buffer[index] === "\r" && index === buffer.length - 1)
1966
+ break;
1967
+ const frame2 = processLine(buffer.slice(0, index));
1968
+ buffer = buffer.slice(index + lineBreakLength(buffer, index));
1969
+ if (frame2)
1970
+ yield frame2;
1971
+ index = findLineBreak(buffer);
1972
+ }
1973
+ }
1974
+ if (buffer) {
1975
+ const frame2 = processLine(buffer);
1976
+ if (frame2)
1977
+ yield frame2;
1978
+ }
1979
+ const frame = processLine("");
1980
+ if (frame)
1981
+ yield frame;
1982
+ } finally {
1983
+ await reader.cancel().catch(() => void 0);
1984
+ reader.releaseLock();
1985
+ }
1986
+ }
1987
+ function findLineBreak(value) {
1988
+ const lf = value.indexOf("\n");
1989
+ const cr = value.indexOf("\r");
1990
+ if (lf < 0)
1991
+ return cr;
1992
+ if (cr < 0)
1993
+ return lf;
1994
+ return Math.min(lf, cr);
1995
+ }
1996
+ function lineBreakLength(value, index) {
1997
+ return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
1998
+ }
1999
+
2000
+ // src/abstract-client.ts
1891
2001
  var AbstractClient = class {
1892
2002
  /**
1893
2003
  * Creates a new AbstractClient instance
@@ -1955,7 +2065,7 @@ var AbstractClient = class {
1955
2065
  if (!response.success) {
1956
2066
  throw new Error(response.error || "Failed to enqueue message");
1957
2067
  }
1958
- return { messageId: response.messageId, queued: response.queued };
2068
+ return { messageId: response.messageId, queued: response.queued, ...response.runId ? { runId: response.runId } : {} };
1959
2069
  },
1960
2070
  /**
1961
2071
  * Sends a message to a thread and streams the response
@@ -2859,6 +2969,300 @@ var AbstractClient = class {
2859
2969
  return response.success;
2860
2970
  }
2861
2971
  };
2972
+ /**
2973
+ * Agent cron resources (`/api/runs/crons` and thread-bound crons).
2974
+ */
2975
+ this.crons = {
2976
+ /**
2977
+ * Creates a cron bound to an existing thread.
2978
+ * @param threadId - Thread that receives follow-up runs.
2979
+ * @param body - Cron definition.
2980
+ * @returns The created cron.
2981
+ */
2982
+ createForThread: async (threadId, body) => {
2983
+ const response = await this.makeRequest(
2984
+ `/api/threads/${threadId}/runs/crons`,
2985
+ { method: "POST", body }
2986
+ );
2987
+ return response.data;
2988
+ },
2989
+ /**
2990
+ * Creates a stateless cron that starts a fresh thread per fire.
2991
+ * @param body - Cron definition including the assistant id.
2992
+ * @returns The created cron.
2993
+ */
2994
+ createStateless: async (body) => {
2995
+ const response = await this.makeRequest(
2996
+ "/api/runs/crons",
2997
+ { method: "POST", body }
2998
+ );
2999
+ return response.data;
3000
+ },
3001
+ /**
3002
+ * Searches tenant-scoped Agent crons.
3003
+ * @param body - Optional assistant/thread/enabled/pagination filters.
3004
+ * @returns Matching crons.
3005
+ */
3006
+ search: async (body = {}) => {
3007
+ const response = await this.makeRequest("/api/runs/crons/search", { method: "POST", body });
3008
+ return response.data.items;
3009
+ },
3010
+ /**
3011
+ * Counts tenant-scoped Agent crons.
3012
+ * @param body - Optional assistant/thread/enabled filters.
3013
+ * @returns Matching cron count.
3014
+ */
3015
+ count: async (body = {}) => {
3016
+ const response = await this.makeRequest("/api/runs/crons/count", { method: "POST", body });
3017
+ return response.data.count;
3018
+ },
3019
+ /**
3020
+ * Reads one Agent cron.
3021
+ * @param cronId - Cron id.
3022
+ * @returns The cron resource.
3023
+ */
3024
+ get: async (cronId) => {
3025
+ const response = await this.makeRequest(
3026
+ `/api/runs/crons/${cronId}`
3027
+ );
3028
+ return response.data;
3029
+ },
3030
+ /**
3031
+ * Pauses or resumes a cron.
3032
+ * @param cronId - Cron id.
3033
+ * @param enabled - Desired enabled state.
3034
+ * @returns The updated cron.
3035
+ */
3036
+ updateEnabled: async (cronId, enabled) => {
3037
+ const body = { enabled };
3038
+ const response = await this.makeRequest(
3039
+ `/api/runs/crons/${cronId}`,
3040
+ { method: "PATCH", body }
3041
+ );
3042
+ return response.data;
3043
+ },
3044
+ /**
3045
+ * Cancels/deletes a cron.
3046
+ * @param cronId - Cron id.
3047
+ * @returns True when the gateway reports success.
3048
+ */
3049
+ delete: async (cronId) => {
3050
+ const response = await this.makeRequest(
3051
+ `/api/runs/crons/${cronId}`,
3052
+ { method: "DELETE" }
3053
+ );
3054
+ return response.success;
3055
+ }
3056
+ };
3057
+ /**
3058
+ * Thread command surface (`run.start`, `input.respond`, `agent.getTree`).
3059
+ */
3060
+ this.commands = {
3061
+ /**
3062
+ * Starts a run on a thread.
3063
+ * @param threadId - Thread id.
3064
+ * @param args - Input/config/metadata/strategy.
3065
+ * @returns Queued message id and mode.
3066
+ */
3067
+ runStart: async (threadId, args) => {
3068
+ const response = await this.makeRequest(
3069
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3070
+ { method: "POST", body: { command: "run.start", args } }
3071
+ );
3072
+ return response.data;
3073
+ },
3074
+ /**
3075
+ * Answers a pending interrupt.
3076
+ * @param threadId - Thread id.
3077
+ * @param args - Interrupt id and response/resume payload.
3078
+ * @returns Queued message id and interrupt id.
3079
+ */
3080
+ respond: async (threadId, args) => {
3081
+ const response = await this.makeRequest(
3082
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3083
+ { method: "POST", body: { command: "input.respond", args } }
3084
+ );
3085
+ return response.data;
3086
+ },
3087
+ /**
3088
+ * Reads the structured Agent graph.
3089
+ * @param threadId - Thread id.
3090
+ * @returns Nodes, edges, Mermaid, and namespace placeholder.
3091
+ */
3092
+ getTree: async (threadId) => {
3093
+ const response = await this.makeRequest(
3094
+ `/api/assistants/${this.assistantId}/threads/${threadId}/commands`,
3095
+ { method: "POST", body: { command: "agent.getTree" } }
3096
+ );
3097
+ return response.data;
3098
+ }
3099
+ };
3100
+ /**
3101
+ * Single-run surface (`POST/GET /threads/:id/runs`, cancellation).
3102
+ */
3103
+ this.runs = {
3104
+ /**
3105
+ * Enqueues one run-bound input or HITL resume command.
3106
+ * @param threadId - Thread id.
3107
+ * @param input - Message or messages accepted by the run API; omit for command runs.
3108
+ * @param options - Optional config, mode, command, and multitask strategy.
3109
+ * @param assistantId - Assistant id override (defaults to the client's).
3110
+ * @returns Pending run id and the optional input message id.
3111
+ */
3112
+ create: async (threadId, input, options, assistantId) => {
3113
+ const body = {};
3114
+ if (input !== void 0)
3115
+ body.input = input;
3116
+ if (options?.command !== void 0)
3117
+ body.command = options.command;
3118
+ if (options?.config !== void 0)
3119
+ body.config = options.config;
3120
+ if (options?.mode !== void 0)
3121
+ body.mode = options.mode;
3122
+ if (options?.multitaskStrategy !== void 0) {
3123
+ body.multitask_strategy = options.multitaskStrategy;
3124
+ }
3125
+ const response = await this.makeRequest(
3126
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs`,
3127
+ { method: "POST", body }
3128
+ );
3129
+ return response.data;
3130
+ },
3131
+ /**
3132
+ * Lists run ledger records for a thread.
3133
+ * @param threadId - Thread id.
3134
+ * @param assistantId - Assistant id override (defaults to the client's).
3135
+ * @returns Safe run records.
3136
+ */
3137
+ list: async (threadId, assistantId) => {
3138
+ const response = await this.makeRequest(
3139
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs`
3140
+ );
3141
+ return response.data.runs;
3142
+ },
3143
+ /**
3144
+ * Reads one run ledger record.
3145
+ * @param threadId - Thread id.
3146
+ * @param runId - Run id.
3147
+ * @param assistantId - Assistant id override (defaults to the client's).
3148
+ * @returns The safe run record.
3149
+ */
3150
+ get: async (threadId, runId, assistantId) => {
3151
+ const response = await this.makeRequest(
3152
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}`
3153
+ );
3154
+ return response.data;
3155
+ },
3156
+ /**
3157
+ * Waits for a run to reach a terminal status (server-capped).
3158
+ * @param threadId - Thread id.
3159
+ * @param runId - Run id.
3160
+ * @param assistantId - Assistant id override (defaults to the client's).
3161
+ * @returns The terminal run record.
3162
+ * @throws {ApiError} On `504 RUN_JOIN_TIMEOUT` or `404 RUN_NOT_FOUND`.
3163
+ */
3164
+ join: async (threadId, runId, assistantId) => {
3165
+ const response = await this.makeRequest(
3166
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}/join`
3167
+ );
3168
+ return response.data;
3169
+ },
3170
+ /**
3171
+ * Requests cancellation of one run.
3172
+ * @param threadId - Thread id.
3173
+ * @param runId - Run id.
3174
+ * @param options - Optional `wait` and `action` (`interrupt` or `rollback`).
3175
+ * @param assistantId - Assistant id override (defaults to the client's).
3176
+ * @returns Acceptance, terminal status, and optional latest run.
3177
+ */
3178
+ cancel: async (threadId, runId, options, assistantId) => {
3179
+ const params = new URLSearchParams();
3180
+ if (options?.action !== void 0)
3181
+ params.set("action", options.action);
3182
+ if (options?.wait !== void 0)
3183
+ params.set("wait", String(options.wait));
3184
+ const query = params.toString();
3185
+ const response = await this.makeRequest(
3186
+ `/api/assistants/${assistantId ?? this.assistantId}/threads/${threadId}/runs/${runId}/cancel${query ? `?${query}` : ""}`,
3187
+ { method: "POST" }
3188
+ );
3189
+ return response;
3190
+ }
3191
+ };
3192
+ /**
3193
+ * Tenant-scoped namespaced key-value store (viewer/editor surface).
3194
+ */
3195
+ this.store = {
3196
+ /**
3197
+ * Creates or replaces a store item.
3198
+ * @param input - Namespace, key, value, optional TTL/index hint.
3199
+ * @returns The persisted item.
3200
+ */
3201
+ put: async (input) => {
3202
+ const response = await this.makeRequest(
3203
+ "/api/store/items",
3204
+ { method: "PUT", body: input }
3205
+ );
3206
+ return response.data;
3207
+ },
3208
+ /**
3209
+ * Reads one item by namespace and key.
3210
+ * @param namespace - Namespace path.
3211
+ * @param key - Item key.
3212
+ * @returns The item.
3213
+ */
3214
+ get: async (namespace, key) => {
3215
+ const params = namespace.map((segment) => `namespace=${encodeURIComponent(segment)}`).concat(`key=${encodeURIComponent(key)}`).join("&");
3216
+ const response = await this.makeRequest(
3217
+ `/api/store/items?${params}`
3218
+ );
3219
+ return response.data;
3220
+ },
3221
+ /**
3222
+ * Deletes one item.
3223
+ * @param namespace - Namespace path.
3224
+ * @param key - Item key.
3225
+ * @returns True when deleted.
3226
+ */
3227
+ delete: async (namespace, key) => {
3228
+ const response = await this.makeRequest(
3229
+ "/api/store/items",
3230
+ { method: "DELETE", body: { namespace, key } }
3231
+ );
3232
+ return response.data?.deleted === true;
3233
+ },
3234
+ /**
3235
+ * Searches items under a namespace prefix.
3236
+ * @param input - Prefix/filter/query/pagination.
3237
+ * @returns Matching items.
3238
+ */
3239
+ search: async (input = {}) => {
3240
+ const response = await this.makeRequest(
3241
+ "/api/store/items/search",
3242
+ { method: "POST", body: input }
3243
+ );
3244
+ return response.data.items;
3245
+ },
3246
+ /**
3247
+ * Lists distinct namespace paths.
3248
+ * @param prefix - Optional namespace prefix.
3249
+ * @param limit - Optional result cap (gateway clamps).
3250
+ * @returns Namespace paths.
3251
+ */
3252
+ namespaces: async (prefix, limit) => {
3253
+ const response = await this.makeRequest(
3254
+ "/api/store/namespaces",
3255
+ {
3256
+ method: "POST",
3257
+ body: {
3258
+ ...prefix === void 0 ? {} : { prefix },
3259
+ ...limit === void 0 ? {} : { limit }
3260
+ }
3261
+ }
3262
+ );
3263
+ return response.data.namespaces;
3264
+ }
3265
+ };
2862
3266
  this.config = {
2863
3267
  timeout: 3e5,
2864
3268
  // Default timeout
@@ -3235,6 +3639,94 @@ var AbstractClient = class {
3235
3639
  });
3236
3640
  return clonedClient;
3237
3641
  }
3642
+ /**
3643
+ * Headers for thread event SSE requests. Concrete clients may add live
3644
+ * tenant/workspace/auth state.
3645
+ *
3646
+ * @returns Request headers.
3647
+ */
3648
+ getThreadEventHeaders() {
3649
+ return { ...this.config.headers ?? {} };
3650
+ }
3651
+ /**
3652
+ * Stream thread-wide projected events over SSE.
3653
+ *
3654
+ * The caller owns reconnection: pass the last `event.seq` as `since`.
3655
+ * There is no automatic retry. Browser WebSocket auth is not covered here;
3656
+ * this SSE path uses `fetch` and the normal Authorization headers.
3657
+ *
3658
+ * @param threadId - Thread id.
3659
+ * @param options - Channel/namespace/depth filters and resume cursor.
3660
+ * @param onEvent - Callback for each projected event.
3661
+ * @param onError - Callback for stream/cursor errors (stream stops).
3662
+ * @returns Abort function.
3663
+ */
3664
+ streamThreadEvents(threadId, options, onEvent, onError) {
3665
+ const controller = new AbortController();
3666
+ const headers = {
3667
+ "Content-Type": "application/json",
3668
+ Accept: "text/event-stream",
3669
+ ...this.getThreadEventHeaders()
3670
+ };
3671
+ void (async () => {
3672
+ try {
3673
+ const response = await fetch(
3674
+ `${this.config.baseURL}/api/assistants/${this.assistantId}/threads/${threadId}/stream/events`,
3675
+ {
3676
+ method: "POST",
3677
+ headers,
3678
+ body: JSON.stringify(options),
3679
+ signal: controller.signal
3680
+ }
3681
+ );
3682
+ if (!response.ok) {
3683
+ const errorData = await response.json().catch(() => ({}));
3684
+ throw Object.assign(
3685
+ new Error(
3686
+ errorData.error ?? errorData.message ?? `HTTP error! Status: ${response.status}`
3687
+ ),
3688
+ { status: response.status, responseBody: errorData }
3689
+ );
3690
+ }
3691
+ if (!response.body)
3692
+ throw new Error("Response body is null");
3693
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true })) {
3694
+ if (frame.event === "error") {
3695
+ const data = frame.data;
3696
+ const error = Object.assign(
3697
+ new Error(typeof data.message === "string" ? data.message : "Thread event stream error"),
3698
+ { code: typeof data.code === "string" ? data.code : "stream_error" }
3699
+ );
3700
+ onError?.(error);
3701
+ return;
3702
+ }
3703
+ const event = frame.data;
3704
+ if (event.type === "event") {
3705
+ onEvent(event);
3706
+ } else if (event.type === "error") {
3707
+ const data = event;
3708
+ const error = Object.assign(
3709
+ new Error(typeof data.message === "string" ? data.message : "Thread event stream error"),
3710
+ { code: typeof data.code === "string" ? data.code : "stream_error" }
3711
+ );
3712
+ onError?.(error);
3713
+ return;
3714
+ }
3715
+ }
3716
+ } catch (error) {
3717
+ if (controller.signal.aborted)
3718
+ return;
3719
+ if (error instanceof DOMException && error.name === "AbortError")
3720
+ return;
3721
+ if (error instanceof SseParseError) {
3722
+ onError?.(Object.assign(new Error(error.message), { code: "INVALID_EVENT" }));
3723
+ return;
3724
+ }
3725
+ onError?.(error instanceof Error ? error : new Error(String(error)));
3726
+ }
3727
+ })();
3728
+ return () => controller.abort();
3729
+ }
3238
3730
  /**
3239
3731
  * Abstract method for streaming API requests
3240
3732
  * To be implemented by concrete client classes
@@ -3309,6 +3801,98 @@ var AbstractClient = class {
3309
3801
  );
3310
3802
  return response.data.records;
3311
3803
  }
3804
+ /**
3805
+ * Reads a thread's run status, pending message count, and interrupts.
3806
+ * @param threadId - Thread identifier.
3807
+ * @returns Thread status projection.
3808
+ */
3809
+ async getThreadStatus(threadId) {
3810
+ const response = await this.makeRequest(
3811
+ `/api/assistants/${this.assistantId}/threads/${threadId}/status`
3812
+ );
3813
+ return response.data;
3814
+ }
3815
+ /**
3816
+ * Reads a page of thread checkpoint history.
3817
+ * @param threadId - Thread identifier.
3818
+ * @param options - Optional limit and before-checkpoint cursor.
3819
+ * @returns Checkpoint snapshots, newest first.
3820
+ */
3821
+ async getThreadHistory(threadId, options = {}) {
3822
+ const params = new URLSearchParams();
3823
+ if (options.limit !== void 0)
3824
+ params.append("limit", String(options.limit));
3825
+ if (options.before !== void 0)
3826
+ params.append("before", options.before);
3827
+ const query = params.toString();
3828
+ const response = await this.makeRequest(
3829
+ `/api/assistants/${this.assistantId}/threads/${threadId}/history${query ? `?${query}` : ""}`
3830
+ );
3831
+ return response.data.history;
3832
+ }
3833
+ /**
3834
+ * Reads the raw snapshot at one checkpoint.
3835
+ * @param threadId - Thread identifier.
3836
+ * @param checkpointId - Checkpoint identifier.
3837
+ * @returns The raw checkpoint snapshot.
3838
+ */
3839
+ async getThreadStateAtCheckpoint(threadId, checkpointId) {
3840
+ const response = await this.makeRequest(
3841
+ `/api/assistants/${this.assistantId}/threads/${threadId}/state/${encodeURIComponent(checkpointId)}`
3842
+ );
3843
+ return response.data;
3844
+ }
3845
+ /**
3846
+ * Reads checkpoint storage accounting for a thread.
3847
+ * @param threadId - Thread identifier.
3848
+ * @returns Storage byte/count projection.
3849
+ */
3850
+ async getThreadStorage(threadId) {
3851
+ const response = await this.makeRequest(
3852
+ `/api/assistants/${this.assistantId}/threads/${threadId}/storage`
3853
+ );
3854
+ return response.data;
3855
+ }
3856
+ /**
3857
+ * Copies a thread's checkpoints and row into a new thread.
3858
+ * @param threadId - Source thread identifier.
3859
+ * @returns The created thread.
3860
+ */
3861
+ async copyThread(threadId) {
3862
+ const response = await this.makeRequest(
3863
+ `/api/assistants/${this.assistantId}/threads/${threadId}/copy`,
3864
+ { method: "POST" }
3865
+ );
3866
+ return response.data;
3867
+ }
3868
+ /**
3869
+ * Prunes a thread's checkpoints or deletes the thread.
3870
+ * @param threadId - Thread identifier.
3871
+ * @param input - Prune strategy and optional keep count.
3872
+ * @returns Prune result.
3873
+ */
3874
+ async pruneThread(threadId, input) {
3875
+ const response = await this.makeRequest(
3876
+ `/api/assistants/${this.assistantId}/threads/${threadId}/prune`,
3877
+ { method: "POST", body: input }
3878
+ );
3879
+ return response.data;
3880
+ }
3881
+ /**
3882
+ * Reads the public gateway info surface.
3883
+ * @returns Service identity, flags, capabilities, endpoints, and metadata.
3884
+ */
3885
+ async getInfo() {
3886
+ const response = await this.makeRequest("/info");
3887
+ return response.data;
3888
+ }
3889
+ /**
3890
+ * Reads the current gateway replica's runtime metrics.
3891
+ * @returns Run counts, pending threads, worker posture, and chunk posture.
3892
+ */
3893
+ async getSystemMetrics() {
3894
+ return this.makeRequest("/metrics?format=json");
3895
+ }
3312
3896
  /**
3313
3897
  * Deletes a thread
3314
3898
  * @deprecated Use threads.delete() instead
@@ -3801,6 +4385,7 @@ var ProjectRoomsClient = class {
3801
4385
  method: "POST",
3802
4386
  body: {
3803
4387
  ...target,
4388
+ ...input.interruptId === void 0 ? {} : { interruptId: input.interruptId },
3804
4389
  ...input.answers === void 0 ? {} : { answers: input.answers }
3805
4390
  }
3806
4391
  });
@@ -3936,114 +4521,6 @@ var WorkspaceMembersClient = class {
3936
4521
  }
3937
4522
  };
3938
4523
 
3939
- // src/sse-parser.ts
3940
- var SseParseError = class extends Error {
3941
- constructor(message) {
3942
- super(message);
3943
- this.code = "INVALID_EVENT";
3944
- this.name = "SseParseError";
3945
- }
3946
- };
3947
- async function* parseSseBody(body, options = {}) {
3948
- const reader = body.getReader();
3949
- const decoder = new TextDecoder();
3950
- let buffer = "";
3951
- let event = "";
3952
- let id;
3953
- let retry;
3954
- let data = [];
3955
- const dispatch = () => {
3956
- if (data.length === 0) {
3957
- event = "";
3958
- id = void 0;
3959
- retry = void 0;
3960
- return void 0;
3961
- }
3962
- let parsed;
3963
- try {
3964
- parsed = JSON.parse(data.join("\n"));
3965
- } catch {
3966
- throw new SseParseError("Invalid SSE JSON");
3967
- }
3968
- if (options.strictJsonObject && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)))
3969
- throw new SseParseError("SSE data must be an object");
3970
- const result = { event, data: parsed, ...id === void 0 ? {} : { id }, ...retry === void 0 ? {} : { retry } };
3971
- event = "";
3972
- id = void 0;
3973
- retry = void 0;
3974
- data = [];
3975
- return result;
3976
- };
3977
- const processLine = (raw) => {
3978
- const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
3979
- if (line === "")
3980
- return dispatch();
3981
- if (line.startsWith(":"))
3982
- return void 0;
3983
- const separator = line.indexOf(":");
3984
- const field = separator < 0 ? line : line.slice(0, separator);
3985
- let value = separator < 0 ? "" : line.slice(separator + 1);
3986
- if (value.startsWith(" "))
3987
- value = value.slice(1);
3988
- if (field === "event")
3989
- event = value;
3990
- else if (field === "data")
3991
- data.push(value);
3992
- else if (field === "id")
3993
- id = value;
3994
- else if (field === "retry") {
3995
- const parsed = Number(value);
3996
- if (!Number.isInteger(parsed) || parsed < 0 || !Number.isFinite(parsed))
3997
- throw new SseParseError("Invalid SSE retry");
3998
- retry = parsed;
3999
- }
4000
- return void 0;
4001
- };
4002
- try {
4003
- while (true) {
4004
- const chunk = await reader.read();
4005
- if (chunk.done) {
4006
- buffer += decoder.decode();
4007
- break;
4008
- }
4009
- buffer += decoder.decode(chunk.value, { stream: true });
4010
- let index = findLineBreak(buffer);
4011
- while (index >= 0) {
4012
- if (buffer[index] === "\r" && index === buffer.length - 1)
4013
- break;
4014
- const frame2 = processLine(buffer.slice(0, index));
4015
- buffer = buffer.slice(index + lineBreakLength(buffer, index));
4016
- if (frame2)
4017
- yield frame2;
4018
- index = findLineBreak(buffer);
4019
- }
4020
- }
4021
- if (buffer) {
4022
- const frame2 = processLine(buffer);
4023
- if (frame2)
4024
- yield frame2;
4025
- }
4026
- const frame = processLine("");
4027
- if (frame)
4028
- yield frame;
4029
- } finally {
4030
- await reader.cancel().catch(() => void 0);
4031
- reader.releaseLock();
4032
- }
4033
- }
4034
- function findLineBreak(value) {
4035
- const lf = value.indexOf("\n");
4036
- const cr = value.indexOf("\r");
4037
- if (lf < 0)
4038
- return cr;
4039
- if (cr < 0)
4040
- return lf;
4041
- return Math.min(lf, cr);
4042
- }
4043
- function lineBreakLength(value, index) {
4044
- return value[index] === "\r" && value[index + 1] === "\n" ? 2 : 1;
4045
- }
4046
-
4047
4524
  // src/room-events.ts
4048
4525
  var invalidFrame = (message) => new ProjectRoomClientError(message, 200, "INVALID_EVENT", false);
4049
4526
  var requiredString3 = (row, field) => {
@@ -4181,6 +4658,8 @@ var _Client = class extends AbstractClient {
4181
4658
  */
4182
4659
  constructor(config) {
4183
4660
  super(config);
4661
+ /** Last SSE event id observed per thread, for automatic resume. */
4662
+ this.resumeEventIds = /* @__PURE__ */ new Map();
4184
4663
  this.headers = {
4185
4664
  "Content-Type": "application/json",
4186
4665
  Authorization: `Bearer ${this.config.apiKey}`,
@@ -4204,7 +4683,7 @@ var _Client = class extends AbstractClient {
4204
4683
  } else {
4205
4684
  const errorData = await response.json().catch(() => ({}));
4206
4685
  throw new ApiError(
4207
- errorData.message || "API Error",
4686
+ errorData.error ?? errorData.message ?? "API Error",
4208
4687
  response.status,
4209
4688
  errorData
4210
4689
  );
@@ -4314,6 +4793,14 @@ var _Client = class extends AbstractClient {
4314
4793
  getWorkspaceHeaders() {
4315
4794
  return { ..._Client.globalWorkspaceHeaders, ...this.workspaceHeaders };
4316
4795
  }
4796
+ /**
4797
+ * Instance-only workspace headers (never merged with the process-global
4798
+ * Console context). Runtime transports use this so a web-app scope cannot
4799
+ * inherit a Console tenant/project selection from another client.
4800
+ */
4801
+ getInstanceWorkspaceHeaders() {
4802
+ return { ...this.workspaceHeaders };
4803
+ }
4317
4804
  /**
4318
4805
  * Get global workspace headers (legacy static API)
4319
4806
  */
@@ -4375,11 +4862,13 @@ var _Client = class extends AbstractClient {
4375
4862
  * @returns A function that can be called to stop the stream
4376
4863
  */
4377
4864
  resumeStream(options, onEvent, onComplete, onError) {
4865
+ const lastEventId = options.lastEventId?.trim() || this.resumeEventIds.get(options.threadId);
4378
4866
  const headers = {
4379
4867
  "Content-Type": "application/json",
4380
4868
  Accept: "text/event-stream",
4381
4869
  ...this.getAllHeaders(),
4382
- ...(0, import_protocols2.threadAffinityHeaders)(options.threadId)
4870
+ ...(0, import_protocols2.threadAffinityHeaders)(options.threadId),
4871
+ ...lastEventId ? { "Last-Event-ID": lastEventId } : {}
4383
4872
  };
4384
4873
  const controller = new AbortController();
4385
4874
  const { signal } = controller;
@@ -4402,15 +4891,27 @@ var _Client = class extends AbstractClient {
4402
4891
  );
4403
4892
  if (!response.ok) {
4404
4893
  const errorData = await response.json().catch(() => ({}));
4405
- throw new Error(
4406
- errorData.error || errorData.message || `HTTP error! Status: ${response.status}`
4894
+ throw Object.assign(
4895
+ new Error(
4896
+ errorData.error || errorData.message || `HTTP error! Status: ${response.status}`
4897
+ ),
4898
+ { status: response.status, responseBody: errorData }
4407
4899
  );
4408
4900
  }
4409
4901
  if (!response.body) {
4410
4902
  throw new Error("Response body is null");
4411
4903
  }
4412
- for await (const frame of parseSseBody(response.body, { strictJsonObject: true }))
4413
- onEvent(frame.data);
4904
+ for await (const frame of parseSseBody(response.body, { strictJsonObject: true })) {
4905
+ if (typeof frame.id === "string" && frame.id !== "") {
4906
+ this.resumeEventIds.set(options.threadId, frame.id);
4907
+ }
4908
+ const chunk = frame.data;
4909
+ if (chunk.type === "error" && chunk.data?.code === "CURSOR_EXPIRED") {
4910
+ this.resumeEventIds.delete(options.threadId);
4911
+ }
4912
+ onEvent(chunk);
4913
+ }
4914
+ this.resumeEventIds.delete(options.threadId);
4414
4915
  if (onComplete) {
4415
4916
  onComplete();
4416
4917
  }
@@ -4424,6 +4925,7 @@ var _Client = class extends AbstractClient {
4424
4925
  }
4425
4926
  })();
4426
4927
  return () => {
4928
+ this.resumeEventIds.delete(options.threadId);
4427
4929
  controller.abort();
4428
4930
  };
4429
4931
  }
@@ -4477,6 +4979,9 @@ var _Client = class extends AbstractClient {
4477
4979
  ...workspaceHeaders
4478
4980
  };
4479
4981
  }
4982
+ getThreadEventHeaders() {
4983
+ return this.getAllHeaders();
4984
+ }
4480
4985
  bodyAffinityHeaders(body) {
4481
4986
  if (!body || typeof body !== "object" || body instanceof FormData)
4482
4987
  return {};
@@ -4589,11 +5094,7 @@ var RuntimeAxiomClient = class extends Client {
4589
5094
  return { "X-Axiom-External-User-Id": this.identity.userId };
4590
5095
  }
4591
5096
  getAllHeaders() {
4592
- const workspace = this.getWorkspaceHeaders();
4593
- return {
4594
- ...this.identityHeaders(),
4595
- ...workspace
4596
- };
5097
+ return { ...this.identityHeaders() };
4597
5098
  }
4598
5099
  async makeRequest(url, options) {
4599
5100
  await this.primeToken();
@@ -4601,7 +5102,7 @@ var RuntimeAxiomClient = class extends Client {
4601
5102
  const affinity = this.bodyAffinityHeaders(options?.body);
4602
5103
  const headers = {
4603
5104
  "Content-Type": "application/json",
4604
- ...this.identityHeaders(),
5105
+ ...this.getAllHeaders(),
4605
5106
  ...affinity,
4606
5107
  ...options?.headers ?? {}
4607
5108
  };