@distri/core 0.3.3 → 0.3.4

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/index.mjs CHANGED
@@ -6,8 +6,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
6
6
  function isArrayParts(result) {
7
7
  return Array.isArray(result) && result[0].part_type;
8
8
  }
9
- function createSuccessfulToolResult(toolCallId, toolName, result) {
10
- const parts = isArrayParts(result) ? result : [{
9
+ function createSuccessfulToolResult(toolCallId, toolName, result, explicitPartsMetadata) {
10
+ console.log("[createSuccessfulToolResult] toolName:", toolName);
11
+ console.log("[createSuccessfulToolResult] isArrayParts:", isArrayParts(result));
12
+ console.log("[createSuccessfulToolResult] result type:", typeof result, Array.isArray(result) ? `array[${result.length}]` : "");
13
+ if (isArrayParts(result)) {
14
+ console.log("[createSuccessfulToolResult] parts:", result.map((p) => ({ part_type: p.part_type, hasMetadata: !!p.__metadata })));
15
+ }
16
+ const rawParts = isArrayParts(result) ? result : [{
11
17
  part_type: "data",
12
18
  data: {
13
19
  result,
@@ -15,10 +21,22 @@ function createSuccessfulToolResult(toolCallId, toolName, result) {
15
21
  error: void 0
16
22
  }
17
23
  }];
24
+ const parts_metadata = { ...explicitPartsMetadata };
25
+ const parts = rawParts.map((part, index) => {
26
+ if ("__metadata" in part && part.__metadata) {
27
+ parts_metadata[index] = { ...parts_metadata[index], ...part.__metadata };
28
+ }
29
+ if (part.part_type === "image" && !parts_metadata[index]) {
30
+ parts_metadata[index] = { save: false };
31
+ }
32
+ const { __metadata, ...cleanPart } = part;
33
+ return cleanPart;
34
+ });
18
35
  return {
19
36
  tool_call_id: toolCallId,
20
37
  tool_name: toolName,
21
- parts
38
+ parts,
39
+ parts_metadata: Object.keys(parts_metadata).length > 0 ? parts_metadata : void 0
22
40
  };
23
41
  }
24
42
  function createFailedToolResult(toolCallId, toolName, error, result) {
@@ -494,11 +512,22 @@ var A2AClient = class {
494
512
  // src/encoder.ts
495
513
  function convertA2AMessageToDistri(a2aMessage) {
496
514
  const role = a2aMessage.role === "agent" ? "assistant" : "user";
515
+ let agent_id;
516
+ let agent_name;
517
+ if (a2aMessage.metadata) {
518
+ const metadata = a2aMessage.metadata;
519
+ if (metadata.agent) {
520
+ agent_id = metadata.agent.agent_id;
521
+ agent_name = metadata.agent.agent_name;
522
+ }
523
+ }
497
524
  return {
498
525
  id: a2aMessage.messageId,
499
526
  role,
500
527
  parts: a2aMessage.parts.map(convertA2APartToDistri),
501
- created_at: a2aMessage.createdAt
528
+ created_at: a2aMessage.createdAt,
529
+ agent_id,
530
+ agent_name
502
531
  };
503
532
  }
504
533
  function convertA2AStatusUpdateToDistri(statusUpdate) {
@@ -521,8 +550,8 @@ function convertA2AStatusUpdateToDistri(statusUpdate) {
521
550
  const runErrorResult = {
522
551
  type: "run_error",
523
552
  data: {
524
- message: statusUpdate.error,
525
- code: statusUpdate.code
553
+ message: metadata.message || statusUpdate.status?.message || "Unknown error",
554
+ code: metadata.code
526
555
  }
527
556
  };
528
557
  return runErrorResult;
@@ -692,6 +721,19 @@ function convertA2AStatusUpdateToDistri(statusUpdate) {
692
721
  };
693
722
  return browserSessionStarted;
694
723
  }
724
+ case "todos_updated": {
725
+ const todos = parseTodosFromFormatted(metadata.formatted_todos || "");
726
+ const todosUpdated = {
727
+ type: "todos_updated",
728
+ data: {
729
+ formatted_todos: metadata.formatted_todos || "",
730
+ action: metadata.action || "write_todos",
731
+ todo_count: metadata.todo_count || 0,
732
+ todos
733
+ }
734
+ };
735
+ return todosUpdated;
736
+ }
695
737
  default: {
696
738
  console.warn(`Unhandled status update metadata type: ${metadata.type}`, metadata);
697
739
  const defaultResult = {
@@ -743,7 +785,7 @@ function convertA2APartToDistri(a2aPart) {
743
785
  const fileUrl = { type: "url", mime_type: a2aPart.file.mimeType || "application/octet-stream", url: a2aPart.file.uri || "" };
744
786
  return { part_type: "image", data: fileUrl };
745
787
  } else {
746
- const fileBytes = { type: "bytes", mime_type: a2aPart.file.mimeType || "application/octet-stream", data: a2aPart.file.bytes || "" };
788
+ const fileBytes = { type: "bytes", mime_type: a2aPart.file.mimeType || "application/octet-stream", bytes: a2aPart.file.bytes || "" };
747
789
  return { part_type: "image", data: fileBytes };
748
790
  }
749
791
  case "data":
@@ -782,7 +824,8 @@ function convertDistriMessageToA2A(distriMessage, context) {
782
824
  parts: distriMessage.parts.map(convertDistriPartToA2A),
783
825
  kind: "message",
784
826
  contextId: context.thread_id,
785
- taskId: context.task_id || context.run_id || void 0
827
+ taskId: context.task_id || context.run_id || void 0,
828
+ metadata: distriMessage.metadata
786
829
  };
787
830
  }
788
831
  function convertDistriPartToA2A(distriPart) {
@@ -796,7 +839,7 @@ function convertDistriPartToA2A(distriPart) {
796
839
  const fileUri = { mimeType: distriPart.data.mime_type, uri: distriPart.data.url };
797
840
  result = { kind: "file", file: fileUri };
798
841
  } else {
799
- const fileBytes = { mimeType: distriPart.data.mime_type, bytes: distriPart.data.data };
842
+ const fileBytes = { mimeType: distriPart.data.mime_type, bytes: distriPart.data.bytes };
800
843
  result = { kind: "file", file: fileBytes };
801
844
  }
802
845
  break;
@@ -861,6 +904,32 @@ function extractToolCallsFromDistriMessage(message) {
861
904
  function extractToolResultsFromDistriMessage(message) {
862
905
  return message.parts.filter((part) => part.part_type === "tool_result").map((part) => part.data);
863
906
  }
907
+ function parseTodosFromFormatted(formatted) {
908
+ if (!formatted || formatted === "\u25A1 No todos") {
909
+ return [];
910
+ }
911
+ const lines = formatted.split("\n").filter((line) => line.trim());
912
+ return lines.map((line, index) => {
913
+ const trimmed = line.trim();
914
+ let status = "open";
915
+ let content = trimmed;
916
+ if (trimmed.startsWith("\u25A0")) {
917
+ status = "done";
918
+ content = trimmed.slice(1).trim();
919
+ } else if (trimmed.startsWith("\u25D0")) {
920
+ status = "in_progress";
921
+ content = trimmed.slice(1).trim();
922
+ } else if (trimmed.startsWith("\u25A1")) {
923
+ status = "open";
924
+ content = trimmed.slice(1).trim();
925
+ }
926
+ return {
927
+ id: `todo_${index}`,
928
+ content,
929
+ status
930
+ };
931
+ });
932
+ }
864
933
 
865
934
  // src/distri-client.ts
866
935
  var _DistriClient = class _DistriClient {
@@ -1407,7 +1476,12 @@ var _DistriClient = class _DistriClient {
1407
1476
  }
1408
1477
  }
1409
1478
  if (error instanceof Error) {
1410
- return error.message;
1479
+ const msg = error.message;
1480
+ const sseMatch = msg.match(/SSE event contained an error:\s*(.+?)\s*\(Code:/);
1481
+ if (sseMatch) return sseMatch[1];
1482
+ const rpcMatch = msg.match(/RPC Error:\s*(.+?)\s*\(Code:/);
1483
+ if (rpcMatch) return rpcMatch[1];
1484
+ return msg;
1411
1485
  }
1412
1486
  return String(error);
1413
1487
  }
@@ -1471,11 +1545,19 @@ var _DistriClient = class _DistriClient {
1471
1545
  }
1472
1546
  }
1473
1547
  /**
1474
- * Get agents sorted by thread count (most active first)
1548
+ * Get agents sorted by thread count (most active first).
1549
+ * Includes all registered agents, even those with 0 threads.
1550
+ * Optionally filter by name with search parameter.
1475
1551
  */
1476
- async getAgentsByUsage() {
1552
+ async getAgentsByUsage(options) {
1477
1553
  try {
1478
- const response = await this.fetch("/threads/agents");
1554
+ const params = new URLSearchParams();
1555
+ if (options?.search) {
1556
+ params.set("search", options.search);
1557
+ }
1558
+ const query = params.toString();
1559
+ const url = query ? `/threads/agents?${query}` : "/threads/agents";
1560
+ const response = await this.fetch(url);
1479
1561
  if (!response.ok) {
1480
1562
  throw new ApiError(`Failed to fetch agents by usage: ${response.statusText}`, response.status);
1481
1563
  }
@@ -1540,6 +1622,138 @@ var _DistriClient = class _DistriClient {
1540
1622
  const messages = await this.getThreadMessages(threadId);
1541
1623
  return messages.map(convertA2AMessageToDistri);
1542
1624
  }
1625
+ // ========== Message Read Status Methods ==========
1626
+ /**
1627
+ * Mark a message as read
1628
+ */
1629
+ async markMessageRead(threadId, messageId) {
1630
+ try {
1631
+ const response = await this.fetch(
1632
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/read`,
1633
+ { method: "POST" }
1634
+ );
1635
+ if (!response.ok) {
1636
+ throw new ApiError(`Failed to mark message as read: ${response.statusText}`, response.status);
1637
+ }
1638
+ return await response.json();
1639
+ } catch (error) {
1640
+ if (error instanceof ApiError) throw error;
1641
+ throw new DistriError(`Failed to mark message ${messageId} as read`, "MARK_READ_ERROR", error);
1642
+ }
1643
+ }
1644
+ /**
1645
+ * Get read status for a specific message
1646
+ */
1647
+ async getMessageReadStatus(threadId, messageId) {
1648
+ try {
1649
+ const response = await this.fetch(
1650
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/read`
1651
+ );
1652
+ if (response.status === 404) {
1653
+ return null;
1654
+ }
1655
+ if (!response.ok) {
1656
+ throw new ApiError(`Failed to get message read status: ${response.statusText}`, response.status);
1657
+ }
1658
+ return await response.json();
1659
+ } catch (error) {
1660
+ if (error instanceof ApiError) throw error;
1661
+ throw new DistriError(`Failed to get read status for message ${messageId}`, "FETCH_ERROR", error);
1662
+ }
1663
+ }
1664
+ /**
1665
+ * Get read status for all messages in a thread
1666
+ */
1667
+ async getThreadReadStatus(threadId) {
1668
+ try {
1669
+ const response = await this.fetch(
1670
+ `/threads/${encodeURIComponent(threadId)}/read-status`
1671
+ );
1672
+ if (!response.ok) {
1673
+ throw new ApiError(`Failed to get thread read status: ${response.statusText}`, response.status);
1674
+ }
1675
+ return await response.json();
1676
+ } catch (error) {
1677
+ if (error instanceof ApiError) throw error;
1678
+ throw new DistriError(`Failed to get read status for thread ${threadId}`, "FETCH_ERROR", error);
1679
+ }
1680
+ }
1681
+ // ========== Message Voting Methods ==========
1682
+ /**
1683
+ * Vote on a message (upvote or downvote)
1684
+ * Downvotes require a comment explaining the issue
1685
+ */
1686
+ async voteMessage(threadId, messageId, request) {
1687
+ try {
1688
+ const response = await this.fetch(
1689
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`,
1690
+ {
1691
+ method: "POST",
1692
+ headers: { "Content-Type": "application/json" },
1693
+ body: JSON.stringify(request)
1694
+ }
1695
+ );
1696
+ if (!response.ok) {
1697
+ const errorData = await response.json().catch(() => ({}));
1698
+ throw new ApiError(errorData.error || `Failed to vote on message: ${response.statusText}`, response.status);
1699
+ }
1700
+ return await response.json();
1701
+ } catch (error) {
1702
+ if (error instanceof ApiError) throw error;
1703
+ throw new DistriError(`Failed to vote on message ${messageId}`, "VOTE_ERROR", error);
1704
+ }
1705
+ }
1706
+ /**
1707
+ * Remove vote from a message
1708
+ */
1709
+ async removeVote(threadId, messageId) {
1710
+ try {
1711
+ const response = await this.fetch(
1712
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`,
1713
+ { method: "DELETE" }
1714
+ );
1715
+ if (!response.ok && response.status !== 204) {
1716
+ throw new ApiError(`Failed to remove vote: ${response.statusText}`, response.status);
1717
+ }
1718
+ } catch (error) {
1719
+ if (error instanceof ApiError) throw error;
1720
+ throw new DistriError(`Failed to remove vote from message ${messageId}`, "VOTE_ERROR", error);
1721
+ }
1722
+ }
1723
+ /**
1724
+ * Get vote summary for a message (counts + current user's vote)
1725
+ */
1726
+ async getMessageVoteSummary(threadId, messageId) {
1727
+ try {
1728
+ const response = await this.fetch(
1729
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`
1730
+ );
1731
+ if (!response.ok) {
1732
+ throw new ApiError(`Failed to get vote summary: ${response.statusText}`, response.status);
1733
+ }
1734
+ return await response.json();
1735
+ } catch (error) {
1736
+ if (error instanceof ApiError) throw error;
1737
+ throw new DistriError(`Failed to get vote summary for message ${messageId}`, "FETCH_ERROR", error);
1738
+ }
1739
+ }
1740
+ /**
1741
+ * Get all votes for a message (admin/analytics use)
1742
+ */
1743
+ async getMessageVotes(threadId, messageId) {
1744
+ try {
1745
+ const response = await this.fetch(
1746
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/votes`
1747
+ );
1748
+ if (!response.ok) {
1749
+ throw new ApiError(`Failed to get message votes: ${response.statusText}`, response.status);
1750
+ }
1751
+ return await response.json();
1752
+ } catch (error) {
1753
+ if (error instanceof ApiError) throw error;
1754
+ throw new DistriError(`Failed to get votes for message ${messageId}`, "FETCH_ERROR", error);
1755
+ }
1756
+ }
1543
1757
  /**
1544
1758
  * Send a DistriMessage to a thread
1545
1759
  */
@@ -1565,7 +1779,12 @@ var _DistriClient = class _DistriClient {
1565
1779
  },
1566
1780
  body: JSON.stringify({
1567
1781
  tool_call_id: result.tool_call_id,
1568
- tool_response: result
1782
+ tool_response: {
1783
+ tool_call_id: result.tool_call_id,
1784
+ tool_name: result.tool_name,
1785
+ parts: result.parts,
1786
+ parts_metadata: result.parts_metadata
1787
+ }
1569
1788
  })
1570
1789
  });
1571
1790
  if (!response.ok) {
@@ -1829,9 +2048,17 @@ var _DistriClient = class _DistriClient {
1829
2048
  };
1830
2049
  }
1831
2050
  /**
1832
- * Helper method to create message send parameters
1833
- */
1834
- static initMessageParams(message, configuration, metadata) {
2051
+ * Helper method to create message send parameters.
2052
+ *
2053
+ * Pass `dynamicMetadata` to inject `dynamic_sections` and/or `dynamic_values`
2054
+ * into the metadata so the server can apply them to prompt templates.
2055
+ */
2056
+ static initMessageParams(message, configuration, metadata, dynamicMetadata) {
2057
+ const mergedMetadata = {
2058
+ ...metadata,
2059
+ ...dynamicMetadata?.dynamic_sections ? { dynamic_sections: dynamicMetadata.dynamic_sections } : {},
2060
+ ...dynamicMetadata?.dynamic_values ? { dynamic_values: dynamicMetadata.dynamic_values } : {}
2061
+ };
1835
2062
  return {
1836
2063
  message,
1837
2064
  configuration: {
@@ -1840,18 +2067,26 @@ var _DistriClient = class _DistriClient {
1840
2067
  // Default to non-blocking for streaming
1841
2068
  ...configuration
1842
2069
  },
1843
- metadata
2070
+ metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : metadata
1844
2071
  };
1845
2072
  }
1846
2073
  /**
1847
- * Create MessageSendParams from a DistriMessage using InvokeContext
2074
+ * Create MessageSendParams from a DistriMessage using InvokeContext.
2075
+ *
2076
+ * Pass `dynamicMetadata` to inject `dynamic_sections` and/or `dynamic_values`
2077
+ * into the metadata so the server can apply them to prompt templates.
1848
2078
  */
1849
- static initDistriMessageParams(message, context) {
2079
+ static initDistriMessageParams(message, context, dynamicMetadata) {
1850
2080
  const a2aMessage = convertDistriMessageToA2A(message, context);
1851
2081
  const contextMetadata = context.getMetadata?.() || {};
2082
+ const mergedMetadata = {
2083
+ ...contextMetadata,
2084
+ ...dynamicMetadata?.dynamic_sections ? { dynamic_sections: dynamicMetadata.dynamic_sections } : {},
2085
+ ...dynamicMetadata?.dynamic_values ? { dynamic_values: dynamicMetadata.dynamic_values } : {}
2086
+ };
1852
2087
  return {
1853
2088
  message: a2aMessage,
1854
- metadata: contextMetadata
2089
+ metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : contextMetadata
1855
2090
  };
1856
2091
  }
1857
2092
  };
@@ -1957,28 +2192,40 @@ var Agent = class _Agent {
1957
2192
  const enhancedParams = this.enhanceParamsWithTools(params, tools);
1958
2193
  const a2aStream = this.client.sendMessageStream(this.agentDefinition.id, enhancedParams);
1959
2194
  const self = this;
1960
- return async function* () {
1961
- for await (const event of a2aStream) {
1962
- const converted = decodeA2AStreamEvent(event);
1963
- if (converted && converted.type === "inline_hook_requested") {
1964
- const hookReq = converted.data;
1965
- const handler = self.hookHandlers.get(hookReq.hook) || self.defaultHookHandler;
1966
- if (handler) {
1967
- try {
1968
- const mutation = await handler(hookReq);
1969
- await self.client.completeInlineHook(hookReq.hook_id, mutation);
1970
- } catch (err) {
2195
+ return (async function* () {
2196
+ try {
2197
+ for await (const event of a2aStream) {
2198
+ const converted = decodeA2AStreamEvent(event);
2199
+ if (converted && converted.type === "inline_hook_requested") {
2200
+ const hookReq = converted.data;
2201
+ const handler = self.hookHandlers.get(hookReq.hook) || self.defaultHookHandler;
2202
+ if (handler) {
2203
+ try {
2204
+ const mutation = await handler(hookReq);
2205
+ await self.client.completeInlineHook(hookReq.hook_id, mutation);
2206
+ } catch (err) {
2207
+ await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
2208
+ }
2209
+ } else {
1971
2210
  await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
1972
2211
  }
1973
- } else {
1974
- await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
2212
+ yield converted;
2213
+ } else if (converted) {
2214
+ yield converted;
1975
2215
  }
1976
- yield converted;
1977
- } else if (converted) {
1978
- yield converted;
1979
2216
  }
2217
+ } catch (error) {
2218
+ const message = error instanceof Error ? error.message : String(error);
2219
+ const runError = {
2220
+ type: "run_error",
2221
+ data: {
2222
+ message,
2223
+ code: "STREAM_ERROR"
2224
+ }
2225
+ };
2226
+ yield runError;
1980
2227
  }
1981
- }();
2228
+ })();
1982
2229
  }
1983
2230
  /**
1984
2231
  * Validate that required external tools are registered before invoking.
@@ -2006,12 +2253,16 @@ var Agent = class _Agent {
2006
2253
  };
2007
2254
  }
2008
2255
  /**
2009
- * Enhance message params with tool definitions
2256
+ * Enhance message params with tool definitions and dynamic metadata.
2257
+ *
2258
+ * When `dynamic_sections` or `dynamic_values` are present in `params.metadata`,
2259
+ * they are forwarded so the server injects them into the prompt template.
2010
2260
  */
2011
2261
  enhanceParamsWithTools(params, tools) {
2012
2262
  this.assertExternalTools(tools);
2263
+ const existingMeta = params.metadata ?? {};
2013
2264
  const metadata = {
2014
- ...params.metadata,
2265
+ ...existingMeta,
2015
2266
  external_tools: tools?.map((tool) => ({
2016
2267
  name: tool.name,
2017
2268
  description: tool.description,