@introspection-sdk/introspection-node 0.4.2 → 0.4.4

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 (219) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/client.d.ts +42 -132
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +67 -366
  5. package/dist/client.js.map +1 -0
  6. package/dist/converters/claude.d.ts +4 -0
  7. package/dist/converters/claude.d.ts.map +1 -1
  8. package/dist/converters/claude.js +7 -0
  9. package/dist/converters/claude.js.map +1 -0
  10. package/dist/converters/gemini.d.ts +90 -0
  11. package/dist/converters/gemini.d.ts.map +1 -0
  12. package/dist/converters/gemini.js +171 -0
  13. package/dist/converters/gemini.js.map +1 -0
  14. package/dist/converters/index.d.ts +1 -1
  15. package/dist/converters/index.d.ts.map +1 -1
  16. package/dist/converters/index.js +2 -1
  17. package/dist/converters/index.js.map +1 -0
  18. package/dist/converters/openai.js +1 -0
  19. package/dist/converters/openai.js.map +1 -0
  20. package/dist/converters/openinference.js +1 -0
  21. package/dist/converters/openinference.js.map +1 -0
  22. package/dist/converters/vercel.d.ts.map +1 -1
  23. package/dist/converters/vercel.js +31 -3
  24. package/dist/converters/vercel.js.map +1 -0
  25. package/dist/http.d.ts +36 -0
  26. package/dist/http.d.ts.map +1 -0
  27. package/dist/http.js +145 -0
  28. package/dist/http.js.map +1 -0
  29. package/dist/index.d.ts +24 -27
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +22 -32
  32. package/dist/index.js.map +1 -0
  33. package/dist/{anthropic.d.ts → otel/anthropic.d.ts} +23 -13
  34. package/dist/otel/anthropic.d.ts.map +1 -0
  35. package/dist/{anthropic.js → otel/anthropic.js} +132 -40
  36. package/dist/otel/anthropic.js.map +1 -0
  37. package/dist/{claude-hooks.d.ts → otel/claude-hooks.d.ts} +19 -1
  38. package/dist/otel/claude-hooks.d.ts.map +1 -0
  39. package/dist/{claude-hooks.js → otel/claude-hooks.js} +94 -20
  40. package/dist/otel/claude-hooks.js.map +1 -0
  41. package/dist/otel/claude-wrapper.d.ts.map +1 -0
  42. package/dist/{claude-wrapper.js → otel/claude-wrapper.js} +2 -1
  43. package/dist/otel/claude-wrapper.js.map +1 -0
  44. package/dist/otel/gemini.d.ts +56 -0
  45. package/dist/otel/gemini.d.ts.map +1 -0
  46. package/dist/otel/gemini.js +348 -0
  47. package/dist/otel/gemini.js.map +1 -0
  48. package/dist/otel/index.d.ts +32 -0
  49. package/dist/otel/index.d.ts.map +1 -0
  50. package/dist/otel/index.js +41 -0
  51. package/dist/otel/index.js.map +1 -0
  52. package/dist/otel/init.d.ts +126 -0
  53. package/dist/otel/init.d.ts.map +1 -0
  54. package/dist/otel/init.js +259 -0
  55. package/dist/otel/init.js.map +1 -0
  56. package/dist/otel/integrations/anthropic.d.ts +10 -0
  57. package/dist/otel/integrations/anthropic.d.ts.map +1 -0
  58. package/dist/otel/integrations/anthropic.js +22 -0
  59. package/dist/otel/integrations/anthropic.js.map +1 -0
  60. package/dist/otel/integrations/base.d.ts +83 -0
  61. package/dist/otel/integrations/base.d.ts.map +1 -0
  62. package/dist/otel/integrations/base.js +23 -0
  63. package/dist/otel/integrations/base.js.map +1 -0
  64. package/dist/otel/integrations/claude-agent.d.ts +13 -0
  65. package/dist/otel/integrations/claude-agent.d.ts.map +1 -0
  66. package/dist/otel/integrations/claude-agent.js +27 -0
  67. package/dist/otel/integrations/claude-agent.js.map +1 -0
  68. package/dist/otel/integrations/gemini.d.ts +11 -0
  69. package/dist/otel/integrations/gemini.d.ts.map +1 -0
  70. package/dist/otel/integrations/gemini.js +21 -0
  71. package/dist/otel/integrations/gemini.js.map +1 -0
  72. package/dist/otel/integrations/index.d.ts +39 -0
  73. package/dist/otel/integrations/index.d.ts.map +1 -0
  74. package/dist/otel/integrations/index.js +131 -0
  75. package/dist/otel/integrations/index.js.map +1 -0
  76. package/dist/otel/integrations/langchain.d.ts +16 -0
  77. package/dist/otel/integrations/langchain.d.ts.map +1 -0
  78. package/dist/otel/integrations/langchain.js +41 -0
  79. package/dist/otel/integrations/langchain.js.map +1 -0
  80. package/dist/otel/integrations/mastra.d.ts +14 -0
  81. package/dist/otel/integrations/mastra.d.ts.map +1 -0
  82. package/dist/otel/integrations/mastra.js +27 -0
  83. package/dist/otel/integrations/mastra.js.map +1 -0
  84. package/dist/otel/integrations/openai-agents.d.ts +11 -0
  85. package/dist/otel/integrations/openai-agents.d.ts.map +1 -0
  86. package/dist/otel/integrations/openai-agents.js +25 -0
  87. package/dist/otel/integrations/openai-agents.js.map +1 -0
  88. package/dist/otel/integrations/pi.d.ts +12 -0
  89. package/dist/otel/integrations/pi.d.ts.map +1 -0
  90. package/dist/otel/integrations/pi.js +20 -0
  91. package/dist/otel/integrations/pi.js.map +1 -0
  92. package/dist/otel/integrations/vercel.d.ts +15 -0
  93. package/dist/otel/integrations/vercel.d.ts.map +1 -0
  94. package/dist/otel/integrations/vercel.js +20 -0
  95. package/dist/otel/integrations/vercel.js.map +1 -0
  96. package/dist/{langchain-handler.d.ts → otel/langchain-handler.d.ts} +10 -1
  97. package/dist/otel/langchain-handler.d.ts.map +1 -0
  98. package/dist/{langchain-handler.js → otel/langchain-handler.js} +43 -6
  99. package/dist/otel/langchain-handler.js.map +1 -0
  100. package/dist/otel/logs.d.ts +82 -0
  101. package/dist/otel/logs.d.ts.map +1 -0
  102. package/dist/otel/logs.js +271 -0
  103. package/dist/otel/logs.js.map +1 -0
  104. package/dist/{mastra-exporter.d.ts → otel/mastra-exporter.d.ts} +3 -1
  105. package/dist/otel/mastra-exporter.d.ts.map +1 -0
  106. package/dist/{mastra-exporter.js → otel/mastra-exporter.js} +71 -17
  107. package/dist/otel/mastra-exporter.js.map +1 -0
  108. package/dist/otel/pi.d.ts +59 -0
  109. package/dist/otel/pi.d.ts.map +1 -0
  110. package/dist/otel/pi.js +67 -0
  111. package/dist/otel/pi.js.map +1 -0
  112. package/dist/otel/register.d.ts +8 -0
  113. package/dist/otel/register.d.ts.map +1 -0
  114. package/dist/otel/register.js +48 -0
  115. package/dist/otel/register.js.map +1 -0
  116. package/dist/otel/setup.d.ts +52 -0
  117. package/dist/otel/setup.d.ts.map +1 -0
  118. package/dist/otel/setup.js +146 -0
  119. package/dist/otel/setup.js.map +1 -0
  120. package/dist/{span-processor.d.ts → otel/span-processor.d.ts} +1 -1
  121. package/dist/otel/span-processor.d.ts.map +1 -0
  122. package/dist/{span-processor.js → otel/span-processor.js} +11 -5
  123. package/dist/otel/span-processor.js.map +1 -0
  124. package/dist/{tracing-processor.d.ts → otel/tracing-processor.d.ts} +4 -1
  125. package/dist/otel/tracing-processor.d.ts.map +1 -0
  126. package/dist/{tracing-processor.js → otel/tracing-processor.js} +64 -14
  127. package/dist/otel/tracing-processor.js.map +1 -0
  128. package/dist/resources/experiments.d.ts +31 -0
  129. package/dist/resources/experiments.d.ts.map +1 -0
  130. package/dist/resources/experiments.js +133 -0
  131. package/dist/resources/experiments.js.map +1 -0
  132. package/dist/resources/recipes.d.ts +22 -0
  133. package/dist/resources/recipes.d.ts.map +1 -0
  134. package/dist/resources/recipes.js +61 -0
  135. package/dist/resources/recipes.js.map +1 -0
  136. package/dist/resources/runtimes.d.ts +76 -0
  137. package/dist/resources/runtimes.d.ts.map +1 -0
  138. package/dist/resources/runtimes.js +179 -0
  139. package/dist/resources/runtimes.js.map +1 -0
  140. package/dist/runner-resources/files.d.ts +35 -0
  141. package/dist/runner-resources/files.d.ts.map +1 -0
  142. package/dist/runner-resources/files.js +131 -0
  143. package/dist/runner-resources/files.js.map +1 -0
  144. package/dist/runner-resources/tasks.d.ts +39 -0
  145. package/dist/runner-resources/tasks.d.ts.map +1 -0
  146. package/dist/runner-resources/tasks.js +129 -0
  147. package/dist/runner-resources/tasks.js.map +1 -0
  148. package/dist/runner.d.ts +80 -0
  149. package/dist/runner.d.ts.map +1 -0
  150. package/dist/runner.js +159 -0
  151. package/dist/runner.js.map +1 -0
  152. package/dist/streaming.d.ts +8 -0
  153. package/dist/streaming.d.ts.map +1 -0
  154. package/dist/streaming.js +67 -0
  155. package/dist/streaming.js.map +1 -0
  156. package/dist/types.js +1 -0
  157. package/dist/types.js.map +1 -0
  158. package/dist/utils.d.ts +10 -0
  159. package/dist/utils.d.ts.map +1 -1
  160. package/dist/utils.js +13 -4
  161. package/dist/utils.js.map +1 -0
  162. package/dist/version.js +1 -0
  163. package/dist/version.js.map +1 -0
  164. package/package.json +91 -22
  165. package/src/client.ts +76 -473
  166. package/src/converters/claude.ts +10 -0
  167. package/src/converters/gemini.ts +243 -0
  168. package/src/converters/index.ts +13 -7
  169. package/src/converters/vercel.ts +41 -3
  170. package/src/http.ts +163 -0
  171. package/src/index.ts +110 -75
  172. package/src/{anthropic.ts → otel/anthropic.ts} +206 -54
  173. package/src/{claude-hooks.ts → otel/claude-hooks.ts} +119 -20
  174. package/src/{claude-wrapper.ts → otel/claude-wrapper.ts} +1 -1
  175. package/src/otel/gemini.ts +491 -0
  176. package/src/otel/index.ts +121 -0
  177. package/src/otel/init.ts +411 -0
  178. package/src/otel/integrations/anthropic.ts +26 -0
  179. package/src/otel/integrations/base.ts +95 -0
  180. package/src/otel/integrations/claude-agent.ts +32 -0
  181. package/src/otel/integrations/gemini.ts +25 -0
  182. package/src/otel/integrations/index.ts +151 -0
  183. package/src/otel/integrations/langchain.ts +45 -0
  184. package/src/otel/integrations/mastra.ts +30 -0
  185. package/src/otel/integrations/openai-agents.ts +31 -0
  186. package/src/otel/integrations/pi.ts +24 -0
  187. package/src/otel/integrations/vercel.ts +24 -0
  188. package/src/{langchain-handler.ts → otel/langchain-handler.ts} +53 -6
  189. package/src/otel/logs.ts +394 -0
  190. package/src/{mastra-exporter.ts → otel/mastra-exporter.ts} +83 -22
  191. package/src/otel/pi.ts +88 -0
  192. package/src/otel/register.ts +50 -0
  193. package/src/otel/setup.ts +215 -0
  194. package/src/{span-processor.ts → otel/span-processor.ts} +11 -6
  195. package/src/{tracing-processor.ts → otel/tracing-processor.ts} +94 -19
  196. package/src/resources/experiments.ts +170 -0
  197. package/src/resources/recipes.ts +73 -0
  198. package/src/resources/runtimes.ts +231 -0
  199. package/src/runner-resources/files.ts +163 -0
  200. package/src/runner-resources/tasks.ts +156 -0
  201. package/src/runner.ts +194 -0
  202. package/src/streaming.ts +57 -0
  203. package/src/utils.ts +12 -5
  204. package/dist/ai-sdk-integration.d.ts +0 -123
  205. package/dist/ai-sdk-integration.d.ts.map +0 -1
  206. package/dist/ai-sdk-integration.js +0 -475
  207. package/dist/anthropic.d.ts.map +0 -1
  208. package/dist/claude-hooks.d.ts.map +0 -1
  209. package/dist/claude-wrapper.d.ts.map +0 -1
  210. package/dist/converters/ai-sdk.d.ts +0 -65
  211. package/dist/converters/ai-sdk.d.ts.map +0 -1
  212. package/dist/converters/ai-sdk.js +0 -261
  213. package/dist/langchain-handler.d.ts.map +0 -1
  214. package/dist/mastra-exporter.d.ts.map +0 -1
  215. package/dist/span-processor.d.ts.map +0 -1
  216. package/dist/tracing-processor.d.ts.map +0 -1
  217. package/src/ai-sdk-integration.ts +0 -691
  218. package/src/converters/ai-sdk.ts +0 -323
  219. /package/dist/{claude-wrapper.d.ts → otel/claude-wrapper.d.ts} +0 -0
