@databricks/appkit 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/databricks.d.ts +180 -0
- package/dist/agents/databricks.d.ts.map +1 -0
- package/dist/agents/databricks.js +473 -0
- package/dist/agents/databricks.js.map +1 -0
- package/dist/appkit/package.js +1 -1
- package/dist/beta.d.ts +2 -1
- package/dist/beta.js +3 -1
- package/dist/connectors/serving/client.js +27 -2
- package/dist/connectors/serving/client.js.map +1 -1
- package/dist/shared/src/agent.d.ts +72 -0
- package/dist/shared/src/agent.d.ts.map +1 -0
- package/dist/shared/src/index.d.ts +1 -0
- package/package.json +2 -2
- package/sbom.cdx.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"databricks.js","names":["servingStream"],"sources":["../../src/agents/databricks.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentEvent,\n AgentInput,\n AgentRunContext,\n AgentToolDefinition,\n} from \"shared\";\nimport { stream as servingStream } from \"../connectors/serving/client\";\n\n/** Default cap for a single incomplete SSE line tail (DoS guard). */\nconst DEFAULT_MAX_SSE_LINE_CHARS = 1024 * 1024;\n\n/** Default cap for accumulated assistant text from `delta.content`. */\nconst DEFAULT_MAX_STREAM_TEXT_CHARS = 4 * 1024 * 1024;\n\n/** Default cap for accumulated JSON arguments per streamed tool call index. */\nconst DEFAULT_MAX_TOOL_ARGUMENT_CHARS = 2 * 1024 * 1024;\n\n/** Cap text length before running Python-style tool-call regex (ReDoS guard). */\nconst PYTHON_STYLE_TOOL_PARSE_MAX_INPUT = 64 * 1024;\n\n/** Fallback HTTP timeout when the raw fetch adapter path receives no AbortSignal from the runner. */\nconst RAW_FETCH_DEFAULT_TIMEOUT_MS = 120_000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction extractLlamaToolJsonSlice(text: string): string | undefined {\n const start = text.indexOf(\"[{\");\n if (start < 0) return undefined;\n const endBracket = text.lastIndexOf(\"}]\");\n if (endBracket < start) return undefined;\n return text.slice(start, endBracket + 2);\n}\n\n/** OpenAI SSE payload: `{ choices: [{ delta }] }`. */\nfunction openAiChoicesDelta(parsed: unknown): unknown {\n if (!isRecord(parsed)) return undefined;\n const choices = parsed.choices;\n if (!Array.isArray(choices) || choices.length < 1) return undefined;\n const first = choices[0];\n if (!isRecord(first)) return undefined;\n return first.delta;\n}\n\nfunction isStreamingDeltaToolCall(value: unknown): value is DeltaToolCall {\n if (!isRecord(value)) return false;\n return typeof value.index === \"number\";\n}\n\nfunction throwIfExceedsStreamLimit(\n label: string,\n currentLength: number,\n chunk: string,\n max: number,\n): void {\n if (currentLength + chunk.length > max) {\n throw new Error(\n `DatabricksAdapter: ${label} exceeds configured limit (${max} UTF-16 code units)`,\n );\n }\n}\n\n/**\n * Transport shim: given an OpenAI-compatible request body, returns the raw\n * SSE byte stream from the serving endpoint. Injected at construction time so\n * callers can swap in the workspace SDK (factory paths), a bare `fetch`\n * (the raw constructor), or a test fake.\n */\ntype StreamBody = (\n body: Record<string, unknown>,\n signal?: AbortSignal,\n) => Promise<ReadableStream<Uint8Array>>;\n\n/**\n * Escape-hatch options: provide an `endpointUrl` + `authenticate()` and the\n * adapter uses a bare `fetch()` to call it. Useful for tests and for pointing\n * the adapter at non-workspace endpoints (reverse proxies, mocks).\n */\ninterface RawFetchAdapterOptions {\n endpointUrl: string;\n authenticate: () => Promise<Record<string, string>>;\n maxSteps?: number;\n maxTokens?: number;\n /** Max length of one SSE line (including an incomplete tail in the buffer). */\n maxSseLineChars?: number;\n /** Max total length of assistant `delta.content` across the stream. */\n maxStreamTextChars?: number;\n /** Max length of streamed `function.arguments` per tool call index. */\n maxToolArgumentsChars?: number;\n}\n\n/**\n * Preferred options: caller provides the transport function directly.\n * The `fromServingEndpoint` / `fromModelServing` factories use this to route\n * through `connectors/serving/stream`, which centralises URL encoding, auth\n * via the SDK's `apiClient.request`, and any future retries/telemetry.\n */\ninterface StreamBodyAdapterOptions {\n streamBody: StreamBody;\n maxSteps?: number;\n maxTokens?: number;\n maxSseLineChars?: number;\n maxStreamTextChars?: number;\n maxToolArgumentsChars?: number;\n}\n\ntype DatabricksAdapterOptions =\n | RawFetchAdapterOptions\n | StreamBodyAdapterOptions;\n\nfunction isStreamBodyOptions(\n o: DatabricksAdapterOptions,\n): o is StreamBodyAdapterOptions {\n return \"streamBody\" in o;\n}\n\n/**\n * Duck-typed subset of the Databricks SDK `WorkspaceClient`. Callers of\n * `fromServingEndpoint` and `fromModelServing` pass a real `WorkspaceClient`,\n * but we only need the `apiClient.request` surface — so we declare the minimal\n * interface rather than importing the SDK type directly. This keeps the adapter\n * free of a hard compile-time dependency on `@databricks/sdk-experimental`.\n */\ninterface WorkspaceClientLike {\n apiClient: {\n request(options: Record<string, unknown>): Promise<unknown>;\n };\n}\n\ninterface ServingEndpointOptions {\n workspaceClient: WorkspaceClientLike;\n endpointName: string;\n maxSteps?: number;\n maxTokens?: number;\n maxSseLineChars?: number;\n maxStreamTextChars?: number;\n maxToolArgumentsChars?: number;\n}\n\ninterface ModelServingOptions {\n maxSteps?: number;\n maxTokens?: number;\n workspaceClient?: WorkspaceClientLike;\n maxSseLineChars?: number;\n maxStreamTextChars?: number;\n maxToolArgumentsChars?: number;\n}\n\ninterface OpenAIMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string | null;\n tool_calls?: OpenAIToolCall[];\n tool_call_id?: string;\n}\n\ninterface OpenAIToolCall {\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n}\n\ninterface OpenAITool {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: unknown;\n };\n}\n\ninterface DeltaToolCall {\n index: number;\n id?: string;\n type?: string;\n function?: { name?: string; arguments?: string };\n}\n\n/**\n * Adapter that talks directly to Databricks Model Serving `/invocations` endpoint.\n *\n * No dependency on the Vercel AI SDK or LangChain. Uses raw `fetch()` to POST\n * OpenAI-compatible payloads and parses the SSE stream itself. Calls\n * `authenticate()` per-request so tokens are always fresh.\n *\n * Handles both structured `tool_calls` responses and text-based tool call\n * fallback parsing for models that output tool calls as text.\n *\n * @example Using the factory (recommended)\n * ```ts\n * import { createApp, createAgent, agents } from \"@databricks/appkit\";\n * import { DatabricksAdapter } from \"@databricks/appkit/beta\";\n * import { WorkspaceClient } from \"@databricks/sdk-experimental\";\n *\n * const adapter = DatabricksAdapter.fromServingEndpoint({\n * workspaceClient: new WorkspaceClient({}),\n * endpointName: \"my-endpoint\",\n * });\n *\n * await createApp({\n * plugins: [\n * agents({\n * agents: {\n * assistant: createAgent({\n * instructions: \"You are a helpful assistant.\",\n * model: adapter,\n * }),\n * },\n * }),\n * ],\n * });\n * ```\n *\n * @example Using the raw constructor\n * ```ts\n * const adapter = new DatabricksAdapter({\n * endpointUrl: \"https://host/serving-endpoints/my-endpoint/invocations\",\n * authenticate: async () => ({ Authorization: `Bearer ${token}` }),\n * });\n * ```\n */\nexport class DatabricksAdapter implements AgentAdapter {\n private streamBody: StreamBody;\n private maxSteps: number;\n private maxTokens: number;\n private maxSseLineChars: number;\n private maxStreamTextChars: number;\n private maxToolArgumentsChars: number;\n\n constructor(options: DatabricksAdapterOptions) {\n this.maxSteps = options.maxSteps ?? 10;\n this.maxTokens = options.maxTokens ?? 4096;\n this.maxSseLineChars =\n options.maxSseLineChars ?? DEFAULT_MAX_SSE_LINE_CHARS;\n this.maxStreamTextChars =\n options.maxStreamTextChars ?? DEFAULT_MAX_STREAM_TEXT_CHARS;\n this.maxToolArgumentsChars =\n options.maxToolArgumentsChars ?? DEFAULT_MAX_TOOL_ARGUMENT_CHARS;\n\n if (isStreamBodyOptions(options)) {\n this.streamBody = options.streamBody;\n } else {\n const { endpointUrl, authenticate } = options;\n this.streamBody = async (body, signal) => {\n const fetchSignal =\n signal ?? AbortSignal.timeout(RAW_FETCH_DEFAULT_TIMEOUT_MS);\n const authHeaders = await authenticate();\n const response = await fetch(endpointUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n },\n body: JSON.stringify(body),\n signal: fetchSignal,\n });\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n throw new Error(\n `Databricks API error (${response.status}): ${errorText}`,\n );\n }\n if (!response.body) throw new Error(\"No response body\");\n return response.body;\n };\n }\n }\n\n /**\n * Creates a DatabricksAdapter for a Databricks Model Serving endpoint.\n *\n * Routes through the shared `connectors/serving/stream` helper, which\n * delegates to the SDK's `apiClient.request({ raw: true })`. That gives the\n * adapter centralised URL encoding + authentication with the rest of the\n * serving surface — no bespoke `fetch()` + `authenticate()` plumbing.\n */\n static async fromServingEndpoint(\n options: ServingEndpointOptions,\n ): Promise<DatabricksAdapter> {\n const {\n workspaceClient,\n endpointName,\n maxSteps,\n maxTokens,\n maxSseLineChars,\n maxStreamTextChars,\n maxToolArgumentsChars,\n } = options;\n return new DatabricksAdapter({\n streamBody: (body, signal) =>\n // Cast through the structural shape: the connector types\n // `workspaceClient` as the SDK's concrete `WorkspaceClient`, but we\n // only need `apiClient.request`.\n servingStream(\n workspaceClient as unknown as Parameters<typeof servingStream>[0],\n endpointName,\n body,\n signal,\n ),\n maxSteps,\n maxTokens,\n maxSseLineChars,\n maxStreamTextChars,\n maxToolArgumentsChars,\n });\n }\n\n /**\n * Creates a DatabricksAdapter from a Model Serving endpoint name.\n * Auto-creates a WorkspaceClient internally. Reads the endpoint name\n * from the argument or the `DATABRICKS_SERVING_ENDPOINT_NAME` env var.\n *\n * @example\n * ```ts\n * // Reads endpoint from DATABRICKS_SERVING_ENDPOINT_NAME env var\n * const adapter = await DatabricksAdapter.fromModelServing();\n *\n * // Explicit endpoint\n * const adapter = await DatabricksAdapter.fromModelServing(\"my-endpoint\");\n *\n * // With options\n * const adapter = await DatabricksAdapter.fromModelServing(\"my-endpoint\", {\n * maxSteps: 5,\n * maxTokens: 2048,\n * });\n * ```\n */\n static async fromModelServing(\n endpointName?: string,\n options?: ModelServingOptions,\n ): Promise<DatabricksAdapter> {\n const resolvedEndpoint =\n endpointName ?? process.env.DATABRICKS_SERVING_ENDPOINT_NAME;\n\n if (!resolvedEndpoint) {\n throw new Error(\n \"No endpoint name provided and DATABRICKS_SERVING_ENDPOINT_NAME env var is not set. \" +\n \"Pass an endpoint name or set DATABRICKS_SERVING_ENDPOINT_NAME.\",\n );\n }\n\n let workspaceClient: WorkspaceClientLike | undefined =\n options?.workspaceClient;\n if (!workspaceClient) {\n const sdk = await import(\"@databricks/sdk-experimental\");\n workspaceClient = new sdk.WorkspaceClient(\n {},\n ) as unknown as WorkspaceClientLike;\n }\n\n return DatabricksAdapter.fromServingEndpoint({\n workspaceClient,\n endpointName: resolvedEndpoint,\n maxSteps: options?.maxSteps,\n maxTokens: options?.maxTokens,\n maxSseLineChars: options?.maxSseLineChars,\n maxStreamTextChars: options?.maxStreamTextChars,\n maxToolArgumentsChars: options?.maxToolArgumentsChars,\n });\n }\n\n async *run(\n input: AgentInput,\n context: AgentRunContext,\n ): AsyncGenerator<AgentEvent, void, unknown> {\n // Databricks API requires tool names to match [a-zA-Z0-9_-].\n // Our tool names use dots (e.g. \"analytics.query\"), so we swap dots\n // for double-underscores in the wire format and map back on receipt.\n const nameToWire = new Map<string, string>();\n const wireToName = new Map<string, string>();\n for (const tool of input.tools) {\n const wire = tool.name.replace(/\\./g, \"__\");\n if (wireToName.has(wire) && wireToName.get(wire) !== tool.name) {\n throw new Error(\n `Tool name collision: '${tool.name}' and '${wireToName.get(wire)}' both map to wire name '${wire}'`,\n );\n }\n nameToWire.set(tool.name, wire);\n wireToName.set(wire, tool.name);\n }\n\n const tools = this.buildTools(input.tools, nameToWire);\n const messages = this.buildMessages(input.messages, nameToWire);\n\n yield { type: \"status\", status: \"running\" };\n\n for (let step = 0; step < this.maxSteps; step++) {\n if (context.signal?.aborted) break;\n\n const { text, toolCalls } = yield* this.streamCompletion(\n messages,\n tools,\n context,\n );\n\n if (toolCalls.length === 0) {\n const parsed = parseTextToolCalls(text);\n if (parsed.length > 0) {\n yield* this.executeToolCalls(parsed, messages, context, nameToWire);\n continue;\n }\n break;\n }\n\n messages.push({\n role: \"assistant\",\n content: text || null,\n tool_calls: toolCalls,\n });\n\n for (const tc of toolCalls) {\n const wireName = tc.function.name;\n const originalName = wireToName.get(wireName) ?? wireName;\n yield* this.executeSingleTool(tc, originalName, messages, context);\n }\n }\n }\n\n /** Parse wire arguments, emit tool_call / tool_result, append tool messages. */\n private async *executeSingleTool(\n tc: OpenAIToolCall,\n originalName: string,\n messages: OpenAIMessage[],\n context: AgentRunContext,\n ): AsyncGenerator<AgentEvent, void, unknown> {\n let args: unknown;\n try {\n args = JSON.parse(tc.function.arguments);\n } catch {\n args = {};\n }\n\n yield { type: \"tool_call\", callId: tc.id, name: originalName, args };\n\n try {\n const result = await context.executeTool(originalName, args);\n const resultStr =\n typeof result === \"string\" ? result : JSON.stringify(result);\n\n yield { type: \"tool_result\", callId: tc.id, result };\n\n messages.push({\n role: \"tool\",\n content: resultStr,\n tool_call_id: tc.id,\n });\n } catch (error) {\n const errMsg =\n error instanceof Error ? error.message : \"Tool execution failed\";\n\n yield {\n type: \"tool_result\",\n callId: tc.id,\n result: null,\n error: errMsg,\n };\n\n messages.push({\n role: \"tool\",\n content: JSON.stringify({ error: errMsg }),\n tool_call_id: tc.id,\n });\n }\n }\n\n private async *streamCompletion(\n messages: OpenAIMessage[],\n tools: OpenAITool[],\n context: AgentRunContext,\n ): AsyncGenerator<\n AgentEvent,\n { text: string; toolCalls: OpenAIToolCall[] },\n unknown\n > {\n const body: Record<string, unknown> = {\n messages,\n stream: true,\n max_tokens: this.maxTokens,\n };\n\n if (tools.length > 0) {\n body.tools = tools;\n }\n\n let responseBody: ReadableStream<Uint8Array>;\n try {\n responseBody = await this.streamBody(body, context.signal);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Stream request failed\";\n yield { type: \"status\", status: \"error\", error: msg };\n throw err;\n }\n\n const reader = responseBody.getReader();\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let fullText = \"\";\n const toolCallAccumulator = new Map<\n number,\n { id: string; name: string; arguments: string }\n >();\n\n try {\n while (true) {\n if (context.signal?.aborted) break;\n\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n if (buffer.length > this.maxSseLineChars) {\n throw new Error(\n `DatabricksAdapter: SSE line buffer exceeds configured limit (${this.maxSseLineChars} UTF-16 code units)`,\n );\n }\n\n for (const line of lines) {\n if (line.length > this.maxSseLineChars) {\n throw new Error(\n `DatabricksAdapter: SSE line exceeds configured limit (${this.maxSseLineChars} UTF-16 code units)`,\n );\n }\n\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data: \")) continue;\n const data = trimmed.slice(6);\n if (data === \"[DONE]\") continue;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch (parseErr) {\n console.debug(\n \"[DatabricksAdapter] malformed SSE data line JSON\",\n { line: `${data.slice(0, 256)}${data.length > 256 ? \"…\" : \"\"}` },\n parseErr,\n );\n continue;\n }\n\n const deltaUnknown = openAiChoicesDelta(parsed);\n if (!isRecord(deltaUnknown)) continue;\n\n if (typeof deltaUnknown.content === \"string\") {\n const content = deltaUnknown.content;\n throwIfExceedsStreamLimit(\n \"streamed assistant text\",\n fullText.length,\n content,\n this.maxStreamTextChars,\n );\n fullText += content;\n yield { type: \"message_delta\" as const, content };\n }\n\n const toolCallsRaw = deltaUnknown.tool_calls;\n if (!Array.isArray(toolCallsRaw)) continue;\n\n for (const tc of toolCallsRaw) {\n if (!isStreamingDeltaToolCall(tc)) continue;\n const existing = toolCallAccumulator.get(tc.index);\n if (existing) {\n if (tc.function?.arguments) {\n throwIfExceedsStreamLimit(\n \"tool call arguments\",\n existing.arguments.length,\n tc.function.arguments,\n this.maxToolArgumentsChars,\n );\n existing.arguments += tc.function.arguments;\n }\n } else {\n const initial = tc.function?.arguments ?? \"\";\n if (initial.length > this.maxToolArgumentsChars) {\n throw new Error(\n `DatabricksAdapter: tool call arguments exceed configured limit (${this.maxToolArgumentsChars} UTF-16 code units)`,\n );\n }\n toolCallAccumulator.set(tc.index, {\n id: tc.id ?? `call_${tc.index}`,\n name: tc.function?.name ?? \"\",\n arguments: initial,\n });\n }\n }\n }\n }\n } finally {\n try {\n await reader.cancel();\n } catch (cancelErr) {\n console.debug(\n \"[DatabricksAdapter] reader.cancel() failed during teardown\",\n cancelErr,\n );\n }\n try {\n reader.releaseLock();\n } catch (unlockErr) {\n console.debug(\n \"[DatabricksAdapter] reader.releaseLock() failed during teardown\",\n unlockErr,\n );\n }\n }\n\n const toolCalls: OpenAIToolCall[] = Array.from(\n toolCallAccumulator.values(),\n ).map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments || \"{}\" },\n }));\n\n return { text: fullText, toolCalls };\n }\n\n private async *executeToolCalls(\n calls: Array<{ name: string; args: unknown }>,\n messages: OpenAIMessage[],\n context: AgentRunContext,\n nameToWire: Map<string, string>,\n ): AsyncGenerator<AgentEvent, void, unknown> {\n const wireToolName = (name: string) =>\n nameToWire.get(name) ?? name.replace(/\\./g, \"__\");\n\n const toolCallObjs: OpenAIToolCall[] = calls.map((c, i) => ({\n id: `text_call_${i}`,\n type: \"function\" as const,\n function: {\n name: wireToolName(c.name),\n arguments: JSON.stringify(c.args),\n },\n }));\n\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: toolCallObjs,\n });\n\n for (let i = 0; i < toolCallObjs.length; i++) {\n const tc = toolCallObjs[i];\n const originalName = calls[i]?.name ?? tc.function.name;\n yield* this.executeSingleTool(tc, originalName, messages, context);\n }\n }\n\n /**\n * Maps AppKit {@link AgentInput} messages into OpenAI-compatible wire messages.\n * Preserves multi-turn tool state (`toolCalls` → `tool_calls`, `toolCallId` →\n * `tool_call_id`) so resumed threads and hydrated history reach the model.\n */\n private buildMessages(\n messages: AgentInput[\"messages\"],\n nameToWire: Map<string, string>,\n ): OpenAIMessage[] {\n const wireToolName = (name: string) =>\n nameToWire.get(name) ?? name.replace(/\\./g, \"__\");\n\n return messages.map((m) => {\n let content: string | null = m.content;\n if (\n m.role === \"assistant\" &&\n m.toolCalls &&\n m.toolCalls.length > 0 &&\n (!m.content || m.content.trim() === \"\")\n ) {\n content = null;\n }\n\n const out: OpenAIMessage = {\n role: m.role as OpenAIMessage[\"role\"],\n content,\n };\n\n if (m.toolCallId) {\n out.tool_call_id = m.toolCallId;\n }\n\n if (m.toolCalls && m.toolCalls.length > 0) {\n out.tool_calls = m.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: wireToolName(tc.name),\n arguments:\n typeof tc.args === \"string\"\n ? tc.args\n : JSON.stringify(tc.args ?? {}),\n },\n }));\n }\n\n return out;\n });\n }\n\n private buildTools(\n definitions: AgentToolDefinition[],\n nameToWire: Map<string, string>,\n ): OpenAITool[] {\n return definitions.map((def) => ({\n type: \"function\" as const,\n function: {\n name: nameToWire.get(def.name) ?? def.name,\n description: def.description,\n parameters: def.parameters,\n },\n }));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Text-based tool call parsing (fallback)\n// ---------------------------------------------------------------------------\n\n/**\n * Parses text-based tool calls from model output.\n *\n * Handles two formats:\n * 1. Llama native: `[{\"name\": \"tool_name\", \"parameters\": {\"arg\": \"val\"}}]`\n * 2. Python-style: `[tool_name(arg1='val1', arg2='val2')]`\n */\nexport function parseTextToolCalls(\n text: string,\n): Array<{ name: string; args: unknown }> {\n const trimmed = text.trim();\n\n const jsonResult = tryParseLlamaJsonToolCalls(trimmed);\n if (jsonResult.length > 0) return jsonResult;\n\n const pyResult = tryParsePythonStyleToolCalls(trimmed);\n if (pyResult.length > 0) return pyResult;\n\n return [];\n}\n\nfunction isLlamaToolJsonItem(value: unknown): value is Record<\n string,\n unknown\n> & {\n name: string;\n} {\n if (!isRecord(value)) return false;\n return typeof value.name === \"string\";\n}\n\nfunction tryParseLlamaJsonToolCalls(\n text: string,\n): Array<{ name: string; args: unknown }> {\n const slice = extractLlamaToolJsonSlice(text);\n if (!slice) return [];\n\n try {\n const parsed: unknown = JSON.parse(slice);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.filter(isLlamaToolJsonItem).map((item) => ({\n name: item.name,\n args: item.parameters ?? item.arguments ?? item.args ?? {},\n }));\n } catch {\n return [];\n }\n}\n\nfunction tryParsePythonStyleToolCalls(\n text: string,\n): Array<{ name: string; args: unknown }> {\n if (text.length > PYTHON_STYLE_TOOL_PARSE_MAX_INPUT) {\n return [];\n }\n\n const pattern = /\\[?([a-zA-Z_][\\w.]*)\\(([^)]*)\\)\\]?/g;\n const results: Array<{ name: string; args: unknown }> = [];\n\n for (const match of text.matchAll(pattern)) {\n const name = match[1];\n const argsStr = match[2];\n\n const args: Record<string, unknown> = {};\n const argPattern = /(\\w+)\\s*=\\s*(?:'([^']*)'|\"([^\"]*)\"|(\\S+))/g;\n for (const argMatch of argsStr.matchAll(argPattern)) {\n const key = argMatch[1];\n const value = argMatch[2] ?? argMatch[3] ?? argMatch[4];\n args[key] = value;\n }\n\n results.push({ name, args });\n }\n\n return results;\n}\n"],"mappings":"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"}
|
package/dist/appkit/package.js
CHANGED
package/dist/beta.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { DatabricksAdapter, parseTextToolCalls } from "./agents/databricks.js";
|
|
2
|
+
export { DatabricksAdapter, parseTextToolCalls };
|
package/dist/beta.js
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import { createLogger } from "../../logging/logger.js";
|
|
2
|
+
import { Context } from "@databricks/sdk-experimental";
|
|
2
3
|
|
|
3
4
|
//#region src/connectors/serving/client.ts
|
|
4
5
|
const logger = createLogger("connectors:serving");
|
|
5
6
|
/**
|
|
7
|
+
* Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so
|
|
8
|
+
* `apiClient.request` can abort the outbound HTTP request (and stop pulling
|
|
9
|
+
* the SSE body) when the agent run is cancelled.
|
|
10
|
+
*/
|
|
11
|
+
function cancellationTokenFromAbortSignal(signal) {
|
|
12
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
13
|
+
const fire = () => {
|
|
14
|
+
for (const cb of listeners) try {
|
|
15
|
+
cb();
|
|
16
|
+
} catch {}
|
|
17
|
+
};
|
|
18
|
+
signal.addEventListener("abort", fire, { passive: true });
|
|
19
|
+
return {
|
|
20
|
+
get isCancellationRequested() {
|
|
21
|
+
return signal.aborted;
|
|
22
|
+
},
|
|
23
|
+
onCancellationRequested(callback) {
|
|
24
|
+
listeners.add(callback);
|
|
25
|
+
if (signal.aborted) callback();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
6
30
|
* Invokes a serving endpoint using the SDK's high-level query API.
|
|
7
31
|
* Returns a typed QueryEndpointResponse.
|
|
8
32
|
*/
|
|
@@ -22,9 +46,10 @@ async function invoke(client, endpointName, body) {
|
|
|
22
46
|
* the high-level `servingEndpoints.query()` returns `Promise<QueryEndpointResponse>`
|
|
23
47
|
* and does not support SSE streaming.
|
|
24
48
|
*/
|
|
25
|
-
async function stream(client, endpointName, body) {
|
|
49
|
+
async function stream(client, endpointName, body, signal) {
|
|
26
50
|
const { stream: _stream, ...cleanBody } = body;
|
|
27
51
|
logger.debug("Streaming from endpoint %s", endpointName);
|
|
52
|
+
const context = signal ? new Context({ cancellationToken: cancellationTokenFromAbortSignal(signal) }) : void 0;
|
|
28
53
|
const response = await client.apiClient.request({
|
|
29
54
|
path: `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,
|
|
30
55
|
method: "POST",
|
|
@@ -37,7 +62,7 @@ async function stream(client, endpointName, body) {
|
|
|
37
62
|
stream: true
|
|
38
63
|
},
|
|
39
64
|
raw: true
|
|
40
|
-
});
|
|
65
|
+
}, context);
|
|
41
66
|
if (!response.contents) throw new Error("Response body is null — streaming not supported");
|
|
42
67
|
return response.contents;
|
|
43
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {\n CancellationToken,\n serving,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { Context } from \"@databricks/sdk-experimental\";\nimport { createLogger } from \"../../logging/logger\";\n\nconst logger = createLogger(\"connectors:serving\");\n\n/**\n * Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so\n * `apiClient.request` can abort the outbound HTTP request (and stop pulling\n * the SSE body) when the agent run is cancelled.\n */\nfunction cancellationTokenFromAbortSignal(\n signal: AbortSignal,\n): CancellationToken {\n const listeners = new Set<() => void>();\n const fire = () => {\n for (const cb of listeners) {\n try {\n cb();\n } catch {\n // ignore listener failures — abort must stay best-effort\n }\n }\n };\n signal.addEventListener(\"abort\", fire, { passive: true });\n\n return {\n get isCancellationRequested() {\n return signal.aborted;\n },\n onCancellationRequested(callback: (e?: unknown) => unknown) {\n listeners.add(callback as () => void);\n if (signal.aborted) {\n void callback();\n }\n },\n };\n}\n\n/**\n * Invokes a serving endpoint using the SDK's high-level query API.\n * Returns a typed QueryEndpointResponse.\n */\nexport async function invoke(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n): Promise<serving.QueryEndpointResponse> {\n // Strip `stream` from the body — the connector controls this\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Invoking endpoint %s\", endpointName);\n\n return client.servingEndpoints.query({\n name: endpointName,\n ...cleanBody,\n } as serving.QueryEndpointInput);\n}\n\n/**\n * Returns the raw SSE byte stream from a serving endpoint.\n * No parsing is performed — bytes are passed through as-is.\n *\n * Uses the SDK's low-level `apiClient.request({ raw: true })` because\n * the high-level `servingEndpoints.query()` returns `Promise<QueryEndpointResponse>`\n * and does not support SSE streaming.\n */\nexport async function stream(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Streaming from endpoint %s\", endpointName);\n\n const context = signal\n ? new Context({\n cancellationToken: cancellationTokenFromAbortSignal(signal),\n })\n : undefined;\n\n const response = (await client.apiClient.request(\n {\n path: `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,\n method: \"POST\",\n headers: new Headers({\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n }),\n payload: { ...cleanBody, stream: true },\n raw: true,\n },\n context,\n )) as { contents: ReadableStream<Uint8Array> };\n\n if (!response.contents) {\n throw new Error(\"Response body is null — streaming not supported\");\n }\n\n return response.contents;\n}\n"],"mappings":";;;;AAQA,MAAM,SAAS,aAAa,qBAAqB;;;;;;AAOjD,SAAS,iCACP,QACmB;CACnB,MAAM,4BAAY,IAAI,KAAiB;CACvC,MAAM,aAAa;AACjB,OAAK,MAAM,MAAM,UACf,KAAI;AACF,OAAI;UACE;;AAKZ,QAAO,iBAAiB,SAAS,MAAM,EAAE,SAAS,MAAM,CAAC;AAEzD,QAAO;EACL,IAAI,0BAA0B;AAC5B,UAAO,OAAO;;EAEhB,wBAAwB,UAAoC;AAC1D,aAAU,IAAI,SAAuB;AACrC,OAAI,OAAO,QACT,CAAK,UAAU;;EAGpB;;;;;;AAOH,eAAsB,OACpB,QACA,cACA,MACwC;CAExC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,wBAAwB,aAAa;AAElD,QAAO,OAAO,iBAAiB,MAAM;EACnC,MAAM;EACN,GAAG;EACJ,CAA+B;;;;;;;;;;AAWlC,eAAsB,OACpB,QACA,cACA,MACA,QACqC;CACrC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,8BAA8B,aAAa;CAExD,MAAM,UAAU,SACZ,IAAI,QAAQ,EACV,mBAAmB,iCAAiC,OAAO,EAC5D,CAAC,GACF;CAEJ,MAAM,WAAY,MAAM,OAAO,UAAU,QACvC;EACE,MAAM,sBAAsB,mBAAmB,aAAa,CAAC;EAC7D,QAAQ;EACR,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,QAAQ;GACT,CAAC;EACF,SAAS;GAAE,GAAG;GAAW,QAAQ;GAAM;EACvC,KAAK;EACN,EACD,QACD;AAED,KAAI,CAAC,SAAS,SACZ,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAO,SAAS"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { JSONSchema7 } from "json-schema";
|
|
2
|
+
|
|
3
|
+
//#region ../shared/src/agent.d.ts
|
|
4
|
+
interface ToolAnnotations {
|
|
5
|
+
readOnly?: boolean;
|
|
6
|
+
destructive?: boolean;
|
|
7
|
+
idempotent?: boolean;
|
|
8
|
+
requiresUserContext?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface AgentToolDefinition {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
parameters: JSONSchema7;
|
|
14
|
+
annotations?: ToolAnnotations;
|
|
15
|
+
}
|
|
16
|
+
interface Message {
|
|
17
|
+
id: string;
|
|
18
|
+
role: "user" | "assistant" | "system" | "tool";
|
|
19
|
+
content: string;
|
|
20
|
+
toolCallId?: string;
|
|
21
|
+
toolCalls?: ToolCall[];
|
|
22
|
+
createdAt: Date;
|
|
23
|
+
}
|
|
24
|
+
interface ToolCall {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
args: unknown;
|
|
28
|
+
}
|
|
29
|
+
type AgentEvent = {
|
|
30
|
+
type: "message_delta";
|
|
31
|
+
content: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "message";
|
|
34
|
+
content: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: "tool_call";
|
|
37
|
+
callId: string;
|
|
38
|
+
name: string;
|
|
39
|
+
args: unknown;
|
|
40
|
+
} | {
|
|
41
|
+
type: "tool_result";
|
|
42
|
+
callId: string;
|
|
43
|
+
result: unknown;
|
|
44
|
+
error?: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: "thinking";
|
|
47
|
+
content: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: "status";
|
|
50
|
+
status: "running" | "waiting" | "complete" | "error";
|
|
51
|
+
error?: string;
|
|
52
|
+
} | {
|
|
53
|
+
type: "metadata";
|
|
54
|
+
data: Record<string, unknown>;
|
|
55
|
+
};
|
|
56
|
+
interface AgentInput {
|
|
57
|
+
messages: Message[];
|
|
58
|
+
tools: AgentToolDefinition[];
|
|
59
|
+
threadId: string;
|
|
60
|
+
signal?: AbortSignal;
|
|
61
|
+
}
|
|
62
|
+
interface AgentRunContext {
|
|
63
|
+
/** Tool implementations should sanitize failure text — errors become `tool_result.error` and can flow back into the LLM transcript. */
|
|
64
|
+
executeTool: (name: string, args: unknown) => Promise<unknown>;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}
|
|
67
|
+
interface AgentAdapter {
|
|
68
|
+
run(input: AgentInput, context: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown>;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { AgentAdapter, AgentEvent, AgentInput, AgentRunContext, AgentToolDefinition, Message, ToolAnnotations, ToolCall };
|
|
72
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","names":[],"sources":["../../../../shared/src/agent.ts"],"mappings":";;;UAMiB,eAAA;EACf,QAAA;EACA,WAAA;EACA,UAAA;EACA,mBAAA;AAAA;AAAA,UAGe,mBAAA;EACf,IAAA;EACA,WAAA;EACA,UAAA,EAAY,WAAA;EACZ,WAAA,GAAc,eAAA;AAAA;AAAA,UAgBC,OAAA;EACf,EAAA;EACA,IAAA;EACA,OAAA;EACA,UAAA;EACA,SAAA,GAAY,QAAA;EACZ,SAAA,EAAW,IAAA;AAAA;AAAA,UAGI,QAAA;EACf,EAAA;EACA,IAAA;EACA,IAAA;AAAA;AAAA,KA2BU,UAAA;EACN,IAAA;EAAuB,OAAA;AAAA;EACvB,IAAA;EAAiB,OAAA;AAAA;EACjB,IAAA;EAAmB,MAAA;EAAgB,IAAA;EAAc,IAAA;AAAA;EAEjD,IAAA;EACA,MAAA;EACA,MAAA;EACA,KAAA;AAAA;EAEA,IAAA;EAAkB,OAAA;AAAA;EAElB,IAAA;EACA,MAAA;EACA,KAAA;AAAA;EAEA,IAAA;EAAkB,IAAA,EAAM,MAAA;AAAA;AAAA,UA0Gb,UAAA;EACf,QAAA,EAAU,OAAA;EACV,KAAA,EAAO,mBAAA;EACP,QAAA;EACA,MAAA,GAAS,WAAA;AAAA;AAAA,UAGM,eAAA;;EAEf,WAAA,GAAc,IAAA,UAAc,IAAA,cAAkB,OAAA;EAC9C,MAAA,GAAS,WAAA;AAAA;AAAA,UAGM,YAAA;EACf,GAAA,CACE,KAAA,EAAO,UAAA,EACP,OAAA,EAAS,eAAA,GACR,cAAA,CAAe,UAAA;AAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AgentAdapter, AgentEvent, AgentInput, AgentRunContext, AgentToolDefinition, Message, ToolAnnotations, ToolCall } from "./agent.js";
|
|
1
2
|
import { ResourceFieldEntry } from "./schemas/plugin-manifest.generated.js";
|
|
2
3
|
import { BasePlugin, BasePluginConfig, HttpMethod, IAppRequest, IAppResponse, IAppRouter, PluginConstructor, PluginData, PluginEndpointMap, PluginExports, PluginManifest, PluginMap, PluginPhase, ResourceRequirement, RouteConfig, TelemetryOptions, ToPlugin, WithAsUser } from "./plugin.js";
|
|
3
4
|
import { CacheConfig, CacheEntry, CacheStorage } from "./cache.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@databricks/appkit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.29.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"packageManager": "pnpm@10.21.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@ast-grep/napi": "0.37.0",
|
|
46
|
-
"@databricks/lakebase": "0.
|
|
46
|
+
"@databricks/lakebase": "0.3.0",
|
|
47
47
|
"@databricks/sdk-experimental": "0.16.0",
|
|
48
48
|
"@opentelemetry/api": "1.9.0",
|
|
49
49
|
"@opentelemetry/api-logs": "0.208.0",
|