@amigo-ai/platform-sdk 0.22.0 → 0.23.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/api.md CHANGED
@@ -240,6 +240,7 @@ All workspace-scoped resources also expose `withOptions(options)`.
240
240
  - `close`
241
241
  - `createTurn`
242
242
  - `createTurnStream`
243
+ - `streamTurn`
243
244
  - `textStreamUrl`
244
245
  - `sessionConnectUrl`
245
246
 
package/dist/index.cjs CHANGED
@@ -2024,7 +2024,10 @@ var ConversationsResource = class extends WorkspaceScopedResource {
2024
2024
  "/v1/{workspace_id}/conversations/{conversation_id}/turns",
2025
2025
  {
2026
2026
  params: {
2027
- path: { workspace_id: this.workspaceId, conversation_id: conversationId }
2027
+ path: { workspace_id: this.workspaceId, conversation_id: conversationId },
2028
+ ...options?.includeToolCalls !== void 0 && {
2029
+ query: { include_tool_calls: options.includeToolCalls }
2030
+ }
2028
2031
  },
2029
2032
  body: request,
2030
2033
  headers: { Accept: "text/event-stream" },
@@ -2037,6 +2040,35 @@ var ConversationsResource = class extends WorkspaceScopedResource {
2037
2040
  }
2038
2041
  return result.data;
2039
2042
  }
2043
+ /**
2044
+ * Send a message and receive the agent's response as a typed
2045
+ * `TurnStreamEvent` async iterable.
2046
+ *
2047
+ * The bytes-and-parser dance from `createTurnStream` is now hidden inside
2048
+ * the SDK — consumers iterate strongly typed events directly. Each yielded
2049
+ * value is a member of the `TurnStreamEvent` discriminated union (`token`,
2050
+ * `thinking`, `tool_call_started`, `tool_call_completed`, `message`,
2051
+ * `done`, `error`), validated as a record with a known `event`
2052
+ * discriminator. Unknown / malformed frames are dropped silently — this
2053
+ * matches the wire-format-drift behavior of the lower-level
2054
+ * `createTurnStream` while keeping the strict `TurnStreamEvent` static
2055
+ * contract intact for consumers.
2056
+ *
2057
+ * @example
2058
+ * ```ts
2059
+ * for await (const event of client.conversations.streamTurn(convId, { message: "Hello" })) {
2060
+ * if (event.event === "token") process.stdout.write(event.text);
2061
+ * else if (event.event === "done") break;
2062
+ * }
2063
+ * ```
2064
+ */
2065
+ async *streamTurn(conversationId, request, options) {
2066
+ const byteStream = await this.createTurnStream(conversationId, request, options);
2067
+ for await (const frame of parseSSEFrames(byteStream)) {
2068
+ const event = parseTurnStreamFrame(frame.event, frame.data);
2069
+ if (event) yield event;
2070
+ }
2071
+ }
2040
2072
  /** Build the real-time text WebSocket URL for browser or custom clients. */
2041
2073
  textStreamUrl(params) {
2042
2074
  const url = buildTextStreamUrl({
@@ -2228,6 +2260,80 @@ function describeInvalidSubprotocolChars(token) {
2228
2260
  }
2229
2261
  return [...chars].map((char) => JSON.stringify(char)).join(", ");
2230
2262
  }
2263
+ async function* parseSSEFrames(stream) {
2264
+ const reader = stream.getReader();
2265
+ const decoder = new TextDecoder();
2266
+ let buffer = "";
2267
+ function* drain(text) {
2268
+ buffer += text;
2269
+ while (true) {
2270
+ const idx = findFrameTerminator(buffer);
2271
+ if (idx === null) break;
2272
+ const block = buffer.slice(0, idx.terminatorStart);
2273
+ buffer = buffer.slice(idx.terminatorEnd);
2274
+ const frame = parseSSEBlock(block);
2275
+ if (frame) yield frame;
2276
+ }
2277
+ }
2278
+ try {
2279
+ while (true) {
2280
+ const { done, value } = await reader.read();
2281
+ if (done) break;
2282
+ yield* drain(decoder.decode(value, { stream: true }));
2283
+ }
2284
+ yield* drain(decoder.decode());
2285
+ if (buffer.trim().length > 0) {
2286
+ const frame = parseSSEBlock(buffer);
2287
+ if (frame) yield frame;
2288
+ buffer = "";
2289
+ }
2290
+ } finally {
2291
+ reader.releaseLock();
2292
+ }
2293
+ }
2294
+ function findFrameTerminator(s) {
2295
+ const lf = s.indexOf("\n\n");
2296
+ const crlf = s.indexOf("\r\n\r\n");
2297
+ if (lf < 0 && crlf < 0) return null;
2298
+ if (lf < 0) return { terminatorStart: crlf, terminatorEnd: crlf + 4 };
2299
+ if (crlf < 0) return { terminatorStart: lf, terminatorEnd: lf + 2 };
2300
+ return lf < crlf ? { terminatorStart: lf, terminatorEnd: lf + 2 } : { terminatorStart: crlf, terminatorEnd: crlf + 4 };
2301
+ }
2302
+ function parseSSEBlock(block) {
2303
+ let event = "";
2304
+ const dataLines = [];
2305
+ for (const line of block.split(/\r?\n/)) {
2306
+ if (line === "" || line.startsWith(":")) continue;
2307
+ const colon = line.indexOf(":");
2308
+ const field = colon < 0 ? line : line.slice(0, colon);
2309
+ let value = colon < 0 ? "" : line.slice(colon + 1);
2310
+ if (value.startsWith(" ")) value = value.slice(1);
2311
+ if (field === "event") event = value;
2312
+ else if (field === "data") dataLines.push(value);
2313
+ }
2314
+ if (!event || dataLines.length === 0) return null;
2315
+ return { event, data: dataLines.join("\n") };
2316
+ }
2317
+ var KNOWN_TURN_STREAM_EVENTS = /* @__PURE__ */ new Set([
2318
+ "token",
2319
+ "thinking",
2320
+ "tool_call_started",
2321
+ "tool_call_completed",
2322
+ "message",
2323
+ "done",
2324
+ "error"
2325
+ ]);
2326
+ function parseTurnStreamFrame(eventName, dataJson) {
2327
+ if (!KNOWN_TURN_STREAM_EVENTS.has(eventName)) return null;
2328
+ let payload;
2329
+ try {
2330
+ payload = JSON.parse(dataJson);
2331
+ } catch {
2332
+ return null;
2333
+ }
2334
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return null;
2335
+ return { ...payload, event: eventName };
2336
+ }
2231
2337
 
2232
2338
  // src/resources/phone-numbers.ts
2233
2339
  var PhoneNumbersResource = class extends WorkspaceScopedResource {