@@ -0,0 +1,73 @@
1
+ import type {
2
+ Paginated,
3
+ Recipe,
4
+ RecipeCreate,
5
+ RecipeListParams,
6
+ RecipeUpdate,
7
+ Uuid,
8
+ } from "@introspection-sdk/types";
9
+ import type { HttpClient } from "../http.js";
10
+
11
+ /**
12
+ * Programmatic CRUD for `/v1/recipes` on the CP.
13
+ *
14
+ * Recipes are immutable build artefacts (repository + git ref + commit
15
+ * sha + optional sub-path). They are referenced by runtimes via
16
+ * `runtime.recipe_id` and by experiment arms via `arm.recipe_id`.
17
+ */
18
+ export class RecipesApi {
19
+ constructor(private readonly http: HttpClient) {}
20
+
21
+ list(params: RecipeListParams): Promise<Paginated<Recipe>> {
22
+ return this.http.request<Paginated<Recipe>>({
23
+ method: "GET",
24
+ path: "/v1/recipes",
25
+ query: params as unknown as Record<string, unknown>,
26
+ });
27
+ }
28
+
29
+ /** Async-iterate every page that matches `params`. */
30
+ async *listAll(params: RecipeListParams): AsyncIterable<Recipe> {
31
+ let next: string | undefined = params.next;
32
+ do {
33
+ const page = await this.list({ ...params, next });
34
+ for (const r of page.records) yield r;
35
+ next = page.next ?? undefined;
36
+ } while (next);
37
+ }
38
+
39
+ get(id: Uuid): Promise<Recipe> {
40
+ return this.http.request<Recipe>({
41
+ method: "GET",
42
+ path: `/v1/recipes/${encodeURIComponent(id)}`,
43
+ });
44
+ }
45
+
46
+ create(input: RecipeCreate): Promise<Recipe> {
47
+ return this.http.request<Recipe>({
48
+ method: "POST",
49
+ path: "/v1/recipes",
50
+ body: input,
51
+ });
52
+ }
53
+
54
+ update(id: Uuid, input: RecipeUpdate): Promise<Recipe> {
55
+ return this.http.request<Recipe>({
56
+ method: "PATCH",
57
+ path: `/v1/recipes/${encodeURIComponent(id)}`,
58
+ body: input,
59
+ });
60
+ }
61
+
62
+ delete(id: Uuid): Promise<void> {
63
+ return this.http.request<void>({
64
+ method: "DELETE",
65
+ path: `/v1/recipes/${encodeURIComponent(id)}`,
66
+ expect: "empty",
67
+ });
68
+ }
69
+ }
70
+
71
+ export function attachRecipes(http: HttpClient): RecipesApi {
72
+ return new RecipesApi(http);
73
+ }
@@ -0,0 +1,231 @@
1
+ import type {
2
+ Paginated,
3
+ Recipe,
4
+ RunRequest,
5
+ Runtime,
6
+ RuntimeCreate,
7
+ RuntimeListParams,
8
+ RuntimeUpdate,
9
+ RunnerSpec,
10
+ Uuid,
11
+ } from "@introspection-sdk/types";
12
+ import { NotFoundError } from "@introspection-sdk/types";
13
+ import type { HttpClient } from "../http.js";
14
+ import type { IntrospectionClient } from "../client.js";
15
+ import { Runner, type RunnerSource } from "../runner.js";
16
+
17
+ const UUID_RE =
18
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19
+
20
+ export function isUuid(value: string): boolean {
21
+ return UUID_RE.test(value);
22
+ }
23
+
24
+ export interface RuntimeRunRequestBody {
25
+ identity?: {
26
+ user_id?: string;
27
+ anonymous_id?: string;
28
+ conversation_id?: string;
29
+ };
30
+ ttl_seconds?: number;
31
+ recipe_id?: Uuid;
32
+ }
33
+
34
+ function toRunBody(opts?: RunRequest): RuntimeRunRequestBody | undefined {
35
+ if (!opts) return undefined;
36
+ const out: RuntimeRunRequestBody = {};
37
+ if (opts.identity) out.identity = opts.identity;
38
+ if (opts.ttl_seconds !== undefined) out.ttl_seconds = opts.ttl_seconds;
39
+ if (opts.recipe_id !== undefined) out.recipe_id = opts.recipe_id;
40
+ return out;
41
+ }
42
+
43
+ /**
44
+ * Programmatic CRUD for `/v1/runtimes` on the CP. Mounted on the
45
+ * IntrospectionClient as a callable hybrid (see `RuntimeHandleFactory`).
46
+ */
47
+ export class RuntimesApi {
48
+ constructor(
49
+ private readonly http: HttpClient,
50
+ private readonly client: IntrospectionClient,
51
+ ) {}
52
+
53
+ list(params: RuntimeListParams): Promise<Paginated<Runtime>> {
54
+ return this.http.request<Paginated<Runtime>>({
55
+ method: "GET",
56
+ path: "/v1/runtimes",
57
+ query: params as unknown as Record<string, unknown>,
58
+ });
59
+ }
60
+
61
+ async *listAll(params: RuntimeListParams): AsyncIterable<Runtime> {
62
+ let next: string | undefined = params.next;
63
+ do {
64
+ const page = await this.list({ ...params, next });
65
+ for (const r of page.records) yield r;
66
+ next = page.next ?? undefined;
67
+ } while (next);
68
+ }
69
+
70
+ get(id: Uuid, params: { project_id?: Uuid }): Promise<Runtime> {
71
+ return this.http.request<Runtime>({
72
+ method: "GET",
73
+ path: `/v1/runtimes/${encodeURIComponent(id)}`,
74
+ query: params as Record<string, unknown>,
75
+ });
76
+ }
77
+
78
+ create(input: RuntimeCreate): Promise<Runtime> {
79
+ return this.http.request<Runtime>({
80
+ method: "POST",
81
+ path: "/v1/runtimes",
82
+ body: input,
83
+ });
84
+ }
85
+
86
+ update(id: Uuid, input: RuntimeUpdate): Promise<Runtime> {
87
+ return this.http.request<Runtime>({
88
+ method: "PATCH",
89
+ path: `/v1/runtimes/${encodeURIComponent(id)}`,
90
+ body: input,
91
+ });
92
+ }
93
+
94
+ delete(id: Uuid): Promise<void> {
95
+ return this.http.request<void>({
96
+ method: "DELETE",
97
+ path: `/v1/runtimes/${encodeURIComponent(id)}`,
98
+ expect: "empty",
99
+ });
100
+ }
101
+
102
+ /** Resolve a name to a runtime by querying `/v1/runtimes?name=…`. */
103
+ async resolveByName(name: string, projectId?: Uuid): Promise<Runtime> {
104
+ const page = await this.list({ project_id: projectId, name, limit: 2 });
105
+ const match = page.records.find((r) => r.name === name);
106
+ if (!match) {
107
+ throw new NotFoundError({
108
+ message: `Runtime '${name}' not found${projectId ? ` in project ${projectId}` : ""}`,
109
+ status: 404,
110
+ code: "not_found",
111
+ });
112
+ }
113
+ return match;
114
+ }
115
+
116
+ /** POST `/v1/runtimes/{id}/run` and wrap the result in a `Runner`. */
117
+ async runById(id: Uuid, opts?: RunRequest): Promise<Runner> {
118
+ const spec = await this.http.request<RunnerSpec>({
119
+ method: "POST",
120
+ path: `/v1/runtimes/${encodeURIComponent(id)}/run`,
121
+ body: toRunBody(opts) ?? {},
122
+ });
123
+ const source: RunnerSource = {
124
+ kind: "runtime",
125
+ id,
126
+ options: opts,
127
+ };
128
+ return new Runner(this.client, source, spec);
129
+ }
130
+
131
+ async activateById(
132
+ id: Uuid,
133
+ params?: { project_id?: Uuid },
134
+ ): Promise<Runtime> {
135
+ return this.http.request<Runtime>({
136
+ method: "POST",
137
+ path: `/v1/runtimes/${encodeURIComponent(id)}/activate`,
138
+ query: params as Record<string, unknown> | undefined,
139
+ body: {},
140
+ });
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Handle returned by `client.runtimes(idOrName)`. Resolves the underlying
146
+ * runtime id lazily — if you pass a UUID, no extra lookup happens; if you
147
+ * pass a name, the first call that needs the id will hit
148
+ * `/v1/runtimes?name=…`.
149
+ */
150
+ export class RuntimeHandle {
151
+ private resolvedId: Uuid | null;
152
+ private readonly pinnedRecipeId: Uuid | null;
153
+
154
+ constructor(
155
+ private readonly api: RuntimesApi,
156
+ private readonly client: IntrospectionClient,
157
+ private readonly idOrName: string,
158
+ pinnedRecipeId: Uuid | null = null,
159
+ ) {
160
+ this.resolvedId = isUuid(idOrName) ? idOrName : null;
161
+ this.pinnedRecipeId = pinnedRecipeId;
162
+ }
163
+
164
+ private async resolveId(): Promise<Uuid> {
165
+ if (this.resolvedId) return this.resolvedId;
166
+ const runtime = await this.api.resolveByName(
167
+ this.idOrName,
168
+ this.client.projectId,
169
+ );
170
+ this.resolvedId = runtime.id;
171
+ return runtime.id;
172
+ }
173
+
174
+ /**
175
+ * Pin to a specific recipe — canary a previous version. Subsequent
176
+ * `.run()` calls on the returned handle open a runner against the
177
+ * runtime row in this name whose `recipe_id` matches `recipe.id`
178
+ * (resolved server-side by CP).
179
+ *
180
+ * Returns a new child {@link RuntimeHandle}; the original handle is
181
+ * unaffected. Accepts a {@link Recipe} object (uses `.id`) or a
182
+ * recipe id string.
183
+ */
184
+ pin(recipe: Recipe | string): RuntimeHandle {
185
+ const recipeId = typeof recipe === "string" ? recipe : recipe.id;
186
+ return new RuntimeHandle(this.api, this.client, this.idOrName, recipeId);
187
+ }
188
+
189
+ async run(opts?: RunRequest): Promise<Runner> {
190
+ const id = await this.resolveId();
191
+ const merged: RunRequest | undefined =
192
+ this.pinnedRecipeId !== null
193
+ ? { ...(opts ?? {}), recipe_id: this.pinnedRecipeId }
194
+ : opts;
195
+ return this.api.runById(id, merged);
196
+ }
197
+
198
+ async activate(params?: { projectId?: Uuid }): Promise<Runtime> {
199
+ const id = await this.resolveId();
200
+ return this.api.activateById(id, { project_id: params?.projectId });
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Callable hybrid: `client.runtimes` exposes the CRUD methods of
206
+ * `RuntimesApi` AND can be invoked as a function returning a
207
+ * `RuntimeHandle`. Realised by `attachRuntimes` below.
208
+ */
209
+ export type RuntimeHandleFactory = (idOrName: string) => RuntimeHandle;
210
+
211
+ export function attachRuntimes(
212
+ client: IntrospectionClient,
213
+ http: HttpClient,
214
+ ): RuntimesApi & RuntimeHandleFactory {
215
+ const api = new RuntimesApi(http, client);
216
+ const factory: RuntimeHandleFactory = (idOrName: string) =>
217
+ new RuntimeHandle(api, client, idOrName);
218
+ // Mount the API methods on the factory function. Using bound copies so
219
+ // the methods can be invoked off the proxy without losing `this`.
220
+ const hybrid = factory as RuntimesApi & RuntimeHandleFactory;
221
+ hybrid.list = api.list.bind(api);
222
+ hybrid.listAll = api.listAll.bind(api);
223
+ hybrid.get = api.get.bind(api);
224
+ hybrid.create = api.create.bind(api);
225
+ hybrid.update = api.update.bind(api);
226
+ hybrid.delete = api.delete.bind(api);
227
+ hybrid.resolveByName = api.resolveByName.bind(api);
228
+ hybrid.runById = api.runById.bind(api);
229
+ hybrid.activateById = api.activateById.bind(api);
230
+ return hybrid;
231
+ }
@@ -0,0 +1,163 @@
1
+ import type {
2
+ File as FileResource,
3
+ FileCreateTextParams,
4
+ FileListParams,
5
+ FileType,
6
+ FileUpdateParams,
7
+ ListParams,
8
+ Paginated,
9
+ } from "@introspection-sdk/types";
10
+ import { HttpClient } from "../http.js";
11
+
12
+ export type FileUploadBody =
13
+ | { file: Blob; name?: string; file_type?: FileType }
14
+ | {
15
+ file: Uint8Array;
16
+ name: string;
17
+ file_type?: FileType;
18
+ contentType?: string;
19
+ };
20
+
21
+ export class FileVersionsApi {
22
+ constructor(private readonly http: HttpClient) {}
23
+
24
+ list(fileId: string, params?: ListParams): Promise<Paginated<FileResource>> {
25
+ return this.http.request<Paginated<FileResource>>({
26
+ method: "GET",
27
+ path: `/v1/files/${encodeURIComponent(fileId)}/versions`,
28
+ query: params as Record<string, unknown> | undefined,
29
+ });
30
+ }
31
+
32
+ async *listAll(
33
+ fileId: string,
34
+ params?: ListParams,
35
+ ): AsyncIterable<FileResource> {
36
+ let next: string | undefined = params?.next;
37
+ do {
38
+ const page = await this.list(fileId, { ...params, next });
39
+ for (const f of page.records) yield f;
40
+ next = page.next ?? undefined;
41
+ } while (next);
42
+ }
43
+
44
+ get(fileId: string, versionId: string): Promise<FileResource> {
45
+ return this.http.request<FileResource>({
46
+ method: "GET",
47
+ path: `/v1/files/${encodeURIComponent(fileId)}/versions/${encodeURIComponent(versionId)}`,
48
+ });
49
+ }
50
+
51
+ create(fileId: string, body: FileUploadBody): Promise<FileResource> {
52
+ const form = toFormData(body);
53
+ return this.http.request<FileResource>({
54
+ method: "POST",
55
+ path: `/v1/files/${encodeURIComponent(fileId)}/versions`,
56
+ body: form,
57
+ });
58
+ }
59
+ }
60
+
61
+ export class FilesApi {
62
+ readonly versions: FileVersionsApi;
63
+
64
+ constructor(private readonly http: HttpClient) {
65
+ this.versions = new FileVersionsApi(http);
66
+ }
67
+
68
+ list(params?: FileListParams): Promise<Paginated<FileResource>> {
69
+ return this.http.request<Paginated<FileResource>>({
70
+ method: "GET",
71
+ path: "/v1/files",
72
+ query: params as Record<string, unknown> | undefined,
73
+ });
74
+ }
75
+
76
+ async *listAll(params?: FileListParams): AsyncIterable<FileResource> {
77
+ let next: string | undefined = params?.next;
78
+ do {
79
+ const page = await this.list({ ...params, next });
80
+ for (const f of page.records) yield f;
81
+ next = page.next ?? undefined;
82
+ } while (next);
83
+ }
84
+
85
+ upload(body: FileUploadBody): Promise<FileResource> {
86
+ const form = toFormData(body);
87
+ return this.http.request<FileResource>({
88
+ method: "POST",
89
+ path: "/v1/files",
90
+ body: form,
91
+ });
92
+ }
93
+
94
+ createText(body: FileCreateTextParams): Promise<FileResource> {
95
+ return this.http.request<FileResource>({
96
+ method: "POST",
97
+ path: "/v1/files",
98
+ body,
99
+ });
100
+ }
101
+
102
+ get(fileId: string): Promise<FileResource> {
103
+ return this.http.request<FileResource>({
104
+ method: "GET",
105
+ path: `/v1/files/${encodeURIComponent(fileId)}`,
106
+ });
107
+ }
108
+
109
+ update(fileId: string, body: FileUpdateParams): Promise<FileResource> {
110
+ return this.http.request<FileResource>({
111
+ method: "PATCH",
112
+ path: `/v1/files/${encodeURIComponent(fileId)}`,
113
+ body,
114
+ });
115
+ }
116
+
117
+ delete(fileId: string): Promise<void> {
118
+ return this.http.request<void>({
119
+ method: "DELETE",
120
+ path: `/v1/files/${encodeURIComponent(fileId)}`,
121
+ expect: "empty",
122
+ });
123
+ }
124
+
125
+ download(fileId: string): Promise<Uint8Array> {
126
+ return this.http.request<Uint8Array>({
127
+ method: "GET",
128
+ path: `/v1/files/${encodeURIComponent(fileId)}/content`,
129
+ expect: "bytes",
130
+ });
131
+ }
132
+
133
+ downloadStream(fileId: string): Promise<ReadableStream<Uint8Array>> {
134
+ return this.http.request<ReadableStream<Uint8Array>>({
135
+ method: "GET",
136
+ path: `/v1/files/${encodeURIComponent(fileId)}/content`,
137
+ expect: "stream",
138
+ });
139
+ }
140
+ }
141
+
142
+ function toFormData(body: FileUploadBody): FormData {
143
+ const fd = new FormData();
144
+ if ("file" in body && body.file instanceof Blob) {
145
+ fd.append("file", body.file, body.name);
146
+ } else {
147
+ // Uint8Array branch — copy into a fresh ArrayBuffer so the Blob
148
+ // constructor sees a concrete ArrayBuffer (not ArrayBufferLike,
149
+ // which TS rejects under nodenext lib).
150
+ const u8 = (body as { file: Uint8Array }).file;
151
+ const ct =
152
+ (body as { contentType?: string }).contentType ??
153
+ "application/octet-stream";
154
+ const ab = u8.buffer.slice(
155
+ u8.byteOffset,
156
+ u8.byteOffset + u8.byteLength,
157
+ ) as ArrayBuffer;
158
+ fd.append("file", new Blob([ab], { type: ct }), body.name);
159
+ }
160
+ if (body.name) fd.append("name", body.name);
161
+ if (body.file_type) fd.append("file_type", body.file_type);
162
+ return fd;
163
+ }
@@ -0,0 +1,156 @@
1
+ import type {
2
+ Paginated,
3
+ SseEvent,
4
+ Task,
5
+ TaskCancelResponse,
6
+ TaskCreateParams,
7
+ TaskCreateResponse,
8
+ TaskListParams,
9
+ TaskRun,
10
+ TaskRunCreateParams,
11
+ TaskRunResponse,
12
+ TaskUpdateParams,
13
+ } from "@introspection-sdk/types";
14
+ import { HttpClient } from "../http.js";
15
+ import { parseSse } from "../streaming.js";
16
+
17
+ export interface StartParams extends TaskCreateParams {
18
+ prompt: string; // required for the cursor-style sugar
19
+ }
20
+
21
+ export class RunHandle {
22
+ constructor(
23
+ public readonly task: Task | null,
24
+ public readonly run: TaskRun,
25
+ private readonly runs: TaskRunsApi,
26
+ ) {}
27
+
28
+ stream(): AsyncIterable<SseEvent> {
29
+ return this.runs.stream(this.run.task_id, this.run.id);
30
+ }
31
+
32
+ cancel(): Promise<TaskCancelResponse> {
33
+ return this.runs.cancel(this.run.task_id, this.run.id);
34
+ }
35
+
36
+ /** Convenience: collect `data` from `event: text`-style frames into a string. */
37
+ async text(): Promise<string> {
38
+ let out = "";
39
+ for await (const ev of this.stream()) {
40
+ if (ev.event === "text" || ev.event === "message") out += ev.data;
41
+ }
42
+ return out;
43
+ }
44
+ }
45
+
46
+ export class TaskRunsApi {
47
+ constructor(private readonly http: HttpClient) {}
48
+
49
+ async create(taskId: string, body: TaskRunCreateParams): Promise<RunHandle> {
50
+ const res = await this.http.request<TaskRunResponse>({
51
+ method: "POST",
52
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/runs`,
53
+ body,
54
+ });
55
+ return new RunHandle(null, res.run, this);
56
+ }
57
+
58
+ get(taskId: string, runId: string): Promise<TaskRun> {
59
+ return this.http.request<TaskRun>({
60
+ method: "GET",
61
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/runs/${encodeURIComponent(runId)}`,
62
+ });
63
+ }
64
+
65
+ cancel(taskId: string, runId: string): Promise<TaskCancelResponse> {
66
+ return this.http.request<TaskCancelResponse>({
67
+ method: "POST",
68
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/runs/${encodeURIComponent(runId)}/cancel`,
69
+ });
70
+ }
71
+
72
+ async *stream(taskId: string, runId: string): AsyncIterable<SseEvent> {
73
+ const res = await this.http.stream({
74
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/runs/${encodeURIComponent(runId)}/stream`,
75
+ });
76
+ yield* parseSse(res);
77
+ }
78
+ }
79
+
80
+ export class TasksApi {
81
+ readonly runs: TaskRunsApi;
82
+
83
+ constructor(private readonly http: HttpClient) {
84
+ this.runs = new TaskRunsApi(http);
85
+ }
86
+
87
+ list(params?: TaskListParams): Promise<Paginated<Task>> {
88
+ return this.http.request<Paginated<Task>>({
89
+ method: "GET",
90
+ path: "/v1/tasks",
91
+ query: params as Record<string, unknown> | undefined,
92
+ });
93
+ }
94
+
95
+ async *listAll(params?: TaskListParams): AsyncIterable<Task> {
96
+ let next: string | undefined = params?.next;
97
+ do {
98
+ const page = await this.list({ ...params, next });
99
+ for (const t of page.records) yield t;
100
+ next = page.next ?? undefined;
101
+ } while (next);
102
+ }
103
+
104
+ create(body: TaskCreateParams): Promise<TaskCreateResponse> {
105
+ return this.http.request<TaskCreateResponse>({
106
+ method: "POST",
107
+ path: "/v1/tasks",
108
+ body,
109
+ });
110
+ }
111
+
112
+ get(taskId: string): Promise<Task> {
113
+ return this.http.request<Task>({
114
+ method: "GET",
115
+ path: `/v1/tasks/${encodeURIComponent(taskId)}`,
116
+ });
117
+ }
118
+
119
+ update(taskId: string, body: TaskUpdateParams): Promise<Task> {
120
+ return this.http.request<Task>({
121
+ method: "PATCH",
122
+ path: `/v1/tasks/${encodeURIComponent(taskId)}`,
123
+ body,
124
+ });
125
+ }
126
+
127
+ delete(taskId: string): Promise<void> {
128
+ return this.http.request<void>({
129
+ method: "DELETE",
130
+ path: `/v1/tasks/${encodeURIComponent(taskId)}`,
131
+ expect: "empty",
132
+ });
133
+ }
134
+
135
+ archive(taskId: string): Promise<void> {
136
+ return this.http.request<void>({
137
+ method: "POST",
138
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/archive`,
139
+ expect: "empty",
140
+ });
141
+ }
142
+
143
+ unarchive(taskId: string): Promise<void> {
144
+ return this.http.request<void>({
145
+ method: "POST",
146
+ path: `/v1/tasks/${encodeURIComponent(taskId)}/unarchive`,
147
+ expect: "empty",
148
+ });
149
+ }
150
+
151
+ /** Cursor-style sugar: create a task + return a handle on its initial run. */
152
+ async start(params: StartParams): Promise<RunHandle> {
153
+ const res = await this.create(params);
154
+ return new RunHandle(res.task, res.run, this.runs);
155
+ }
156
+ }