@ekodb/ekodb-client 0.15.2 → 0.17.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/src/client.ts CHANGED
@@ -6,7 +6,7 @@ import { encode, decode } from "@msgpack/msgpack";
6
6
  import { QueryBuilder, Query as QueryBuilderQuery } from "./query-builder";
7
7
  import { SearchQuery, SearchResponse } from "./search";
8
8
  import { Schema, SchemaBuilder, CollectionMetadata } from "./schema";
9
- import { Script, FunctionResult } from "./functions";
9
+ import { UserFunction, FunctionResult } from "./functions";
10
10
 
11
11
  export interface Record {
12
12
  [key: string]: any;
@@ -188,6 +188,7 @@ export interface CreateChatSessionRequest {
188
188
  llm_provider: string;
189
189
  llm_model?: string;
190
190
  system_prompt?: string;
191
+ agent_id?: string;
191
192
  bypass_ripple?: boolean;
192
193
  parent_id?: string;
193
194
  branch_point_idx?: number;
@@ -204,6 +205,9 @@ export interface ChatMessageRequest {
204
205
  max_iterations?: number;
205
206
  tool_config?: ToolConfig;
206
207
  llm_model?: string;
208
+ client_tools?: ClientToolDefinition[];
209
+ confirm_tools?: string[];
210
+ exclude_tools?: string[];
207
211
  }
208
212
 
209
213
  export interface TokenUsage {
@@ -229,6 +233,7 @@ export interface ChatSession {
229
233
  llm_model: string;
230
234
  collections: CollectionConfig[];
231
235
  system_prompt?: string;
236
+ agent_id?: string;
232
237
  title?: string;
233
238
  message_count: number;
234
239
  }
@@ -335,21 +340,7 @@ export interface RawCompletionResponse {
335
340
  content: string;
336
341
  }
337
342
 
338
- /**
339
- * User function definition - reusable sequence of Functions that can be called by Scripts
340
- */
341
- export interface UserFunction {
342
- label: string;
343
- name: string;
344
- description?: string;
345
- version?: string;
346
- parameters: { [key: string]: ParameterDefinition };
347
- functions: FunctionStageConfig[];
348
- tags?: string[];
349
- id?: string;
350
- created_at?: string;
351
- updated_at?: string;
352
- }
343
+ // UserFunction is defined in functions.ts and re-exported from there.
353
344
 
354
345
  /**
355
346
  * Parameter definition for functions
@@ -1769,6 +1760,31 @@ export class EkoDBClient {
1769
1760
  );
1770
1761
  }
1771
1762
 
1763
+ /**
1764
+ * Submit a client tool result for an in-flight SSE chat stream.
1765
+ * Unblocks ekoDB's tool loop so it can feed the result to the LLM.
1766
+ */
1767
+ async submitChatToolResult(
1768
+ chatId: string,
1769
+ callId: string,
1770
+ success: boolean,
1771
+ result?: any,
1772
+ error?: string,
1773
+ ): Promise<void> {
1774
+ await this.makeRequest(
1775
+ "POST",
1776
+ `/api/chat/${chatId}/tool-result`,
1777
+ {
1778
+ call_id: callId,
1779
+ success,
1780
+ ...(result !== undefined && { result }),
1781
+ ...(error !== undefined && { error }),
1782
+ },
1783
+ 0,
1784
+ true,
1785
+ );
1786
+ }
1787
+
1772
1788
  /**
1773
1789
  * Send a message in an existing chat session via SSE streaming.
1774
1790
  *
@@ -2106,9 +2122,9 @@ export class EkoDBClient {
2106
2122
  // ========================================================================
2107
2123
 
2108
2124
  /**
2109
- * Save a new script definition
2125
+ * Save a new function definition
2110
2126
  */
2111
- async saveScript(script: Script): Promise<string> {
2127
+ async saveFunction(script: UserFunction): Promise<string> {
2112
2128
  const result = await this.makeRequest<{ id: string }>(
2113
2129
  "POST",
2114
2130
  "/api/functions",
@@ -2118,38 +2134,38 @@ export class EkoDBClient {
2118
2134
  }
2119
2135
 
2120
2136
  /**
2121
- * Get a script by ID
2137
+ * Get a function by ID
2122
2138
  */
2123
- async getScript(id: string): Promise<Script> {
2124
- return this.makeRequest<Script>("GET", `/api/functions/${id}`);
2139
+ async getFunction(id: string): Promise<UserFunction> {
2140
+ return this.makeRequest<UserFunction>("GET", `/api/functions/${id}`);
2125
2141
  }
2126
2142
 
2127
2143
  /**
2128
- * List all scripts, optionally filtered by tags
2144
+ * List all functions, optionally filtered by tags
2129
2145
  */
2130
- async listScripts(tags?: string[]): Promise<Script[]> {
2146
+ async listFunctions(tags?: string[]): Promise<UserFunction[]> {
2131
2147
  const params = tags ? `?tags=${tags.join(",")}` : "";
2132
- return this.makeRequest<Script[]>("GET", `/api/functions${params}`);
2148
+ return this.makeRequest<UserFunction[]>("GET", `/api/functions${params}`);
2133
2149
  }
2134
2150
 
2135
2151
  /**
2136
- * Update an existing script by ID
2152
+ * Update an existing function by ID
2137
2153
  */
2138
- async updateScript(id: string, script: Script): Promise<void> {
2154
+ async updateFunction(id: string, script: UserFunction): Promise<void> {
2139
2155
  await this.makeRequest<void>("PUT", `/api/functions/${id}`, script);
2140
2156
  }
2141
2157
 
2142
2158
  /**
2143
- * Delete a script by ID
2159
+ * Delete a function by ID
2144
2160
  */
2145
- async deleteScript(id: string): Promise<void> {
2161
+ async deleteFunction(id: string): Promise<void> {
2146
2162
  await this.makeRequest<void>("DELETE", `/api/functions/${id}`);
2147
2163
  }
2148
2164
 
2149
2165
  /**
2150
- * Call a saved script by ID or label
2166
+ * Call a saved function by ID or label
2151
2167
  */
2152
- async callScript(
2168
+ async callFunction(
2153
2169
  idOrLabel: string,
2154
2170
  params?: { [key: string]: any },
2155
2171
  ): Promise<FunctionResult> {
@@ -2783,6 +2799,115 @@ export class EkoDBClient {
2783
2799
  return records.length;
2784
2800
  }
2785
2801
 
2802
+ /**
2803
+ * Subscribe to collection mutations via SSE (Server-Sent Events).
2804
+ *
2805
+ * Returns an EventStream that emits MutationNotification events.
2806
+ * Use this when WebSocket connections aren't available (e.g. behind
2807
+ * reverse proxies that block WS upgrades).
2808
+ */
2809
+ subscribeSSE(
2810
+ collection: string,
2811
+ options?: { filterField?: string; filterValue?: string },
2812
+ ): EventStream<MutationNotification> {
2813
+ const stream = new EventStream<MutationNotification>();
2814
+
2815
+ (async () => {
2816
+ try {
2817
+ let token = await this.getToken();
2818
+ if (!token) {
2819
+ await this.refreshToken();
2820
+ token = await this.getToken();
2821
+ }
2822
+
2823
+ let url = `${this.baseURL}/api/subscribe/${encodeURIComponent(collection)}`;
2824
+ const params: string[] = [];
2825
+ if (options?.filterField)
2826
+ params.push(
2827
+ `filter_field=${encodeURIComponent(options.filterField)}`,
2828
+ );
2829
+ if (options?.filterValue)
2830
+ params.push(
2831
+ `filter_value=${encodeURIComponent(options.filterValue)}`,
2832
+ );
2833
+ if (params.length > 0) url += `?${params.join("&")}`;
2834
+
2835
+ const response = await fetch(url, {
2836
+ method: "GET",
2837
+ headers: {
2838
+ Accept: "text/event-stream",
2839
+ Authorization: `Bearer ${token}`,
2840
+ },
2841
+ });
2842
+
2843
+ if (!response.ok) {
2844
+ const body = await response.text();
2845
+ stream.emit(
2846
+ "error",
2847
+ `SSE subscribe failed (${response.status}): ${body}`,
2848
+ );
2849
+ stream.close();
2850
+ return;
2851
+ }
2852
+
2853
+ const reader = response.body?.getReader();
2854
+ if (!reader) {
2855
+ stream.emit("error", "SSE subscribe failed: streaming not supported");
2856
+ stream.close();
2857
+ return;
2858
+ }
2859
+
2860
+ const decoder = new TextDecoder("utf-8");
2861
+ let buffer = "";
2862
+ let eventType = "";
2863
+ let dataLines: string[] = [];
2864
+
2865
+ while (!stream.closed) {
2866
+ const { value, done } = await reader.read();
2867
+ if (done) break;
2868
+
2869
+ buffer += decoder.decode(value, { stream: true });
2870
+ const lines = buffer.split("\n");
2871
+ buffer = lines.pop() ?? "";
2872
+
2873
+ for (const line of lines) {
2874
+ if (line === "") {
2875
+ // End of event block
2876
+ if (eventType === "mutation" && dataLines.length > 0) {
2877
+ try {
2878
+ const payload = JSON.parse(dataLines.join("\n"));
2879
+ stream.emit("event", {
2880
+ collection: payload.collection,
2881
+ event: payload.event,
2882
+ recordIds: payload.record_ids,
2883
+ records: payload.records,
2884
+ timestamp: payload.timestamp,
2885
+ } as MutationNotification);
2886
+ } catch {
2887
+ // skip malformed data
2888
+ }
2889
+ }
2890
+ eventType = "";
2891
+ dataLines = [];
2892
+ continue;
2893
+ }
2894
+ if (line.startsWith("event: ")) {
2895
+ eventType = line.slice(7).trim();
2896
+ } else if (line.startsWith("data: ")) {
2897
+ dataLines.push(line.slice(6).trim());
2898
+ }
2899
+ }
2900
+ }
2901
+ stream.close();
2902
+ } catch (err: any) {
2903
+ stream.emit("error", err.message ?? String(err));
2904
+ stream.close();
2905
+ }
2906
+ })();
2907
+
2908
+ return stream;
2909
+ }
2910
+
2786
2911
  /**
2787
2912
  * Create a WebSocket client
2788
2913
  */