@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.js CHANGED
@@ -55,8 +55,14 @@ module.exports = __toCommonJS(index_exports);
55
55
  function isArrayParts(result) {
56
56
  return Array.isArray(result) && result[0].part_type;
57
57
  }
58
- function createSuccessfulToolResult(toolCallId, toolName, result) {
59
- const parts = isArrayParts(result) ? result : [{
58
+ function createSuccessfulToolResult(toolCallId, toolName, result, explicitPartsMetadata) {
59
+ console.log("[createSuccessfulToolResult] toolName:", toolName);
60
+ console.log("[createSuccessfulToolResult] isArrayParts:", isArrayParts(result));
61
+ console.log("[createSuccessfulToolResult] result type:", typeof result, Array.isArray(result) ? `array[${result.length}]` : "");
62
+ if (isArrayParts(result)) {
63
+ console.log("[createSuccessfulToolResult] parts:", result.map((p) => ({ part_type: p.part_type, hasMetadata: !!p.__metadata })));
64
+ }
65
+ const rawParts = isArrayParts(result) ? result : [{
60
66
  part_type: "data",
61
67
  data: {
62
68
  result,
@@ -64,10 +70,22 @@ function createSuccessfulToolResult(toolCallId, toolName, result) {
64
70
  error: void 0
65
71
  }
66
72
  }];
73
+ const parts_metadata = { ...explicitPartsMetadata };
74
+ const parts = rawParts.map((part, index) => {
75
+ if ("__metadata" in part && part.__metadata) {
76
+ parts_metadata[index] = { ...parts_metadata[index], ...part.__metadata };
77
+ }
78
+ if (part.part_type === "image" && !parts_metadata[index]) {
79
+ parts_metadata[index] = { save: false };
80
+ }
81
+ const { __metadata, ...cleanPart } = part;
82
+ return cleanPart;
83
+ });
67
84
  return {
68
85
  tool_call_id: toolCallId,
69
86
  tool_name: toolName,
70
- parts
87
+ parts,
88
+ parts_metadata: Object.keys(parts_metadata).length > 0 ? parts_metadata : void 0
71
89
  };
72
90
  }
73
91
  function createFailedToolResult(toolCallId, toolName, error, result) {
@@ -543,11 +561,22 @@ var A2AClient = class {
543
561
  // src/encoder.ts
544
562
  function convertA2AMessageToDistri(a2aMessage) {
545
563
  const role = a2aMessage.role === "agent" ? "assistant" : "user";
564
+ let agent_id;
565
+ let agent_name;
566
+ if (a2aMessage.metadata) {
567
+ const metadata = a2aMessage.metadata;
568
+ if (metadata.agent) {
569
+ agent_id = metadata.agent.agent_id;
570
+ agent_name = metadata.agent.agent_name;
571
+ }
572
+ }
546
573
  return {
547
574
  id: a2aMessage.messageId,
548
575
  role,
549
576
  parts: a2aMessage.parts.map(convertA2APartToDistri),
550
- created_at: a2aMessage.createdAt
577
+ created_at: a2aMessage.createdAt,
578
+ agent_id,
579
+ agent_name
551
580
  };
552
581
  }
553
582
  function convertA2AStatusUpdateToDistri(statusUpdate) {
@@ -570,8 +599,8 @@ function convertA2AStatusUpdateToDistri(statusUpdate) {
570
599
  const runErrorResult = {
571
600
  type: "run_error",
572
601
  data: {
573
- message: statusUpdate.error,
574
- code: statusUpdate.code
602
+ message: metadata.message || statusUpdate.status?.message || "Unknown error",
603
+ code: metadata.code
575
604
  }
576
605
  };
577
606
  return runErrorResult;
@@ -741,6 +770,19 @@ function convertA2AStatusUpdateToDistri(statusUpdate) {
741
770
  };
742
771
  return browserSessionStarted;
743
772
  }
773
+ case "todos_updated": {
774
+ const todos = parseTodosFromFormatted(metadata.formatted_todos || "");
775
+ const todosUpdated = {
776
+ type: "todos_updated",
777
+ data: {
778
+ formatted_todos: metadata.formatted_todos || "",
779
+ action: metadata.action || "write_todos",
780
+ todo_count: metadata.todo_count || 0,
781
+ todos
782
+ }
783
+ };
784
+ return todosUpdated;
785
+ }
744
786
  default: {
745
787
  console.warn(`Unhandled status update metadata type: ${metadata.type}`, metadata);
746
788
  const defaultResult = {
@@ -792,7 +834,7 @@ function convertA2APartToDistri(a2aPart) {
792
834
  const fileUrl = { type: "url", mime_type: a2aPart.file.mimeType || "application/octet-stream", url: a2aPart.file.uri || "" };
793
835
  return { part_type: "image", data: fileUrl };
794
836
  } else {
795
- const fileBytes = { type: "bytes", mime_type: a2aPart.file.mimeType || "application/octet-stream", data: a2aPart.file.bytes || "" };
837
+ const fileBytes = { type: "bytes", mime_type: a2aPart.file.mimeType || "application/octet-stream", bytes: a2aPart.file.bytes || "" };
796
838
  return { part_type: "image", data: fileBytes };
797
839
  }
798
840
  case "data":
@@ -831,7 +873,8 @@ function convertDistriMessageToA2A(distriMessage, context) {
831
873
  parts: distriMessage.parts.map(convertDistriPartToA2A),
832
874
  kind: "message",
833
875
  contextId: context.thread_id,
834
- taskId: context.task_id || context.run_id || void 0
876
+ taskId: context.task_id || context.run_id || void 0,
877
+ metadata: distriMessage.metadata
835
878
  };
836
879
  }
837
880
  function convertDistriPartToA2A(distriPart) {
@@ -845,7 +888,7 @@ function convertDistriPartToA2A(distriPart) {
845
888
  const fileUri = { mimeType: distriPart.data.mime_type, uri: distriPart.data.url };
846
889
  result = { kind: "file", file: fileUri };
847
890
  } else {
848
- const fileBytes = { mimeType: distriPart.data.mime_type, bytes: distriPart.data.data };
891
+ const fileBytes = { mimeType: distriPart.data.mime_type, bytes: distriPart.data.bytes };
849
892
  result = { kind: "file", file: fileBytes };
850
893
  }
851
894
  break;
@@ -910,6 +953,32 @@ function extractToolCallsFromDistriMessage(message) {
910
953
  function extractToolResultsFromDistriMessage(message) {
911
954
  return message.parts.filter((part) => part.part_type === "tool_result").map((part) => part.data);
912
955
  }
956
+ function parseTodosFromFormatted(formatted) {
957
+ if (!formatted || formatted === "\u25A1 No todos") {
958
+ return [];
959
+ }
960
+ const lines = formatted.split("\n").filter((line) => line.trim());
961
+ return lines.map((line, index) => {
962
+ const trimmed = line.trim();
963
+ let status = "open";
964
+ let content = trimmed;
965
+ if (trimmed.startsWith("\u25A0")) {
966
+ status = "done";
967
+ content = trimmed.slice(1).trim();
968
+ } else if (trimmed.startsWith("\u25D0")) {
969
+ status = "in_progress";
970
+ content = trimmed.slice(1).trim();
971
+ } else if (trimmed.startsWith("\u25A1")) {
972
+ status = "open";
973
+ content = trimmed.slice(1).trim();
974
+ }
975
+ return {
976
+ id: `todo_${index}`,
977
+ content,
978
+ status
979
+ };
980
+ });
981
+ }
913
982
 
914
983
  // src/distri-client.ts
915
984
  var _DistriClient = class _DistriClient {
@@ -1456,7 +1525,12 @@ var _DistriClient = class _DistriClient {
1456
1525
  }
1457
1526
  }
1458
1527
  if (error instanceof Error) {
1459
- return error.message;
1528
+ const msg = error.message;
1529
+ const sseMatch = msg.match(/SSE event contained an error:\s*(.+?)\s*\(Code:/);
1530
+ if (sseMatch) return sseMatch[1];
1531
+ const rpcMatch = msg.match(/RPC Error:\s*(.+?)\s*\(Code:/);
1532
+ if (rpcMatch) return rpcMatch[1];
1533
+ return msg;
1460
1534
  }
1461
1535
  return String(error);
1462
1536
  }
@@ -1520,11 +1594,19 @@ var _DistriClient = class _DistriClient {
1520
1594
  }
1521
1595
  }
1522
1596
  /**
1523
- * Get agents sorted by thread count (most active first)
1597
+ * Get agents sorted by thread count (most active first).
1598
+ * Includes all registered agents, even those with 0 threads.
1599
+ * Optionally filter by name with search parameter.
1524
1600
  */
1525
- async getAgentsByUsage() {
1601
+ async getAgentsByUsage(options) {
1526
1602
  try {
1527
- const response = await this.fetch("/threads/agents");
1603
+ const params = new URLSearchParams();
1604
+ if (options?.search) {
1605
+ params.set("search", options.search);
1606
+ }
1607
+ const query = params.toString();
1608
+ const url = query ? `/threads/agents?${query}` : "/threads/agents";
1609
+ const response = await this.fetch(url);
1528
1610
  if (!response.ok) {
1529
1611
  throw new ApiError(`Failed to fetch agents by usage: ${response.statusText}`, response.status);
1530
1612
  }
@@ -1589,6 +1671,138 @@ var _DistriClient = class _DistriClient {
1589
1671
  const messages = await this.getThreadMessages(threadId);
1590
1672
  return messages.map(convertA2AMessageToDistri);
1591
1673
  }
1674
+ // ========== Message Read Status Methods ==========
1675
+ /**
1676
+ * Mark a message as read
1677
+ */
1678
+ async markMessageRead(threadId, messageId) {
1679
+ try {
1680
+ const response = await this.fetch(
1681
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/read`,
1682
+ { method: "POST" }
1683
+ );
1684
+ if (!response.ok) {
1685
+ throw new ApiError(`Failed to mark message as read: ${response.statusText}`, response.status);
1686
+ }
1687
+ return await response.json();
1688
+ } catch (error) {
1689
+ if (error instanceof ApiError) throw error;
1690
+ throw new DistriError(`Failed to mark message ${messageId} as read`, "MARK_READ_ERROR", error);
1691
+ }
1692
+ }
1693
+ /**
1694
+ * Get read status for a specific message
1695
+ */
1696
+ async getMessageReadStatus(threadId, messageId) {
1697
+ try {
1698
+ const response = await this.fetch(
1699
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/read`
1700
+ );
1701
+ if (response.status === 404) {
1702
+ return null;
1703
+ }
1704
+ if (!response.ok) {
1705
+ throw new ApiError(`Failed to get message read status: ${response.statusText}`, response.status);
1706
+ }
1707
+ return await response.json();
1708
+ } catch (error) {
1709
+ if (error instanceof ApiError) throw error;
1710
+ throw new DistriError(`Failed to get read status for message ${messageId}`, "FETCH_ERROR", error);
1711
+ }
1712
+ }
1713
+ /**
1714
+ * Get read status for all messages in a thread
1715
+ */
1716
+ async getThreadReadStatus(threadId) {
1717
+ try {
1718
+ const response = await this.fetch(
1719
+ `/threads/${encodeURIComponent(threadId)}/read-status`
1720
+ );
1721
+ if (!response.ok) {
1722
+ throw new ApiError(`Failed to get thread read status: ${response.statusText}`, response.status);
1723
+ }
1724
+ return await response.json();
1725
+ } catch (error) {
1726
+ if (error instanceof ApiError) throw error;
1727
+ throw new DistriError(`Failed to get read status for thread ${threadId}`, "FETCH_ERROR", error);
1728
+ }
1729
+ }
1730
+ // ========== Message Voting Methods ==========
1731
+ /**
1732
+ * Vote on a message (upvote or downvote)
1733
+ * Downvotes require a comment explaining the issue
1734
+ */
1735
+ async voteMessage(threadId, messageId, request) {
1736
+ try {
1737
+ const response = await this.fetch(
1738
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`,
1739
+ {
1740
+ method: "POST",
1741
+ headers: { "Content-Type": "application/json" },
1742
+ body: JSON.stringify(request)
1743
+ }
1744
+ );
1745
+ if (!response.ok) {
1746
+ const errorData = await response.json().catch(() => ({}));
1747
+ throw new ApiError(errorData.error || `Failed to vote on message: ${response.statusText}`, response.status);
1748
+ }
1749
+ return await response.json();
1750
+ } catch (error) {
1751
+ if (error instanceof ApiError) throw error;
1752
+ throw new DistriError(`Failed to vote on message ${messageId}`, "VOTE_ERROR", error);
1753
+ }
1754
+ }
1755
+ /**
1756
+ * Remove vote from a message
1757
+ */
1758
+ async removeVote(threadId, messageId) {
1759
+ try {
1760
+ const response = await this.fetch(
1761
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`,
1762
+ { method: "DELETE" }
1763
+ );
1764
+ if (!response.ok && response.status !== 204) {
1765
+ throw new ApiError(`Failed to remove vote: ${response.statusText}`, response.status);
1766
+ }
1767
+ } catch (error) {
1768
+ if (error instanceof ApiError) throw error;
1769
+ throw new DistriError(`Failed to remove vote from message ${messageId}`, "VOTE_ERROR", error);
1770
+ }
1771
+ }
1772
+ /**
1773
+ * Get vote summary for a message (counts + current user's vote)
1774
+ */
1775
+ async getMessageVoteSummary(threadId, messageId) {
1776
+ try {
1777
+ const response = await this.fetch(
1778
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/vote`
1779
+ );
1780
+ if (!response.ok) {
1781
+ throw new ApiError(`Failed to get vote summary: ${response.statusText}`, response.status);
1782
+ }
1783
+ return await response.json();
1784
+ } catch (error) {
1785
+ if (error instanceof ApiError) throw error;
1786
+ throw new DistriError(`Failed to get vote summary for message ${messageId}`, "FETCH_ERROR", error);
1787
+ }
1788
+ }
1789
+ /**
1790
+ * Get all votes for a message (admin/analytics use)
1791
+ */
1792
+ async getMessageVotes(threadId, messageId) {
1793
+ try {
1794
+ const response = await this.fetch(
1795
+ `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/votes`
1796
+ );
1797
+ if (!response.ok) {
1798
+ throw new ApiError(`Failed to get message votes: ${response.statusText}`, response.status);
1799
+ }
1800
+ return await response.json();
1801
+ } catch (error) {
1802
+ if (error instanceof ApiError) throw error;
1803
+ throw new DistriError(`Failed to get votes for message ${messageId}`, "FETCH_ERROR", error);
1804
+ }
1805
+ }
1592
1806
  /**
1593
1807
  * Send a DistriMessage to a thread
1594
1808
  */
@@ -1614,7 +1828,12 @@ var _DistriClient = class _DistriClient {
1614
1828
  },
1615
1829
  body: JSON.stringify({
1616
1830
  tool_call_id: result.tool_call_id,
1617
- tool_response: result
1831
+ tool_response: {
1832
+ tool_call_id: result.tool_call_id,
1833
+ tool_name: result.tool_name,
1834
+ parts: result.parts,
1835
+ parts_metadata: result.parts_metadata
1836
+ }
1618
1837
  })
1619
1838
  });
1620
1839
  if (!response.ok) {
@@ -1878,9 +2097,17 @@ var _DistriClient = class _DistriClient {
1878
2097
  };
1879
2098
  }
1880
2099
  /**
1881
- * Helper method to create message send parameters
1882
- */
1883
- static initMessageParams(message, configuration, metadata) {
2100
+ * Helper method to create message send parameters.
2101
+ *
2102
+ * Pass `dynamicMetadata` to inject `dynamic_sections` and/or `dynamic_values`
2103
+ * into the metadata so the server can apply them to prompt templates.
2104
+ */
2105
+ static initMessageParams(message, configuration, metadata, dynamicMetadata) {
2106
+ const mergedMetadata = {
2107
+ ...metadata,
2108
+ ...dynamicMetadata?.dynamic_sections ? { dynamic_sections: dynamicMetadata.dynamic_sections } : {},
2109
+ ...dynamicMetadata?.dynamic_values ? { dynamic_values: dynamicMetadata.dynamic_values } : {}
2110
+ };
1884
2111
  return {
1885
2112
  message,
1886
2113
  configuration: {
@@ -1889,18 +2116,26 @@ var _DistriClient = class _DistriClient {
1889
2116
  // Default to non-blocking for streaming
1890
2117
  ...configuration
1891
2118
  },
1892
- metadata
2119
+ metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : metadata
1893
2120
  };
1894
2121
  }
1895
2122
  /**
1896
- * Create MessageSendParams from a DistriMessage using InvokeContext
2123
+ * Create MessageSendParams from a DistriMessage using InvokeContext.
2124
+ *
2125
+ * Pass `dynamicMetadata` to inject `dynamic_sections` and/or `dynamic_values`
2126
+ * into the metadata so the server can apply them to prompt templates.
1897
2127
  */
1898
- static initDistriMessageParams(message, context) {
2128
+ static initDistriMessageParams(message, context, dynamicMetadata) {
1899
2129
  const a2aMessage = convertDistriMessageToA2A(message, context);
1900
2130
  const contextMetadata = context.getMetadata?.() || {};
2131
+ const mergedMetadata = {
2132
+ ...contextMetadata,
2133
+ ...dynamicMetadata?.dynamic_sections ? { dynamic_sections: dynamicMetadata.dynamic_sections } : {},
2134
+ ...dynamicMetadata?.dynamic_values ? { dynamic_values: dynamicMetadata.dynamic_values } : {}
2135
+ };
1901
2136
  return {
1902
2137
  message: a2aMessage,
1903
- metadata: contextMetadata
2138
+ metadata: Object.keys(mergedMetadata).length > 0 ? mergedMetadata : contextMetadata
1904
2139
  };
1905
2140
  }
1906
2141
  };
@@ -2006,28 +2241,40 @@ var Agent = class _Agent {
2006
2241
  const enhancedParams = this.enhanceParamsWithTools(params, tools);
2007
2242
  const a2aStream = this.client.sendMessageStream(this.agentDefinition.id, enhancedParams);
2008
2243
  const self = this;
2009
- return async function* () {
2010
- for await (const event of a2aStream) {
2011
- const converted = decodeA2AStreamEvent(event);
2012
- if (converted && converted.type === "inline_hook_requested") {
2013
- const hookReq = converted.data;
2014
- const handler = self.hookHandlers.get(hookReq.hook) || self.defaultHookHandler;
2015
- if (handler) {
2016
- try {
2017
- const mutation = await handler(hookReq);
2018
- await self.client.completeInlineHook(hookReq.hook_id, mutation);
2019
- } catch (err) {
2244
+ return (async function* () {
2245
+ try {
2246
+ for await (const event of a2aStream) {
2247
+ const converted = decodeA2AStreamEvent(event);
2248
+ if (converted && converted.type === "inline_hook_requested") {
2249
+ const hookReq = converted.data;
2250
+ const handler = self.hookHandlers.get(hookReq.hook) || self.defaultHookHandler;
2251
+ if (handler) {
2252
+ try {
2253
+ const mutation = await handler(hookReq);
2254
+ await self.client.completeInlineHook(hookReq.hook_id, mutation);
2255
+ } catch (err) {
2256
+ await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
2257
+ }
2258
+ } else {
2020
2259
  await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
2021
2260
  }
2022
- } else {
2023
- await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
2261
+ yield converted;
2262
+ } else if (converted) {
2263
+ yield converted;
2024
2264
  }
2025
- yield converted;
2026
- } else if (converted) {
2027
- yield converted;
2028
2265
  }
2266
+ } catch (error) {
2267
+ const message = error instanceof Error ? error.message : String(error);
2268
+ const runError = {
2269
+ type: "run_error",
2270
+ data: {
2271
+ message,
2272
+ code: "STREAM_ERROR"
2273
+ }
2274
+ };
2275
+ yield runError;
2029
2276
  }
2030
- }();
2277
+ })();
2031
2278
  }
2032
2279
  /**
2033
2280
  * Validate that required external tools are registered before invoking.
@@ -2055,12 +2302,16 @@ var Agent = class _Agent {
2055
2302
  };
2056
2303
  }
2057
2304
  /**
2058
- * Enhance message params with tool definitions
2305
+ * Enhance message params with tool definitions and dynamic metadata.
2306
+ *
2307
+ * When `dynamic_sections` or `dynamic_values` are present in `params.metadata`,
2308
+ * they are forwarded so the server injects them into the prompt template.
2059
2309
  */
2060
2310
  enhanceParamsWithTools(params, tools) {
2061
2311
  this.assertExternalTools(tools);
2312
+ const existingMeta = params.metadata ?? {};
2062
2313
  const metadata = {
2063
- ...params.metadata,
2314
+ ...existingMeta,
2064
2315
  external_tools: tools?.map((tool) => ({
2065
2316
  name: tool.name,
2066
2317
  description: tool.description,