@zyraxon-ai/sdk 19.0.2

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 (41) hide show
  1. package/README.md +117 -0
  2. package/package.json +59 -0
  3. package/src/client.ts +57 -0
  4. package/src/error-interceptor.ts +51 -0
  5. package/src/gen/client/client.gen.ts +212 -0
  6. package/src/gen/client/index.ts +25 -0
  7. package/src/gen/client/types.gen.ts +222 -0
  8. package/src/gen/client/utils.gen.ts +287 -0
  9. package/src/gen/client.gen.ts +22 -0
  10. package/src/gen/core/auth.gen.ts +41 -0
  11. package/src/gen/core/bodySerializer.gen.ts +74 -0
  12. package/src/gen/core/params.gen.ts +144 -0
  13. package/src/gen/core/pathSerializer.gen.ts +167 -0
  14. package/src/gen/core/queryKeySerializer.gen.ts +111 -0
  15. package/src/gen/core/serverSentEvents.gen.ts +210 -0
  16. package/src/gen/core/types.gen.ts +91 -0
  17. package/src/gen/core/utils.gen.ts +109 -0
  18. package/src/gen/sdk.gen.ts +1197 -0
  19. package/src/gen/types.gen.ts +3907 -0
  20. package/src/index.ts +21 -0
  21. package/src/process.ts +31 -0
  22. package/src/server.ts +134 -0
  23. package/src/v2/client.ts +93 -0
  24. package/src/v2/data.ts +32 -0
  25. package/src/v2/gen/client/client.gen.ts +285 -0
  26. package/src/v2/gen/client/index.ts +25 -0
  27. package/src/v2/gen/client/types.gen.ts +202 -0
  28. package/src/v2/gen/client/utils.gen.ts +289 -0
  29. package/src/v2/gen/client.gen.ts +18 -0
  30. package/src/v2/gen/core/auth.gen.ts +41 -0
  31. package/src/v2/gen/core/bodySerializer.gen.ts +82 -0
  32. package/src/v2/gen/core/params.gen.ts +169 -0
  33. package/src/v2/gen/core/pathSerializer.gen.ts +167 -0
  34. package/src/v2/gen/core/queryKeySerializer.gen.ts +111 -0
  35. package/src/v2/gen/core/serverSentEvents.gen.ts +239 -0
  36. package/src/v2/gen/core/types.gen.ts +86 -0
  37. package/src/v2/gen/core/utils.gen.ts +137 -0
  38. package/src/v2/gen/sdk.gen.ts +7219 -0
  39. package/src/v2/gen/types.gen.ts +13618 -0
  40. package/src/v2/index.ts +23 -0
  41. package/src/v2/server.ts +134 -0
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ export * from "./client.js"
2
+ export * from "./server.js"
3
+
4
+ import { createZyraxonClient } from "./client.js"
5
+ import { createZyraxonServer } from "./server.js"
6
+ import type { ServerOptions } from "./server.js"
7
+
8
+ export async function createZyraxon(options?: ServerOptions) {
9
+ const server = await createZyraxonServer({
10
+ ...options,
11
+ })
12
+
13
+ const client = createZyraxonClient({
14
+ baseUrl: server.url,
15
+ })
16
+
17
+ return {
18
+ client,
19
+ server,
20
+ }
21
+ }
package/src/process.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { type ChildProcess, spawnSync } from "node:child_process"
2
+
3
+ // Duplicated from `packages/zyraxon/src/util/process.ts` because the SDK cannot
4
+ // import `zyraxon` without creating a cycle (`zyraxon` depends on `@zyraxon-ai/sdk`).
5
+ export function stop(proc: ChildProcess) {
6
+ if (proc.exitCode !== null || proc.signalCode !== null) return
7
+ if (process.platform === "win32" && proc.pid) {
8
+ const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true })
9
+ if (!out.error && out.status === 0) return
10
+ }
11
+ proc.kill()
12
+ }
13
+
14
+ export function bindAbort(proc: ChildProcess, signal?: AbortSignal, onAbort?: () => void) {
15
+ if (!signal) return () => {}
16
+ const abort = () => {
17
+ clear()
18
+ stop(proc)
19
+ onAbort?.()
20
+ }
21
+ const clear = () => {
22
+ signal.removeEventListener("abort", abort)
23
+ proc.off("exit", clear)
24
+ proc.off("error", clear)
25
+ }
26
+ signal.addEventListener("abort", abort, { once: true })
27
+ proc.on("exit", clear)
28
+ proc.on("error", clear)
29
+ if (signal.aborted) abort()
30
+ return clear
31
+ }
package/src/server.ts ADDED
@@ -0,0 +1,134 @@
1
+ import launch from "cross-spawn"
2
+ import { type Config } from "./gen/types.gen.js"
3
+ import { stop, bindAbort } from "./process.js"
4
+
5
+ export type ServerOptions = {
6
+ hostname?: string
7
+ port?: number
8
+ signal?: AbortSignal
9
+ timeout?: number
10
+ config?: Config
11
+ }
12
+
13
+ export type TuiOptions = {
14
+ project?: string
15
+ model?: string
16
+ session?: string
17
+ agent?: string
18
+ signal?: AbortSignal
19
+ config?: Config
20
+ }
21
+
22
+ export async function createZyraxonServer(options?: ServerOptions) {
23
+ options = Object.assign(
24
+ {
25
+ hostname: "127.0.0.1",
26
+ port: 4096,
27
+ timeout: 5000,
28
+ },
29
+ options ?? {},
30
+ )
31
+
32
+ const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`]
33
+ if (options.config?.logLevel) args.push(`--log-level=${options.config.logLevel}`)
34
+
35
+ const proc = launch(`zyraxon`, args, {
36
+ env: {
37
+ ...process.env,
38
+ ZYRAXON_CONFIG_CONTENT: JSON.stringify(options.config ?? {}),
39
+ },
40
+ })
41
+ let clear = () => {}
42
+
43
+ const url = await new Promise<string>((resolve, reject) => {
44
+ const id = setTimeout(() => {
45
+ clear()
46
+ stop(proc)
47
+ reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`))
48
+ }, options.timeout)
49
+ let output = ""
50
+ let resolved = false
51
+ proc.stdout?.on("data", (chunk) => {
52
+ if (resolved) return
53
+ output += chunk.toString()
54
+ const lines = output.split("\n")
55
+ for (const line of lines) {
56
+ if (line.startsWith("zyraxon server listening")) {
57
+ const match = line.match(/on\s+(https?:\/\/[^\s]+)/)
58
+ if (!match) {
59
+ clear()
60
+ stop(proc)
61
+ clearTimeout(id)
62
+ reject(new Error(`Failed to parse server url from output: ${line}`))
63
+ return
64
+ }
65
+ clearTimeout(id)
66
+ resolved = true
67
+ resolve(match[1]!)
68
+ return
69
+ }
70
+ }
71
+ })
72
+ proc.stderr?.on("data", (chunk) => {
73
+ output += chunk.toString()
74
+ })
75
+ proc.on("exit", (code) => {
76
+ clearTimeout(id)
77
+ let msg = `Server exited with code ${code}`
78
+ if (output.trim()) {
79
+ msg += `\nServer output: ${output}`
80
+ }
81
+ reject(new Error(msg))
82
+ })
83
+ proc.on("error", (error) => {
84
+ clearTimeout(id)
85
+ reject(error)
86
+ })
87
+ clear = bindAbort(proc, options.signal, () => {
88
+ clearTimeout(id)
89
+ reject(options.signal?.reason)
90
+ })
91
+ })
92
+
93
+ return {
94
+ url,
95
+ close() {
96
+ clear()
97
+ stop(proc)
98
+ },
99
+ }
100
+ }
101
+
102
+ export function createZyraxonTui(options?: TuiOptions) {
103
+ const args = []
104
+
105
+ if (options?.project) {
106
+ args.push(`--project=${options.project}`)
107
+ }
108
+ if (options?.model) {
109
+ args.push(`--model=${options.model}`)
110
+ }
111
+ if (options?.session) {
112
+ args.push(`--session=${options.session}`)
113
+ }
114
+ if (options?.agent) {
115
+ args.push(`--agent=${options.agent}`)
116
+ }
117
+
118
+ const proc = launch(`zyraxon`, args, {
119
+ stdio: "inherit",
120
+ env: {
121
+ ...process.env,
122
+ ZYRAXON_CONFIG_CONTENT: JSON.stringify(options?.config ?? {}),
123
+ },
124
+ })
125
+
126
+ const clear = bindAbort(proc, options?.signal)
127
+
128
+ return {
129
+ close() {
130
+ clear()
131
+ stop(proc)
132
+ },
133
+ }
134
+ }
@@ -0,0 +1,93 @@
1
+ export * from "./gen/types.gen.js"
2
+ export type { FileSystemEntry as LocationFileSystemEntry } from "./gen/types.gen.js"
3
+
4
+ import { createClient } from "./gen/client/client.gen.js"
5
+ import { type Config } from "./gen/client/types.gen.js"
6
+ import { ZyraxonClient } from "./gen/sdk.gen.js"
7
+ import { wrapClientError } from "../error-interceptor.js"
8
+ export { type Config as ZyraxonClientConfig, ZyraxonClient }
9
+
10
+ function pick(value: string | null, fallback?: string, encode?: (value: string) => string) {
11
+ if (!value) return
12
+ if (!fallback) return value
13
+ if (value === fallback) return fallback
14
+ if (encode && value === encode(fallback)) return fallback
15
+ return value
16
+ }
17
+
18
+ function rewrite(request: Request, values: { directory?: string; workspace?: string }) {
19
+ if (request.method !== "GET" && request.method !== "HEAD") return request
20
+
21
+ const url = new URL(request.url)
22
+ let changed = false
23
+
24
+ for (const [name, key] of [
25
+ ["x-zyraxon-directory", "directory"],
26
+ ["x-zyraxon-workspace", "workspace"],
27
+ ] as const) {
28
+ const value = pick(
29
+ request.headers.get(name),
30
+ key === "directory" ? values.directory : values.workspace,
31
+ key === "directory" ? encodeURIComponent : undefined,
32
+ )
33
+ if (!value) continue
34
+ for (const query of url.pathname.startsWith("/api/") ? [key, `location[${key}]`] : [key]) {
35
+ if (!url.searchParams.has(query)) {
36
+ url.searchParams.set(query, value)
37
+ }
38
+ }
39
+ changed = true
40
+ }
41
+
42
+ if (!changed) return request
43
+
44
+ const next = new Request(url, request)
45
+ next.headers.delete("x-zyraxon-directory")
46
+ next.headers.delete("x-zyraxon-workspace")
47
+ return next
48
+ }
49
+
50
+ export function createZyraxonClient(config?: Config & { directory?: string; experimental_workspaceID?: string }) {
51
+ if (!config?.fetch) {
52
+ const customFetch: any = (req: any) => {
53
+ // @ts-ignore
54
+ req.timeout = false
55
+ return fetch(req)
56
+ }
57
+ config = {
58
+ ...config,
59
+ fetch: customFetch,
60
+ }
61
+ }
62
+
63
+ if (config?.directory) {
64
+ config.headers = {
65
+ ...config.headers,
66
+ "x-zyraxon-directory": encodeURIComponent(config.directory),
67
+ }
68
+ }
69
+
70
+ if (config?.experimental_workspaceID) {
71
+ config.headers = {
72
+ ...config.headers,
73
+ "x-zyraxon-workspace": config.experimental_workspaceID,
74
+ }
75
+ }
76
+
77
+ const client = createClient(config)
78
+ client.interceptors.request.use((request) =>
79
+ rewrite(request, {
80
+ directory: config?.directory,
81
+ workspace: config?.experimental_workspaceID,
82
+ }),
83
+ )
84
+ client.interceptors.response.use((response) => {
85
+ const contentType = response.headers.get("content-type")
86
+ if (contentType === "text/html")
87
+ throw new Error("Request is not supported by this version of Zyraxon Server (Server responded with text/html)")
88
+
89
+ return response
90
+ })
91
+ client.interceptors.error.use(wrapClientError)
92
+ return new ZyraxonClient({ client })
93
+ }
package/src/v2/data.ts ADDED
@@ -0,0 +1,32 @@
1
+ import type { Part, UserMessage } from "./client.js"
2
+
3
+ export const message = {
4
+ user(input: Omit<UserMessage, "role" | "time" | "id"> & { parts: Omit<Part, "id" | "sessionID" | "messageID">[] }): {
5
+ info: UserMessage
6
+ parts: Part[]
7
+ } {
8
+ const { parts: _parts, ...rest } = input
9
+
10
+ const info: UserMessage = {
11
+ ...rest,
12
+ id: "asdasd",
13
+ time: {
14
+ created: Date.now(),
15
+ },
16
+ role: "user",
17
+ }
18
+
19
+ return {
20
+ info,
21
+ parts: input.parts.map(
22
+ (part) =>
23
+ ({
24
+ ...part,
25
+ id: "asdasd",
26
+ messageID: info.id,
27
+ sessionID: info.sessionID,
28
+ }) as Part,
29
+ ),
30
+ }
31
+ },
32
+ }
@@ -0,0 +1,285 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ import { createSseClient } from "../core/serverSentEvents.gen.js"
4
+ import type { HttpMethod } from "../core/types.gen.js"
5
+ import { getValidRequestBody } from "../core/utils.gen.js"
6
+ import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen.js"
7
+ import {
8
+ buildUrl,
9
+ createConfig,
10
+ createInterceptors,
11
+ getParseAs,
12
+ mergeConfigs,
13
+ mergeHeaders,
14
+ setAuthParams,
15
+ } from "./utils.gen.js"
16
+
17
+ type ReqInit = Omit<RequestInit, "body" | "headers"> & {
18
+ body?: any
19
+ headers: ReturnType<typeof mergeHeaders>
20
+ }
21
+
22
+ export const createClient = (config: Config = {}): Client => {
23
+ let _config = mergeConfigs(createConfig(), config)
24
+
25
+ const getConfig = (): Config => ({ ..._config })
26
+
27
+ const setConfig = (config: Config): Config => {
28
+ _config = mergeConfigs(_config, config)
29
+ return getConfig()
30
+ }
31
+
32
+ const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>()
33
+
34
+ const beforeRequest = async (options: RequestOptions) => {
35
+ const opts = {
36
+ ..._config,
37
+ ...options,
38
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
39
+ headers: mergeHeaders(_config.headers, options.headers),
40
+ serializedBody: undefined,
41
+ }
42
+
43
+ if (opts.security) {
44
+ await setAuthParams({
45
+ ...opts,
46
+ security: opts.security,
47
+ })
48
+ }
49
+
50
+ if (opts.requestValidator) {
51
+ await opts.requestValidator(opts)
52
+ }
53
+
54
+ if (opts.body !== undefined && opts.bodySerializer) {
55
+ opts.serializedBody = opts.bodySerializer(opts.body)
56
+ }
57
+
58
+ // remove Content-Type header if body is empty to avoid sending invalid requests
59
+ if (opts.body === undefined || opts.serializedBody === "") {
60
+ opts.headers.delete("Content-Type")
61
+ }
62
+
63
+ const url = buildUrl(opts)
64
+
65
+ return { opts, url }
66
+ }
67
+
68
+ const request: Client["request"] = async (options) => {
69
+ // @ts-expect-error
70
+ const { opts, url } = await beforeRequest(options)
71
+ const requestInit: ReqInit = {
72
+ redirect: "follow",
73
+ ...opts,
74
+ body: getValidRequestBody(opts),
75
+ }
76
+
77
+ let request = new Request(url, requestInit)
78
+
79
+ for (const fn of interceptors.request.fns) {
80
+ if (fn) {
81
+ request = await fn(request, opts)
82
+ }
83
+ }
84
+
85
+ // fetch must be assigned here, otherwise it would throw the error:
86
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
87
+ const _fetch = opts.fetch!
88
+ let response: Response
89
+
90
+ try {
91
+ response = await _fetch(request)
92
+ } catch (error) {
93
+ // Handle fetch exceptions (AbortError, network errors, etc.)
94
+ let finalError = error
95
+
96
+ for (const fn of interceptors.error.fns) {
97
+ if (fn) {
98
+ finalError = (await fn(error, undefined as any, request, opts)) as unknown
99
+ }
100
+ }
101
+
102
+ finalError = finalError || ({} as unknown)
103
+
104
+ if (opts.throwOnError) {
105
+ throw finalError
106
+ }
107
+
108
+ // Return error response
109
+ return opts.responseStyle === "data"
110
+ ? undefined
111
+ : {
112
+ error: finalError,
113
+ request,
114
+ response: undefined as any,
115
+ }
116
+ }
117
+
118
+ for (const fn of interceptors.response.fns) {
119
+ if (fn) {
120
+ response = await fn(response, request, opts)
121
+ }
122
+ }
123
+
124
+ const result = {
125
+ request,
126
+ response,
127
+ }
128
+
129
+ if (response.ok) {
130
+ const parseAs =
131
+ (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
132
+
133
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
134
+ let emptyData: any
135
+ switch (parseAs) {
136
+ case "arrayBuffer":
137
+ case "blob":
138
+ case "text":
139
+ emptyData = await response[parseAs]()
140
+ break
141
+ case "formData":
142
+ emptyData = new FormData()
143
+ break
144
+ case "stream":
145
+ emptyData = response.body
146
+ break
147
+ case "json":
148
+ default:
149
+ emptyData = {}
150
+ break
151
+ }
152
+ return opts.responseStyle === "data"
153
+ ? emptyData
154
+ : {
155
+ data: emptyData,
156
+ ...result,
157
+ }
158
+ }
159
+
160
+ let data: any
161
+ switch (parseAs) {
162
+ case "arrayBuffer":
163
+ case "blob":
164
+ case "formData":
165
+ case "text":
166
+ data = await response[parseAs]()
167
+ break
168
+ case "json": {
169
+ // Some servers return 200 with no Content-Length and empty body.
170
+ // response.json() would throw; read as text and parse if non-empty.
171
+ const text = await response.text()
172
+ data = text ? JSON.parse(text) : {}
173
+ break
174
+ }
175
+ case "stream":
176
+ return opts.responseStyle === "data"
177
+ ? response.body
178
+ : {
179
+ data: response.body,
180
+ ...result,
181
+ }
182
+ }
183
+
184
+ if (parseAs === "json") {
185
+ if (opts.responseValidator) {
186
+ await opts.responseValidator(data)
187
+ }
188
+
189
+ if (opts.responseTransformer) {
190
+ data = await opts.responseTransformer(data)
191
+ }
192
+ }
193
+
194
+ return opts.responseStyle === "data"
195
+ ? data
196
+ : {
197
+ data,
198
+ ...result,
199
+ }
200
+ }
201
+
202
+ const textError = await response.text()
203
+ let jsonError: unknown
204
+
205
+ try {
206
+ jsonError = JSON.parse(textError)
207
+ } catch {
208
+ // noop
209
+ }
210
+
211
+ const error = jsonError ?? textError
212
+ let finalError = error
213
+
214
+ for (const fn of interceptors.error.fns) {
215
+ if (fn) {
216
+ finalError = (await fn(error, response, request, opts)) as string
217
+ }
218
+ }
219
+
220
+ finalError = finalError || ({} as string)
221
+
222
+ if (opts.throwOnError) {
223
+ throw finalError
224
+ }
225
+
226
+ // TODO: we probably want to return error and improve types
227
+ return opts.responseStyle === "data"
228
+ ? undefined
229
+ : {
230
+ error: finalError,
231
+ ...result,
232
+ }
233
+ }
234
+
235
+ const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) => request({ ...options, method })
236
+
237
+ const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
238
+ const { opts, url } = await beforeRequest(options)
239
+ return createSseClient({
240
+ ...opts,
241
+ body: opts.body as BodyInit | null | undefined,
242
+ headers: opts.headers as unknown as Record<string, string>,
243
+ method,
244
+ onRequest: async (url, init) => {
245
+ let request = new Request(url, init)
246
+ for (const fn of interceptors.request.fns) {
247
+ if (fn) {
248
+ request = await fn(request, opts)
249
+ }
250
+ }
251
+ return request
252
+ },
253
+ serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined,
254
+ url,
255
+ })
256
+ }
257
+
258
+ return {
259
+ buildUrl,
260
+ connect: makeMethodFn("CONNECT"),
261
+ delete: makeMethodFn("DELETE"),
262
+ get: makeMethodFn("GET"),
263
+ getConfig,
264
+ head: makeMethodFn("HEAD"),
265
+ interceptors,
266
+ options: makeMethodFn("OPTIONS"),
267
+ patch: makeMethodFn("PATCH"),
268
+ post: makeMethodFn("POST"),
269
+ put: makeMethodFn("PUT"),
270
+ request,
271
+ setConfig,
272
+ sse: {
273
+ connect: makeSseFn("CONNECT"),
274
+ delete: makeSseFn("DELETE"),
275
+ get: makeSseFn("GET"),
276
+ head: makeSseFn("HEAD"),
277
+ options: makeSseFn("OPTIONS"),
278
+ patch: makeSseFn("PATCH"),
279
+ post: makeSseFn("POST"),
280
+ put: makeSseFn("PUT"),
281
+ trace: makeSseFn("TRACE"),
282
+ },
283
+ trace: makeMethodFn("TRACE"),
284
+ } as Client
285
+ }
@@ -0,0 +1,25 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ export type { Auth } from "../core/auth.gen.js"
4
+ export type { QuerySerializerOptions } from "../core/bodySerializer.gen.js"
5
+ export {
6
+ formDataBodySerializer,
7
+ jsonBodySerializer,
8
+ urlSearchParamsBodySerializer,
9
+ } from "../core/bodySerializer.gen.js"
10
+ export { buildClientParams } from "../core/params.gen.js"
11
+ export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen.js"
12
+ export { createClient } from "./client.gen.js"
13
+ export type {
14
+ Client,
15
+ ClientOptions,
16
+ Config,
17
+ CreateClientConfig,
18
+ Options,
19
+ RequestOptions,
20
+ RequestResult,
21
+ ResolvedRequestOptions,
22
+ ResponseStyle,
23
+ TDataShape,
24
+ } from "./types.gen.js"
25
+ export { createConfig, mergeHeaders } from "./utils.gen.js"