@openhex-ai/agent-sdk 0.0.1
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.
- package/LICENSE +9 -0
- package/README.md +207 -0
- package/dist/index-DOE19uln.d.ts +93 -0
- package/dist/index.d.ts +1218 -0
- package/dist/index.js +987 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/query.ts","../src/http/httpClient.ts","../src/http/sse.ts","../src/http/backoff.ts","../src/chat/events.ts","../src/chat/chatClient.ts","../src/chat/trainingChatClient.ts","../src/workspace/workspaceClient.ts","../src/client.ts","../src/tools/index.ts","../src/hooks.ts"],"sourcesContent":["/**\n * Error types thrown by the Openhex Agent SDK.\n *\n * NOTE: scaffold only — these are the shapes consumers should `catch`;\n * the runtime throws them once wired up.\n */\n\n/** Base class for every error the SDK raises. */\nexport class OpenhexSdkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'OpenhexSdkError';\n }\n}\n\n/** Thrown when no API key is resolvable from options or the environment. */\nexport class AuthenticationError extends OpenhexSdkError {\n constructor(message = 'No Openhex API key provided. Set OPENHEX_API_KEY or pass { apiKey }.') {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/** Thrown when the platform rejects a request (non-2xx response). */\nexport class ApiError extends OpenhexSdkError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\n/** Thrown when an agent run aborts before producing a result. */\nexport class AbortError extends OpenhexSdkError {\n constructor(message = 'The agent run was aborted.') {\n super(message);\n this.name = 'AbortError';\n }\n}\n\n/**\n * Placeholder thrown by every scaffolded entry point until the runtime\n * is implemented. Lets the public surface compile and be imported while\n * making partial wiring obvious at call time.\n */\nexport class NotImplementedError extends OpenhexSdkError {\n constructor(what: string) {\n super(`Not implemented yet: ${what}. This is a scaffold — runtime lands in a follow-up MR.`);\n this.name = 'NotImplementedError';\n }\n}\n","/**\n * Transport layer.\n *\n * The transport is the seam between the SDK's agent loop and the Openhex\n * platform. Swapping it (HTTP today, websocket later, an in-memory fake\n * for tests) leaves the rest of the SDK untouched.\n *\n * NOTE: scaffold only — `HttpTransport` is a stub. The concrete\n * request/stream implementation lands in a follow-up MR.\n */\nimport type { AgentOptions } from './types/options';\nimport type { SDKMessage } from './types/messages';\nimport { NotImplementedError } from './errors';\n\n/** Normalized request to start an agent run. */\nexport interface RunRequest {\n prompt: string;\n options: AgentOptions;\n}\n\n/**\n * A transport knows how to open an agent run against the platform and\n * surface the resulting message stream.\n */\nexport interface Transport {\n /** Start a run and stream back {@link SDKMessage}s as they arrive. */\n run(request: RunRequest): AsyncGenerator<SDKMessage, void, void>;\n}\n\n/** Default transport: talks to the Openhex REST/streaming API over HTTPS. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: { apiKey: string; baseUrl: string }) {}\n\n // eslint-disable-next-line require-yield\n async *run(_request: RunRequest): AsyncGenerator<SDKMessage, void, void> {\n throw new NotImplementedError('HttpTransport.run');\n }\n}\n\n/** Production default base URL for the Openhex platform API. */\nexport const DEFAULT_BASE_URL = 'https://api.openhex.tech';\n","/**\n * The primary entry point: `query`.\n *\n * Runs an agent against the Openhex platform and streams back the\n * resulting messages. Mirrors the Claude Agent SDK's `query` so the\n * ergonomics are familiar:\n *\n * @example\n * import { query } from '@openhex-ai/agent-sdk';\n *\n * for await (const message of query({\n * prompt: 'Summarize the latest support tickets',\n * options: { allowedTools: ['WebSearch', 'Read'] },\n * })) {\n * if (message.type === 'result') console.log(message.result);\n * }\n *\n * NOTE: scaffold only — resolves config and constructs the transport,\n * then defers to it. The transport itself is not implemented yet.\n */\nimport type { AgentOptions } from './types/options';\nimport type { SDKMessage } from './types/messages';\nimport { HttpTransport, DEFAULT_BASE_URL, type Transport } from './transport';\nimport { AuthenticationError } from './errors';\n\nexport interface QueryParams {\n /**\n * The instruction for the agent. A string for a one-shot run, or an\n * async iterable of strings for an interactive/streaming-input session.\n */\n prompt: string | AsyncIterable<string>;\n options?: AgentOptions;\n}\n\n/**\n * The handle returned by {@link query}: an async iterable of\n * {@link SDKMessage}s plus control methods for an in-flight run.\n */\nexport interface Query extends AsyncGenerator<SDKMessage, void, void> {\n /** Cooperatively abort the run. */\n interrupt(): Promise<void>;\n}\n\n/** Resolve the API key from options or the environment, or throw. */\nfunction resolveApiKey(options: AgentOptions): string {\n const key = options.apiKey ?? process.env.OPENHEX_API_KEY;\n if (!key) throw new AuthenticationError();\n return key;\n}\n\n/**\n * Start an agent run. Returns a {@link Query} you iterate to consume the\n * message stream.\n */\nexport function query(params: QueryParams): Query {\n const options = params.options ?? {};\n const apiKey = resolveApiKey(options);\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n\n const transport: Transport = new HttpTransport({ apiKey, baseUrl });\n\n const prompt = typeof params.prompt === 'string' ? params.prompt : '<streaming-input>';\n\n const stream = transport.run({ prompt, options });\n\n const q = stream as Query;\n q.interrupt = async () => {\n await stream.return?.();\n };\n return q;\n}\n","/**\n * Thin HTTP layer for the Openhex platform API.\n *\n * Centralizes base-URL resolution, auth-header injection, JSON\n * (de)serialization, request timeouts, and error mapping so the chat\n * client (and future resource clients) stay focused on protocol logic.\n *\n * Auth mirrors the platform's user-side apps: an `Authorization: Bearer`\n * header carrying either a `mysta_*` API key or a JWT. Optional\n * `X-Login-Type` / `X-Act-As` headers match the app + service-account\n * impersonation paths.\n */\nimport { ApiError, AuthenticationError } from '../errors';\nimport { DEFAULT_BASE_URL } from '../transport';\n\n/** API version prefix every platform route lives under. */\nexport const API_PREFIX = '/api/v2';\n\nexport interface HttpClientConfig {\n /** API key or JWT. Falls back to `OPENHEX_API_KEY` when omitted. */\n apiKey?: string;\n /** Base URL of the platform API. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Login type stamped as `X-Login-Type` (matches the web/app clients).\n * Only relevant for JWT auth; harmless to omit for API-key auth.\n */\n loginType?: string;\n /**\n * Service-account id to impersonate via `X-Act-As`. The caller must own\n * the service account (enforced server-side).\n */\n actAs?: string;\n /** Extra headers merged into every request. */\n headers?: Record<string, string>;\n /** Per-request timeout for non-streaming calls (ms). Default 30_000. */\n timeoutMs?: number;\n /** Override the global fetch (testing / custom agents). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: string;\n /** JSON-serializable request body. */\n body?: unknown;\n /** Extra/override headers for this request. */\n headers?: Record<string, string>;\n /** Caller-supplied abort signal (merged with the timeout signal). */\n signal?: AbortSignal;\n /** Override the default timeout for this request (ms). 0 disables it. */\n timeoutMs?: number;\n}\n\n/** Resolve the API key from explicit config or the environment, or throw. */\nfunction resolveApiKey(apiKey: string | undefined): string {\n const key = apiKey ?? (typeof process !== 'undefined' ? process.env?.OPENHEX_API_KEY : undefined);\n if (!key) throw new AuthenticationError();\n return key;\n}\n\n/** Combine an optional caller signal with a timeout into one signal. */\nfunction withTimeout(\n signal: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n if (!timeoutMs || timeoutMs <= 0) {\n return { signal: signal ?? new AbortController().signal, cancel: () => {} };\n }\n const controller = new AbortController();\n const onAbort = () => controller.abort((signal as AbortSignal & { reason?: unknown })?.reason);\n if (signal) {\n if (signal.aborted) controller.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n}\n\nexport class HttpClient {\n private readonly apiKey: string;\n readonly baseUrl: string;\n private readonly loginType?: string;\n private readonly actAs?: string;\n private readonly extraHeaders: Record<string, string>;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(config: HttpClientConfig = {}) {\n this.apiKey = resolveApiKey(config.apiKey);\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.loginType = config.loginType;\n this.actAs = config.actAs;\n this.extraHeaders = config.headers ?? {};\n this.timeoutMs = config.timeoutMs ?? 30_000;\n const f = config.fetch ?? (typeof fetch !== 'undefined' ? fetch : undefined);\n if (!f) {\n throw new Error('No fetch implementation available. Pass { fetch } in the client config.');\n }\n // Bind so `this` doesn't leak into the platform fetch.\n this.fetchImpl = f.bind(globalThis);\n }\n\n /** Build the full URL for an API path (prefixing `/api/v2` if needed). */\n url(path: string): string {\n if (/^https?:\\/\\//.test(path)) return path;\n const p = path.startsWith('/') ? path : `/${path}`;\n const withPrefix = p.startsWith(API_PREFIX) ? p : `${API_PREFIX}${p}`;\n return `${this.baseUrl}${withPrefix}`;\n }\n\n /** Headers common to every request. `accept` differs for SSE vs JSON. */\n buildHeaders(accept: string, extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: accept,\n ...this.extraHeaders,\n ...extra,\n };\n if (this.loginType) headers['X-Login-Type'] = this.loginType;\n if (this.actAs) headers['X-Act-As'] = this.actAs;\n return headers;\n }\n\n /** Map a non-2xx response to an {@link ApiError}, extracting `detail`. */\n private async toError(response: Response): Promise<ApiError> {\n let body: unknown;\n let detail: string | undefined;\n try {\n body = await response.json();\n detail = (body as { detail?: string })?.detail;\n } catch {\n try {\n detail = await response.text();\n } catch {\n /* ignore */\n }\n }\n if (response.status === 401 || response.status === 403) {\n return new ApiError(detail || 'Unauthorized', response.status, body);\n }\n return new ApiError(detail || `Request failed with status ${response.status}`, response.status, body);\n }\n\n /** Perform a JSON request and parse the response body. */\n async requestJson<T = unknown>(path: string, options: RequestOptions = {}): Promise<T> {\n const response = await this.requestRaw(path, options, 'application/json');\n if (response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n\n /** Perform a request and return the raw {@link Response} (used for SSE). */\n async requestRaw(path: string, options: RequestOptions = {}, accept = 'application/json'): Promise<Response> {\n const { method = 'GET', body, headers, signal } = options;\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const { signal: combined, cancel } = withTimeout(signal, timeoutMs);\n\n const reqHeaders = this.buildHeaders(accept, headers);\n if (body !== undefined) reqHeaders['Content-Type'] = 'application/json';\n\n let response: Response;\n try {\n response = await this.fetchImpl(this.url(path), {\n method,\n headers: reqHeaders,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: combined,\n });\n } finally {\n // For streaming responses we must NOT cancel the timeout here, or it\n // would abort mid-stream — callers of requestRaw for SSE pass\n // timeoutMs:0. For JSON it's already resolved.\n if (accept !== 'text/event-stream') cancel();\n }\n\n if (!response.ok) {\n if (accept !== 'text/event-stream') cancel();\n throw await this.toError(response);\n }\n return response;\n }\n}\n","/**\n * Server-Sent Events parser.\n *\n * Turns a `ReadableStream<Uint8Array>` (a fetch response body) into an\n * async iterable of parsed SSE messages. Handles the platform's wire\n * quirks: `id:` cursor lines, `: heartbeat` / `: <padding>` comment lines\n * (the ALB-flush padding), multi-line `data:` fields, and the `[DONE]`\n * sentinel.\n */\n\nexport interface SSEMessage {\n /** Last `id:` seen — the resumable cursor (Redis stream id). */\n id?: string;\n /** `event:` field, if any. */\n event?: string;\n /** Concatenated `data:` payload (newline-joined per the SSE spec). */\n data: string;\n}\n\n/** Strip exactly one leading space after the colon, per the SSE spec. */\nfunction fieldValue(raw: string): string {\n return raw.startsWith(' ') ? raw.slice(1) : raw;\n}\n\n/**\n * Parse an SSE byte stream into messages. Yields one {@link SSEMessage}\n * per event (blank-line terminated). Comment lines (starting with `:`)\n * are ignored except that they keep the connection's `lastId` intact.\n */\nexport async function* parseSSEStream(\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n): AsyncGenerator<SSEMessage, void, void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let dataLines: string[] = [];\n let eventType: string | undefined;\n let lastId: string | undefined;\n\n const onAbort = () => {\n reader.cancel().catch(() => {});\n };\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete lines; keep the trailing partial in `buffer`.\n let nlIndex: number;\n while ((nlIndex = buffer.indexOf('\\n')) !== -1) {\n let line = buffer.slice(0, nlIndex);\n buffer = buffer.slice(nlIndex + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n\n if (line === '') {\n // Blank line — dispatch the accumulated event.\n if (dataLines.length > 0) {\n yield { id: lastId, event: eventType, data: dataLines.join('\\n') };\n }\n dataLines = [];\n eventType = undefined;\n continue;\n }\n if (line.startsWith(':')) continue; // comment / heartbeat / padding\n\n const colon = line.indexOf(':');\n const field = colon === -1 ? line : line.slice(0, colon);\n const rawVal = colon === -1 ? '' : line.slice(colon + 1);\n const val = fieldValue(rawVal);\n\n switch (field) {\n case 'data':\n dataLines.push(val);\n break;\n case 'id':\n lastId = val;\n break;\n case 'event':\n eventType = val;\n break;\n // `retry` and unknown fields are ignored.\n }\n }\n }\n // Flush a final event with no trailing blank line.\n if (dataLines.length > 0) {\n yield { id: lastId, event: eventType, data: dataLines.join('\\n') };\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n reader.releaseLock();\n }\n}\n","/**\n * Capped exponential backoff — mirrors the web client's SSE reconnect\n * policy (1s → 2s → 4s → 8s → 15s cap) so reconnection behavior matches\n * the user-side apps.\n */\nexport interface BackoffOptions {\n initialMs?: number;\n maxMs?: number;\n factor?: number;\n}\n\nexport class Backoff {\n private attempt = 0;\n private readonly initialMs: number;\n private readonly maxMs: number;\n private readonly factor: number;\n\n constructor(opts: BackoffOptions = {}) {\n this.initialMs = opts.initialMs ?? 1_000;\n this.maxMs = opts.maxMs ?? 15_000;\n this.factor = opts.factor ?? 2;\n }\n\n /** Next delay in ms (advances the attempt counter). */\n next(): number {\n const delay = Math.min(this.maxMs, this.initialMs * Math.pow(this.factor, this.attempt));\n this.attempt += 1;\n return delay;\n }\n\n /** Reset after a successful connection. */\n reset(): void {\n this.attempt = 0;\n }\n}\n\n/** Promise that resolves after `ms`, rejecting if `signal` aborts first. */\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(new DOMException('Aborted', 'AbortError'));\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(new DOMException('Aborted', 'AbortError'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Helpers for interpreting conversation stream records.\n *\n * The wire protocol nests the agent-runtime event inside `record.raw`.\n * These functions encapsulate the discriminants the user-side apps key\n * on (turn completion, text extraction, tool calls) so consumers don't\n * reach into `raw` by hand.\n */\nimport type { ContentBlock } from '../types/messages';\nimport type { ChatStreamRecord } from './types';\n\n/** True when a record is from the agent (1:1 `assistant` or multi-agent `agent`). */\nexport function isAgentRecord(record: ChatStreamRecord): boolean {\n return record.sender === 'assistant' || record.sender === 'agent';\n}\n\n/** True when a record marks the end of an agent turn. */\nexport function isTurnComplete(record: ChatStreamRecord): boolean {\n return isAgentRecord(record) && record.raw?.type === 'result';\n}\n\n/** True when a record is an interruption acknowledgement. */\nexport function isInterrupt(record: ChatStreamRecord): boolean {\n return record.sender === 'system' && (record.raw as { subtype?: string })?.subtype === 'interrupt';\n}\n\n/** Content blocks inside a record's message, if any. */\nfunction contentBlocks(record: ChatStreamRecord): ContentBlock[] {\n const msg = (record.raw as { message?: unknown }).message;\n if (msg && typeof msg === 'object' && Array.isArray((msg as { content?: unknown }).content)) {\n return (msg as { content: ContentBlock[] }).content;\n }\n return [];\n}\n\n/** Extract plain text from a record (empty string if none). */\nexport function extractText(record: ChatStreamRecord): string {\n // A user message can be a bare string.\n if (record.raw?.type === 'user' && typeof (record.raw as { message?: unknown }).message === 'string') {\n return (record.raw as { message: string }).message;\n }\n return contentBlocks(record)\n .filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')\n .map((b) => b.text)\n .join('');\n}\n\n/** Extract tool_use calls from a record (empty array if none). */\nexport function extractToolCalls(\n record: ChatStreamRecord,\n): Array<{ id?: string; name: string; input: Record<string, unknown> }> {\n return contentBlocks(record)\n .filter((b): b is Extract<ContentBlock, { type: 'tool_use' }> => b.type === 'tool_use')\n .map((b) => ({ id: b.id, name: b.name, input: b.input }));\n}\n","/**\n * AgentChatClient — chat with a platform agent over the exact protocol\n * the user-side apps use (`conversationRoutes`).\n *\n * Endpoints (all under `/api/v2`):\n * POST /conversations/send — create/continue a conversation, route a message\n * GET /conversations/:id/stream — SSE record stream (resumable)\n * GET /conversations/:id/messages — full history (JSON)\n * GET /conversations/:id/history — paginated older history (JSON)\n * POST /conversations/:id/interrupt — interrupt the running turn\n *\n * Low-level methods (`send`, `stream`, `messages`, `history`, `interrupt`)\n * map 1:1 to the wire. High-level helpers (`runTurn`, `sendMessage`) add\n * turn isolation (resume the stream from the user message's event id),\n * reconnection, and an idle-timeout for cold-start pod provisioning.\n */\nimport { HttpClient } from '../http/httpClient';\nimport { parseSSEStream, type SSEMessage } from '../http/sse';\nimport { Backoff, delay } from '../http/backoff';\nimport { AbortError } from '../errors';\nimport { extractText, extractToolCalls, isTurnComplete } from './events';\nimport type {\n AgentTurn,\n ChatStreamRecord,\n HistoryPage,\n InterruptResult,\n SendRequest,\n SendResult,\n StreamOptions,\n TurnOptions,\n} from './types';\n\n/** Merge several abort signals into one, with cleanup. */\nfunction anySignal(signals: Array<AbortSignal | undefined>): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const handlers: Array<[AbortSignal, () => void]> = [];\n for (const s of signals) {\n if (!s) continue;\n if (s.aborted) {\n controller.abort((s as AbortSignal & { reason?: unknown }).reason);\n break;\n }\n const handler = () => controller.abort((s as AbortSignal & { reason?: unknown }).reason);\n s.addEventListener('abort', handler, { once: true });\n handlers.push([s, handler]);\n }\n return {\n signal: controller.signal,\n cleanup: () => handlers.forEach(([s, h]) => s.removeEventListener('abort', h)),\n };\n}\n\n/** Parse an SSE message into a {@link ChatStreamRecord}, or null to skip. */\nfunction parseRecord(evt: SSEMessage): ChatStreamRecord | null {\n if (evt.data === '[DONE]') return null;\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(evt.data) as Record<string, unknown>;\n } catch {\n return null;\n }\n // Initial-load pagination marker and error frames aren't records.\n if (parsed._meta === true) return null;\n const record = parsed as unknown as ChatStreamRecord;\n if (evt.id) record.id = evt.id;\n return record;\n}\n\nexport class AgentChatClient {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create or continue a conversation and route a message to its agent(s).\n * Returns immediately (non-blocking); consume {@link stream} for the reply.\n */\n async send(req: SendRequest, opts: { signal?: AbortSignal } = {}): Promise<SendResult> {\n return this.http.requestJson<SendResult>('/conversations/send', {\n method: 'POST',\n body: req,\n signal: opts.signal,\n });\n }\n\n /** Interrupt the conversation's currently-running turn. */\n async interrupt(conversationId: string, opts: { signal?: AbortSignal } = {}): Promise<InterruptResult> {\n return this.http.requestJson<InterruptResult>(`/conversations/${conversationId}/interrupt`, {\n method: 'POST',\n signal: opts.signal,\n });\n }\n\n /** Full conversation history (all messages as JSON). */\n async messages(\n conversationId: string,\n opts: { signal?: AbortSignal } = {},\n ): Promise<{ entries: Array<{ id: string; data: ChatStreamRecord }> }> {\n return this.http.requestJson(`/conversations/${conversationId}/messages`, { signal: opts.signal });\n }\n\n /** A page of older history, before a cursor. */\n async history(\n conversationId: string,\n params: { before: string; turns?: number; maxEntries?: number },\n opts: { signal?: AbortSignal } = {},\n ): Promise<HistoryPage> {\n const q = new URLSearchParams({ before: params.before });\n if (params.turns != null) q.set('turns', String(params.turns));\n if (params.maxEntries != null) q.set('maxEntries', String(params.maxEntries));\n return this.http.requestJson(`/conversations/${conversationId}/history?${q.toString()}`, {\n signal: opts.signal,\n });\n }\n\n /**\n * Open the conversation's SSE record stream. Yields every record\n * (replayed history then live tail), auto-reconnecting with capped\n * backoff on drop. The generator ends when the consumer breaks/returns\n * or `signal` aborts.\n */\n async *stream(\n conversationId: string,\n opts: StreamOptions = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n const { signal, reconnect = true } = opts;\n let cursor = opts.lastEventId;\n const backoff = new Backoff();\n const internal = new AbortController();\n const onAbort = () => internal.abort();\n if (signal) {\n if (signal.aborted) internal.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n const buildPath = () => {\n const q = new URLSearchParams();\n if (cursor) q.set('lastEventId', cursor);\n if (opts.turns != null) q.set('turns', String(opts.turns));\n if (opts.maxEntries != null) q.set('maxEntries', String(opts.maxEntries));\n const qs = q.toString();\n return `/conversations/${conversationId}/stream${qs ? `?${qs}` : ''}`;\n };\n\n try {\n while (!internal.signal.aborted) {\n let body: ReadableStream<Uint8Array> | null = null;\n try {\n const response = await this.http.requestRaw(\n buildPath(),\n { signal: internal.signal, timeoutMs: 0 },\n 'text/event-stream',\n );\n body = response.body as ReadableStream<Uint8Array> | null;\n backoff.reset();\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n await delay(backoff.next(), internal.signal);\n continue;\n }\n\n if (body) {\n try {\n for await (const evt of parseSSEStream(body, internal.signal)) {\n if (evt.data === '[DONE]') return;\n const record = parseRecord(evt);\n if (!record) continue;\n cursor = record.id ?? evt.id ?? cursor;\n yield record;\n }\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n // fall through to reconnect\n }\n }\n\n if (!reconnect || internal.signal.aborted) return;\n await delay(backoff.next(), internal.signal);\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n internal.abort();\n }\n }\n\n /**\n * Stream a single turn over an existing conversation: resume the event\n * stream strictly after `opts.lastEventId` (the user message's event id)\n * and stop at the agent's terminal `result`. Reconnects on drop; an\n * `idleTimeoutMs` gap with no events aborts (covers cold-start pod\n * provisioning). Use when you sent the message yourself via {@link send}.\n */\n async *resumeTurn(\n conversationId: string,\n opts: TurnOptions & { lastEventId?: string } = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n const { signal, idleTimeoutMs = 180_000 } = opts;\n const cursor = opts.lastEventId;\n const idleController = new AbortController();\n const merged = anySignal([signal, idleController.signal]);\n let idleTimer: ReturnType<typeof setTimeout> | undefined;\n const armIdle = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => idleController.abort(new Error('idle timeout')), idleTimeoutMs);\n };\n\n armIdle();\n try {\n for await (const record of this.stream(conversationId, {\n lastEventId: cursor,\n signal: merged.signal,\n })) {\n armIdle();\n yield record;\n if (isTurnComplete(record)) return;\n }\n if (idleController.signal.aborted && !signal?.aborted) {\n throw new AbortError('Turn timed out waiting for the agent to respond.');\n }\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n merged.cleanup();\n idleController.abort();\n }\n }\n\n /**\n * Send a message and stream just this turn's records, ending when the\n * agent's `result` event arrives.\n *\n * The message is sent first; the stream then resumes precisely from the\n * user message's event id, so only the agent's reply is surfaced — no\n * history, no heuristics. To learn the (possibly new) conversation id\n * while streaming, use {@link sendMessage} or the stateful\n * {@link Conversation}.\n *\n * The first message in a new conversation auto-provisions the agent's\n * pod, so the first turn can take tens of seconds before any record\n * arrives; `idleTimeoutMs` (default 180s) bounds the wait.\n */\n async *runTurn(req: SendRequest, opts: TurnOptions = {}): AsyncGenerator<ChatStreamRecord, void, void> {\n const result = await this.send(req, { signal: opts.signal });\n yield* this.resumeTurn(result.conversationId, { ...opts, lastEventId: result.userEventId });\n }\n\n /**\n * Send a message and resolve with the aggregated turn (assistant text,\n * tool calls, all records, conversation id, and a resume cursor).\n */\n async sendMessage(req: SendRequest, opts: TurnOptions = {}): Promise<AgentTurn> {\n const result = await this.send(req, { signal: opts.signal });\n const turn: AgentTurn = {\n conversationId: result.conversationId,\n text: '',\n toolCalls: [],\n records: [],\n sessionId: null,\n };\n for await (const record of this.resumeTurn(result.conversationId, {\n ...opts,\n lastEventId: result.userEventId,\n })) {\n turn.records.push(record);\n if (record.id) turn.lastEventId = record.id;\n if (record.sessionId) turn.sessionId = record.sessionId;\n if (record.sender === 'assistant' || record.sender === 'agent') {\n turn.text += extractText(record);\n turn.toolCalls.push(...extractToolCalls(record));\n }\n if (isTurnComplete(record)) turn.result = record.raw;\n }\n return turn;\n }\n\n /**\n * Start a stateful conversation handle that remembers its id across\n * turns. The first {@link Conversation.send} creates the conversation\n * (routed to `targetAgentIds`); subsequent sends continue it.\n */\n conversation(opts: { conversationId?: string; targetAgentIds?: string[] } = {}): Conversation {\n return new Conversation(this, opts.conversationId, opts.targetAgentIds);\n }\n}\n\n/**\n * A stateful 1:1 (or multi-agent) conversation. Tracks the conversation\n * id so you can `send` repeated turns without re-passing it, and continues\n * the same chat-group context each time.\n */\nexport class Conversation {\n constructor(\n private readonly client: AgentChatClient,\n private conversationId: string | undefined,\n private readonly targetAgentIds: string[] | undefined,\n ) {}\n\n /** The conversation id, once the first message has been sent. */\n get id(): string | undefined {\n return this.conversationId;\n }\n\n /** Build the send request for the next turn (create vs continue). */\n private buildRequest(message: string, extra?: Partial<SendRequest>): SendRequest {\n return this.conversationId\n ? { message, conversationId: this.conversationId, ...extra }\n : { message, targetAgentIds: this.targetAgentIds, ...extra };\n }\n\n /** Send a turn and resolve with the aggregated result. */\n async send(message: string, opts: TurnOptions & Partial<SendRequest> = {}): Promise<AgentTurn> {\n const turn = await this.client.sendMessage(this.buildRequest(message, opts), opts);\n this.conversationId = turn.conversationId;\n return turn;\n }\n\n /** Send a turn and stream its records as they arrive. */\n async *stream(\n message: string,\n opts: TurnOptions & Partial<SendRequest> = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n // Resolve/lock the conversation id up front so it's known while streaming.\n const sent = await this.client.send(this.buildRequest(message, opts), { signal: opts.signal });\n this.conversationId = sent.conversationId;\n yield* this.client.resumeTurn(sent.conversationId, {\n ...opts,\n lastEventId: sent.userEventId,\n });\n }\n\n /** Interrupt the running turn in this conversation. */\n async interrupt(): Promise<InterruptResult> {\n if (!this.conversationId) return { ok: true, interrupted: false, reason: 'No conversation yet' };\n return this.client.interrupt(this.conversationId);\n }\n}\n","/**\n * Training-mode chat — talk to an agent AS ITS OWNER over the dev/train\n * protocol (the agent runs in CREATION/TRAINING mode, so it can learn:\n * edit skills/knowledge/persona, accept feedback, etc.). This is distinct\n * from {@link AgentChatClient}, which is the user-side conversations\n * protocol.\n *\n * Wire (all under /api/v2, owner/collaborator auth):\n * POST /agents/:id/dev/send — send a training message → { ok, msgId }\n * GET /agents/:id/messages/stream — SSE record stream (seq-keyed, resumable\n * via lastEventId; `turns=1` = latest turn)\n * GET /agents/:id/messages/history — JSON history\n * POST /agents/:id/dev/interrupt — interrupt the running turn\n *\n * The training thread is agent-scoped (one per owner), so there's no\n * conversationId — the agent id IS the thread.\n */\nimport { HttpClient } from '../http/httpClient';\nimport { parseSSEStream, type SSEMessage } from '../http/sse';\nimport { Backoff, delay } from '../http/backoff';\nimport { AbortError } from '../errors';\nimport { isTurnComplete } from './events';\nimport type { ChatStreamRecord, TurnOptions } from './types';\n\nexport interface TrainingSendResult {\n ok: boolean;\n msgId?: string;\n}\n\ninterface TrainingStreamOptions extends TurnOptions {\n /** Resume strictly after this record seq (stringified). */\n lastEventId?: string;\n /** Return only the latest N turns (server-side turn paging). */\n turns?: number;\n reconnect?: boolean;\n}\n\nfunction parseRecord(evt: SSEMessage): ChatStreamRecord | null {\n if (evt.data === '[DONE]') return null;\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(evt.data) as Record<string, unknown>;\n } catch {\n return null;\n }\n if (parsed._meta === true) return null;\n const record = parsed as unknown as ChatStreamRecord;\n if (evt.id) record.id = evt.id;\n return record;\n}\n\n/** A training (owner-mode) chat bound to one agent. */\nexport class TrainingChat {\n constructor(\n private readonly http: HttpClient,\n private readonly agentId: string,\n ) {}\n\n /** Send a training message; the reply streams asynchronously (see {@link stream}). */\n async send(message: string, opts: { signal?: AbortSignal } = {}): Promise<TrainingSendResult> {\n return this.http.requestJson<TrainingSendResult>(\n `/agents/${this.agentId}/dev/send`,\n { method: 'POST', body: { message }, signal: opts.signal },\n );\n }\n\n /** Interrupt the running training turn. */\n async interrupt(opts: { signal?: AbortSignal } = {}): Promise<{ ok: boolean }> {\n return this.http.requestJson<{ ok: boolean }>(\n `/agents/${this.agentId}/dev/interrupt`,\n { method: 'POST', signal: opts.signal },\n );\n }\n\n /**\n * Training transcript (JSON), paginated backward from `before` (a Redis\n * stream id). The endpoint REQUIRES `before`, so we default to a\n * far-future sentinel to fetch the latest turns; pass a real id to page\n * older history.\n */\n async messages(\n opts: { before?: string; signal?: AbortSignal } = {}\n ): Promise<{ entries: Array<{ data?: ChatStreamRecord }>; hasMore?: boolean }> {\n const before = opts.before ?? '99999999999999-0';\n return this.http.requestJson(\n `/agents/${this.agentId}/messages/history?before=${encodeURIComponent(before)}`,\n { signal: opts.signal }\n );\n }\n\n /** Raw SSE record stream of the training thread (replayed + live tail). */\n async *stream(opts: TrainingStreamOptions = {}): AsyncGenerator<ChatStreamRecord, void, void> {\n const { signal, reconnect = true } = opts;\n let cursor = opts.lastEventId;\n const backoff = new Backoff();\n const internal = new AbortController();\n const onAbort = () => internal.abort();\n if (signal) {\n if (signal.aborted) internal.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n const buildPath = () => {\n const q = new URLSearchParams();\n if (cursor) q.set('lastEventId', cursor);\n if (opts.turns != null) q.set('turns', String(opts.turns));\n const qs = q.toString();\n return `/agents/${this.agentId}/messages/stream${qs ? `?${qs}` : ''}`;\n };\n try {\n while (!internal.signal.aborted) {\n let body: ReadableStream<Uint8Array> | null = null;\n try {\n const response = await this.http.requestRaw(\n buildPath(),\n { signal: internal.signal, timeoutMs: 0 },\n 'text/event-stream',\n );\n body = response.body as ReadableStream<Uint8Array> | null;\n backoff.reset();\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n await delay(backoff.next(), internal.signal);\n continue;\n }\n if (body) {\n try {\n for await (const evt of parseSSEStream(body, internal.signal)) {\n if (evt.data === '[DONE]') return;\n const record = parseRecord(evt);\n if (!record) continue;\n cursor = (record.id ?? evt.id ?? cursor) as string | undefined;\n yield record;\n }\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n }\n }\n if (!reconnect || internal.signal.aborted) return;\n await delay(backoff.next(), internal.signal);\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n internal.abort();\n }\n }\n\n /**\n * Send a training message and stream just that turn's records, ending at\n * the agent's terminal `result`. Streams the latest turn (`turns=1`) after\n * the send; an `idleTimeoutMs` gap (default 180s) bounds cold-start waits.\n */\n async *runTurn(message: string, opts: TurnOptions = {}): AsyncGenerator<ChatStreamRecord, void, void> {\n await this.send(message, { signal: opts.signal });\n const { signal, idleTimeoutMs = 180_000 } = opts;\n const idleController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | undefined;\n const combined = new AbortController();\n const onA = () => combined.abort();\n const onIdle = () => combined.abort();\n signal?.addEventListener('abort', onA, { once: true });\n idleController.signal.addEventListener('abort', onIdle, { once: true });\n const armIdle = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => idleController.abort(new Error('idle timeout')), idleTimeoutMs);\n };\n armIdle();\n try {\n for await (const record of this.stream({ turns: 1, signal: combined.signal })) {\n armIdle();\n yield record;\n if (isTurnComplete(record)) return;\n }\n if (idleController.signal.aborted && !signal?.aborted) {\n throw new AbortError('Training turn timed out waiting for the agent.');\n }\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n signal?.removeEventListener('abort', onA);\n combined.abort();\n }\n }\n}\n","/**\n * WorkspaceClient — manage a platform workspace over the partner-facing\n * subset of `/api/v2/workspaces/*` (the same surface the published\n * OpenAPI spec exposes).\n *\n * Endpoints (all under `/api/v2`):\n *\n * Workspace API key (`sk_ws_…`) — partner backend:\n * GET /workspaces/whoami\n * POST /workspaces/:slug/members\n * DELETE /workspaces/:slug/members/:memberId\n * POST /workspaces/:slug/sessions\n *\n * Either auth (owner JWT or workspace API key):\n * GET /workspaces/:slug/members\n * POST /workspaces/:slug/members/:memberId/credits\n *\n * Public (no auth):\n * POST /workspaces/:slug/sms/send\n * POST /workspaces/:slug/sms/verify\n *\n * Deliberately omitted: the 6 owner-JWT admin routes (workspace ledger,\n * insights, per-member ledger, API-key CRUD). They power the SP admin\n * UI in `webapp/src/app/[locale]/(app)/settings/*` and don't appear in\n * the published partner OpenAPI spec (hidden in\n * `mysta-server/src/routes/workspacesOwnerRoutes.ts`). Wrapping them in\n * the SDK would invite partners to call routes the docs say don't exist;\n * with a workspace API key they'd just 401.\n *\n * Auth is the `Bearer` token carried by the underlying {@link HttpClient}.\n * Configure the client with the token the operation needs: a workspace\n * API key for partner calls, or skip the header entirely for the public\n * SMS endpoints.\n *\n * Use {@link WorkspaceClient.workspace} for a slug-bound handle so you\n * don't repeat the slug on every call.\n */\nimport { HttpClient } from '../http/httpClient';\nimport type {\n GrantCreditsRequest,\n GrantCreditsResponse,\n MembersListResponse,\n MintSessionRequest,\n ProvisionMemberRequest,\n ProvisionMemberResponse,\n SessionTokenResponse,\n SmsSendRequest,\n SmsVerifyRequest,\n WorkspaceRequestOptions,\n WorkspaceWhoami,\n} from './types';\n\n/** URL-encode a path segment (slugs/ids are user-controlled). */\nconst seg = (s: string) => encodeURIComponent(s);\n\nexport class WorkspaceClient {\n constructor(private readonly http: HttpClient) {}\n\n // -- Partner (workspace API key) -----------------------------------------\n\n /**\n * Identify the workspace the configured API key belongs to. Solves the\n * bootstrap problem for a new partner who holds only the `sk_ws_…` token\n * but every slug-keyed route needs a slug.\n */\n whoami(opts: WorkspaceRequestOptions = {}): Promise<WorkspaceWhoami> {\n return this.http.requestJson<WorkspaceWhoami>('/workspaces/whoami', { signal: opts.signal });\n }\n\n /**\n * Provision (or look up) a workspace member by SP user reference.\n * Idempotent on `(workspace, sp_user_ref)` — the first call creates the\n * member, later calls return the existing ids (`created: false`).\n */\n provisionMember(\n slug: string,\n body: ProvisionMemberRequest,\n opts: WorkspaceRequestOptions = {},\n ): Promise<ProvisionMemberResponse> {\n return this.http.requestJson<ProvisionMemberResponse>(`/workspaces/${seg(slug)}/members`, {\n method: 'POST',\n body,\n signal: opts.signal,\n });\n }\n\n /** Suspend a member (soft — sets status to `suspended`). */\n async suspendMember(slug: string, memberId: string, opts: WorkspaceRequestOptions = {}): Promise<void> {\n await this.http.requestJson<void>(`/workspaces/${seg(slug)}/members/${seg(memberId)}`, {\n method: 'DELETE',\n signal: opts.signal,\n });\n }\n\n /**\n * Mint a session JWT for an already-provisioned member. The partner\n * authenticates the human on their side, then calls this with the same\n * `sp_user_ref` to get a token the member's client presents to the platform.\n */\n mintSession(\n slug: string,\n body: MintSessionRequest,\n opts: WorkspaceRequestOptions = {},\n ): Promise<SessionTokenResponse> {\n return this.http.requestJson<SessionTokenResponse>(`/workspaces/${seg(slug)}/sessions`, {\n method: 'POST',\n body,\n signal: opts.signal,\n });\n }\n\n // -- Either auth ---------------------------------------------------------\n\n /** List workspace members with current balances (capped at 500). */\n listMembers(slug: string, opts: WorkspaceRequestOptions = {}): Promise<MembersListResponse> {\n return this.http.requestJson<MembersListResponse>(`/workspaces/${seg(slug)}/members`, {\n signal: opts.signal,\n });\n }\n\n /**\n * Grant credits to a member from the workspace pool. Idempotent on\n * `body.idempotency_key` — replays return the original purchase.\n */\n grantCredits(\n slug: string,\n memberId: string,\n body: GrantCreditsRequest,\n opts: WorkspaceRequestOptions = {},\n ): Promise<GrantCreditsResponse> {\n return this.http.requestJson<GrantCreditsResponse>(\n `/workspaces/${seg(slug)}/members/${seg(memberId)}/credits`,\n { method: 'POST', body, signal: opts.signal },\n );\n }\n\n // -- Public (no auth) ----------------------------------------------------\n\n /**\n * Send a one-time SMS verification code for public signup. Requires the\n * workspace to have `public_sms_signup_enabled`.\n */\n async sendSmsCode(slug: string, body: SmsSendRequest, opts: WorkspaceRequestOptions = {}): Promise<void> {\n await this.http.requestJson<void>(`/workspaces/${seg(slug)}/sms/send`, {\n method: 'POST',\n body,\n signal: opts.signal,\n });\n }\n\n /** Verify an SMS code and mint a member session JWT in one shot. */\n verifySmsCode(\n slug: string,\n body: SmsVerifyRequest,\n opts: WorkspaceRequestOptions = {},\n ): Promise<SessionTokenResponse> {\n return this.http.requestJson<SessionTokenResponse>(`/workspaces/${seg(slug)}/sms/verify`, {\n method: 'POST',\n body,\n signal: opts.signal,\n });\n }\n\n /**\n * A slug-bound handle so you don't repeat the slug on every call.\n * `client.workspaces.workspace('acme').listMembers()`.\n */\n workspace(slug: string): Workspace {\n return new Workspace(this, slug);\n }\n}\n\n/**\n * A workspace pinned to one slug. Thin sugar over {@link WorkspaceClient}\n * that drops the leading `slug` argument from every method. `whoami` stays\n * on the parent client (it's key-bound, not slug-bound).\n */\nexport class Workspace {\n constructor(\n private readonly client: WorkspaceClient,\n readonly slug: string,\n ) {}\n\n listMembers(opts?: WorkspaceRequestOptions): Promise<MembersListResponse> {\n return this.client.listMembers(this.slug, opts);\n }\n\n provisionMember(\n body: ProvisionMemberRequest,\n opts?: WorkspaceRequestOptions,\n ): Promise<ProvisionMemberResponse> {\n return this.client.provisionMember(this.slug, body, opts);\n }\n\n suspendMember(memberId: string, opts?: WorkspaceRequestOptions): Promise<void> {\n return this.client.suspendMember(this.slug, memberId, opts);\n }\n\n grantCredits(\n memberId: string,\n body: GrantCreditsRequest,\n opts?: WorkspaceRequestOptions,\n ): Promise<GrantCreditsResponse> {\n return this.client.grantCredits(this.slug, memberId, body, opts);\n }\n\n mintSession(body: MintSessionRequest, opts?: WorkspaceRequestOptions): Promise<SessionTokenResponse> {\n return this.client.mintSession(this.slug, body, opts);\n }\n\n sendSmsCode(body: SmsSendRequest, opts?: WorkspaceRequestOptions): Promise<void> {\n return this.client.sendSmsCode(this.slug, body, opts);\n }\n\n verifySmsCode(body: SmsVerifyRequest, opts?: WorkspaceRequestOptions): Promise<SessionTokenResponse> {\n return this.client.verifySmsCode(this.slug, body, opts);\n }\n}\n","/**\n * `OpenhexClient` — a stateful, higher-level wrapper over the SDK.\n *\n * Pin connection + agent config once, then chat with an agent (`chat`,\n * `sendMessage`, `conversation`), run local-style queries (`query`,\n * scaffold), or manage sessions.\n */\nimport type { AgentOptions, OpenhexConnection } from './types/options';\nimport type { SessionInfo } from './types/session';\nimport type { AgentTurn, ChatStreamRecord, SendRequest, TurnOptions } from './chat/types';\nimport { query, type Query, type QueryParams } from './query';\nimport { HttpClient } from './http/httpClient';\nimport { AgentChatClient, Conversation } from './chat/chatClient';\nimport { TrainingChat } from './chat/trainingChatClient';\nimport { WorkspaceClient, Workspace } from './workspace/workspaceClient';\nimport { NotImplementedError } from './errors';\n\nexport interface OpenhexClientConfig extends OpenhexConnection {\n /** `X-Login-Type` header (matches the web/app clients). JWT auth only. */\n loginType?: string;\n /** Service-account id to impersonate via `X-Act-As` (caller must own it). */\n actAs?: string;\n /** Per-request timeout for non-streaming calls (ms). Default 30_000. */\n timeoutMs?: number;\n /** Override the global fetch (testing / custom runtimes). */\n fetch?: typeof fetch;\n /** Default options merged into every {@link OpenhexClient.query} call. */\n defaultOptions?: Omit<AgentOptions, keyof OpenhexConnection>;\n}\n\nexport class OpenhexClient {\n /** Low- and high-level chat API (conversations protocol). */\n readonly chat: AgentChatClient;\n /**\n * Workspace API (`/api/v2/workspaces/*`) — provision members, mint\n * member sessions, grant credits, read reporting. Auth is whatever\n * token the client is configured with (a `sk_ws_…` workspace API key\n * for partner calls, or the owner's JWT for SP-admin calls).\n */\n readonly workspaces: WorkspaceClient;\n private readonly http: HttpClient;\n\n constructor(private readonly config: OpenhexClientConfig = {}) {\n const http = new HttpClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n loginType: config.loginType,\n actAs: config.actAs,\n timeoutMs: config.timeoutMs,\n fetch: config.fetch,\n });\n this.http = http;\n this.chat = new AgentChatClient(http);\n this.workspaces = new WorkspaceClient(http);\n }\n\n /**\n * A slug-bound workspace handle so you don't repeat the slug on every\n * call. Equivalent to `client.workspaces.workspace(slug)`.\n */\n workspace(slug: string): Workspace {\n return this.workspaces.workspace(slug);\n }\n\n /**\n * Training-mode chat with an agent AS ITS OWNER (the dev/train protocol —\n * the agent runs in CREATION/TRAINING mode and can learn from feedback).\n * Defaults to the client's configured `agentId`; pass one to override.\n */\n training(agentId?: string): TrainingChat {\n const id = agentId ?? this.config.agentId;\n if (!id) {\n throw new Error('training() needs an agent id: set { agentId } on the client or pass one.');\n }\n return new TrainingChat(this.http, id);\n }\n\n /** Default target agents for new conversations (from `config.agentId`). */\n private defaultTargets(opts?: TurnOptions): string[] | undefined {\n if (opts?.targetAgentIds) return opts.targetAgentIds;\n return this.config.agentId ? [this.config.agentId] : undefined;\n }\n\n /** Build a {@link SendRequest} from a message + turn options. */\n private buildRequest(message: string, opts?: TurnOptions): SendRequest {\n if (opts?.conversationId) return { message, conversationId: opts.conversationId };\n const targetAgentIds = this.defaultTargets(opts);\n if (!targetAgentIds) {\n throw new Error(\n 'No target agent: set { agentId } on the client, or pass { targetAgentIds } / { conversationId } in options.',\n );\n }\n return { message, targetAgentIds };\n }\n\n /**\n * Send a message and resolve with the aggregated turn. Creates a new\n * conversation routed to the configured agent unless `opts.conversationId`\n * is given. The returned turn carries `conversationId` to continue.\n */\n sendMessage(message: string, opts: TurnOptions = {}): Promise<AgentTurn> {\n return this.chat.sendMessage(this.buildRequest(message, opts), opts);\n }\n\n /** Stream a single turn's records (see {@link sendMessage}). */\n runTurn(message: string, opts: TurnOptions = {}): AsyncGenerator<ChatStreamRecord, void, void> {\n return this.chat.runTurn(this.buildRequest(message, opts), opts);\n }\n\n /**\n * Start a stateful conversation that remembers its id across turns,\n * defaulting its target agents to the configured agent.\n */\n conversation(opts: { conversationId?: string; targetAgentIds?: string[] } = {}): Conversation {\n return this.chat.conversation({\n conversationId: opts.conversationId,\n targetAgentIds: opts.targetAgentIds ?? this.defaultTargets(),\n });\n }\n\n /**\n * Run an agent query using this client's connection + default options.\n * Per-call `options` are shallow-merged over the client defaults.\n */\n query(params: QueryParams): Query {\n return query({\n prompt: params.prompt,\n options: {\n apiKey: this.config.apiKey,\n baseUrl: this.config.baseUrl,\n agentId: this.config.agentId,\n ...this.config.defaultOptions,\n ...params.options,\n },\n });\n }\n\n /** List recent sessions for the configured agent. */\n async listSessions(): Promise<SessionInfo[]> {\n throw new NotImplementedError('OpenhexClient.listSessions');\n }\n\n /** Fetch metadata for a single session. */\n async getSession(_sessionId: string): Promise<SessionInfo> {\n throw new NotImplementedError('OpenhexClient.getSession');\n }\n\n /** Delete a session and its stored context. */\n async deleteSession(_sessionId: string): Promise<void> {\n throw new NotImplementedError('OpenhexClient.deleteSession');\n }\n}\n","/**\n * Helpers for defining custom in-process tools.\n *\n * Available as a sub-path import:\n * import { tool, createSdkMcpServer } from '@openhex-ai/agent-sdk/tools';\n *\n * NOTE: scaffold only — `tool` and `createSdkMcpServer` build the typed\n * definitions today; the executor that runs them inside the agent loop\n * lands in a follow-up MR.\n */\nimport type { z } from 'zod';\nimport type {\n SdkToolDefinition,\n AnySdkToolDefinition,\n SdkMcpServer,\n ToolResult,\n} from '../types/tools';\n\n/**\n * Define a custom tool with a Zod-typed input schema and an async\n * handler. Bundle the result into a server with {@link createSdkMcpServer}\n * and pass it via `options.mcpServers`.\n *\n * @example\n * const getWeather = tool(\n * 'get_weather',\n * 'Look up the weather for a city',\n * z.object({ city: z.string() }),\n * async ({ city }) => ({ content: [{ type: 'text', text: `Sunny in ${city}` }] }),\n * );\n */\nexport function tool<TSchema extends z.ZodTypeAny>(\n name: string,\n description: string,\n inputSchema: TSchema,\n handler: (\n input: z.infer<TSchema>,\n extra: { signal?: AbortSignal }\n ) => Promise<ToolResult> | ToolResult\n): SdkToolDefinition<TSchema> {\n return { name, description, inputSchema, handler };\n}\n\n/**\n * Bundle one or more {@link tool} definitions into an in-process MCP\n * server that the agent loop can call without spawning a subprocess.\n */\nexport function createSdkMcpServer(config: {\n name: string;\n version?: string;\n tools: AnySdkToolDefinition[];\n}): SdkMcpServer {\n return {\n type: 'sdk',\n name: config.name,\n version: config.version ?? '0.0.1',\n tools: config.tools,\n };\n}\n\nexport type { SdkToolDefinition, SdkMcpServer, ToolResult } from '../types/tools';\n","/**\n * Helpers for wiring lifecycle hooks.\n *\n * NOTE: scaffold only — `hookMatcher` builds the typed config today;\n * dispatch during a run lands in a follow-up MR.\n */\nimport type { HookCallback, HookMatcher } from './types/hooks';\n\n/**\n * Build a {@link HookMatcher}. Pass a regex string to scope the hook to\n * matching tool names (e.g. `\"Edit|Write\"`), or omit it to match all.\n *\n * @example\n * hooks: {\n * PostToolUse: [hookMatcher('Edit|Write', logFileChange)],\n * }\n */\nexport function hookMatcher(matcher: string | undefined, ...hooks: HookCallback[]): HookMatcher {\n return matcher === undefined ? { hooks } : { matcher, hooks };\n}\n"],"mappings":"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","names":["resolveApiKey","delay","parseRecord"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/tools/index.ts
|
|
2
|
+
function tool(name, description, inputSchema, handler) {
|
|
3
|
+
return { name, description, inputSchema, handler };
|
|
4
|
+
}
|
|
5
|
+
function createSdkMcpServer(config) {
|
|
6
|
+
return {
|
|
7
|
+
type: "sdk",
|
|
8
|
+
name: config.name,
|
|
9
|
+
version: config.version ?? "0.0.1",
|
|
10
|
+
tools: config.tools
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
createSdkMcpServer,
|
|
15
|
+
tool
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/index.ts"],"sourcesContent":["/**\n * Helpers for defining custom in-process tools.\n *\n * Available as a sub-path import:\n * import { tool, createSdkMcpServer } from '@openhex-ai/agent-sdk/tools';\n *\n * NOTE: scaffold only — `tool` and `createSdkMcpServer` build the typed\n * definitions today; the executor that runs them inside the agent loop\n * lands in a follow-up MR.\n */\nimport type { z } from 'zod';\nimport type {\n SdkToolDefinition,\n AnySdkToolDefinition,\n SdkMcpServer,\n ToolResult,\n} from '../types/tools';\n\n/**\n * Define a custom tool with a Zod-typed input schema and an async\n * handler. Bundle the result into a server with {@link createSdkMcpServer}\n * and pass it via `options.mcpServers`.\n *\n * @example\n * const getWeather = tool(\n * 'get_weather',\n * 'Look up the weather for a city',\n * z.object({ city: z.string() }),\n * async ({ city }) => ({ content: [{ type: 'text', text: `Sunny in ${city}` }] }),\n * );\n */\nexport function tool<TSchema extends z.ZodTypeAny>(\n name: string,\n description: string,\n inputSchema: TSchema,\n handler: (\n input: z.infer<TSchema>,\n extra: { signal?: AbortSignal }\n ) => Promise<ToolResult> | ToolResult\n): SdkToolDefinition<TSchema> {\n return { name, description, inputSchema, handler };\n}\n\n/**\n * Bundle one or more {@link tool} definitions into an in-process MCP\n * server that the agent loop can call without spawning a subprocess.\n */\nexport function createSdkMcpServer(config: {\n name: string;\n version?: string;\n tools: AnySdkToolDefinition[];\n}): SdkMcpServer {\n return {\n type: 'sdk',\n name: config.name,\n version: config.version ?? '0.0.1',\n tools: config.tools,\n };\n}\n\nexport type { SdkToolDefinition, SdkMcpServer, ToolResult } from '../types/tools';\n"],"mappings":";AA+BO,SAAS,KACd,MACA,aACA,aACA,SAI4B;AAC5B,SAAO,EAAE,MAAM,aAAa,aAAa,QAAQ;AACnD;AAMO,SAAS,mBAAmB,QAIlB;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,OAAO;AAAA,IACb,SAAS,OAAO,WAAW;AAAA,IAC3B,OAAO,OAAO;AAAA,EAChB;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openhex-ai/agent-sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Build AI agents on the Openhex platform. Programmable agent loop, tools, hooks, sessions, and MCP — the same runtime that powers Openhex agents, as a library.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./tools": {
|
|
17
|
+
"types": "./dist/tools/index.d.ts",
|
|
18
|
+
"import": "./dist/tools/index.js",
|
|
19
|
+
"default": "./dist/tools/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"dev": "tsup --watch",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "jest",
|
|
35
|
+
"lint": "eslint --ext .ts src"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"openhex",
|
|
39
|
+
"agent",
|
|
40
|
+
"agent-sdk",
|
|
41
|
+
"ai",
|
|
42
|
+
"llm",
|
|
43
|
+
"mcp",
|
|
44
|
+
"tools"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"zod": "^3.24.4"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/jest": "^30.0.0",
|
|
51
|
+
"@types/node": "^25.9.1",
|
|
52
|
+
"jest": "^30.2.0",
|
|
53
|
+
"ts-jest": "^29.4.6",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
55
|
+
"typescript": "^5.4.2"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20"
|
|
59
|
+
}
|
|
60
|
+
}
|