agents 0.3.6 → 0.3.7

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.
Files changed (69) hide show
  1. package/README.md +303 -314
  2. package/dist/ai-types.js +1 -1
  3. package/dist/{client-0lfEZpSQ.js → client-6CeOh-EV.js} +7 -3
  4. package/dist/client-6CeOh-EV.js.map +1 -0
  5. package/dist/{client-Cxno-5sH.d.ts → client-DGpERepg.d.ts} +8 -14
  6. package/dist/client.d.ts +80 -24
  7. package/dist/client.js +184 -2
  8. package/dist/client.js.map +1 -0
  9. package/dist/{do-oauth-client-provider-BH9zFtSy.d.ts → do-oauth-client-provider-BqnOQzjy.d.ts} +1 -1
  10. package/dist/{do-oauth-client-provider-BfPFgQU0.js → do-oauth-client-provider-DDg8QrEA.js} +1 -1
  11. package/dist/{do-oauth-client-provider-BfPFgQU0.js.map → do-oauth-client-provider-DDg8QrEA.js.map} +1 -1
  12. package/dist/email-8ljcpvwV.d.ts +157 -0
  13. package/dist/email-XHsSYsTO.js +223 -0
  14. package/dist/email-XHsSYsTO.js.map +1 -0
  15. package/dist/email.d.ts +30 -0
  16. package/dist/email.js +3 -0
  17. package/dist/{index-B7Ny-XfU.d.ts → index-N6791tVt.d.ts} +18 -3
  18. package/dist/index.d.ts +543 -87
  19. package/dist/index.js +6 -6
  20. package/dist/{internal_context-neg89p5n.d.ts → internal_context-CEu5ji80.d.ts} +8 -3
  21. package/dist/{internal_context-oN047Id3.js → internal_context-D9eKFth1.js} +1 -1
  22. package/dist/internal_context-D9eKFth1.js.map +1 -0
  23. package/dist/internal_context.d.ts +1 -1
  24. package/dist/internal_context.js +1 -1
  25. package/dist/mcp/client.d.ts +1 -1
  26. package/dist/mcp/client.js +2 -2
  27. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  28. package/dist/mcp/do-oauth-client-provider.js +1 -1
  29. package/dist/mcp/index.d.ts +4 -2
  30. package/dist/mcp/index.js +35 -35
  31. package/dist/mcp/index.js.map +1 -1
  32. package/dist/mcp/x402.d.ts +0 -1
  33. package/dist/mcp/x402.js.map +1 -1
  34. package/dist/{mcp-AK39tq6H.d.ts → mcp-BwPscEiF.d.ts} +1 -1
  35. package/dist/observability/index.d.ts +1 -1
  36. package/dist/observability/index.js +5 -5
  37. package/dist/react.d.ts +70 -26
  38. package/dist/react.js +83 -21
  39. package/dist/react.js.map +1 -1
  40. package/dist/schedule.d.ts +23 -2
  41. package/dist/schedule.js +23 -1
  42. package/dist/schedule.js.map +1 -1
  43. package/dist/serializable.d.ts +68 -3
  44. package/dist/src-BFP4sOQ4.js +2146 -0
  45. package/dist/src-BFP4sOQ4.js.map +1 -0
  46. package/dist/types-BITaDFf-.js +16 -0
  47. package/dist/{types-4b5tlB0u.js.map → types-BITaDFf-.js.map} +1 -1
  48. package/dist/{types-C5vR2Gzv.d.ts → types-DSSHBW6w.d.ts} +2 -1
  49. package/dist/types.d.ts +1 -1
  50. package/dist/types.js +1 -1
  51. package/dist/utils-B49TmLCI.js +16 -0
  52. package/dist/utils-B49TmLCI.js.map +1 -0
  53. package/dist/utils.d.ts +10 -0
  54. package/dist/utils.js +3 -0
  55. package/dist/workflow-types-Z_Oem1FJ.d.ts +260 -0
  56. package/dist/workflow-types.d.ts +48 -0
  57. package/dist/workflow-types.js +16 -0
  58. package/dist/workflow-types.js.map +1 -0
  59. package/dist/workflows.d.ts +163 -0
  60. package/dist/workflows.js +240 -0
  61. package/dist/workflows.js.map +1 -0
  62. package/package.json +22 -12
  63. package/dist/client-0lfEZpSQ.js.map +0 -1
  64. package/dist/client-CEO0P7vN.js +0 -117
  65. package/dist/client-CEO0P7vN.js.map +0 -1
  66. package/dist/internal_context-oN047Id3.js.map +0 -1
  67. package/dist/src-C_iKczoR.js +0 -1191
  68. package/dist/src-C_iKczoR.js.map +0 -1
  69. package/dist/types-4b5tlB0u.js +0 -15
@@ -1 +1 @@
1
- {"version":3,"file":"x402.js","names":["decoded: PaymentPayload","result: CallToolResult","listTools: typeof _listTools"],"sources":["../../src/mcp/x402.ts"],"sourcesContent":["/**\n * X402 MCP Integration\n *\n * Based on:\n * - Coinbase's x402 (Apache 2.0): https://github.com/coinbase/x402\n * - @ethanniser and his work at https://github.com/ethanniser/x402-mcp\n */\n\nimport type {\n McpServer,\n RegisteredTool,\n ToolCallback\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Client as MCPClient } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type {\n CallToolResultSchema,\n CompatibilityCallToolResultSchema,\n CallToolRequest,\n CallToolResult,\n ToolAnnotations\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ZodRawShape } from \"zod\";\nimport { base, baseSepolia, type Chain } from \"viem/chains\";\n\nimport { processPriceToAtomicAmount } from \"x402/shared\";\nimport { exact } from \"x402/schemes\";\nimport { useFacilitator } from \"x402/verify\";\nimport type {\n FacilitatorConfig,\n Network,\n PaymentPayload,\n PaymentRequirements,\n Wallet\n} from \"x402/types\";\nimport type { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport { createWalletClient, http, type Account } from \"viem\";\nimport { createPaymentHeader } from \"x402/client\";\n\n/*\n ======= SERVER SIDE =======\n*/\n\nexport type X402Config = {\n network: Network;\n recipient: `0x${string}`;\n facilitator: FacilitatorConfig;\n version?: number;\n};\n\nexport interface X402AugmentedServer {\n paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool;\n}\n\nexport function withX402<T extends McpServer>(\n server: McpServer,\n cfg: X402Config\n): T & X402AugmentedServer {\n const { verify, settle } = useFacilitator(cfg.facilitator);\n const x402Version = cfg.version ?? 1;\n\n function paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool {\n return server.registerTool(\n name,\n {\n description,\n inputSchema: paramsSchema,\n annotations,\n _meta: {\n \"agents-x402/paymentRequired\": true,\n \"agents-x402/priceUSD\": priceUSD\n }\n },\n (async (args, extra) => {\n // Build PaymentRequirements for this call\n const atomic = processPriceToAtomicAmount(priceUSD, cfg.network);\n if (\"error\" in atomic) {\n const payload = { x402Version, error: \"PRICE_COMPUTE_FAILED\" };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n }\n const { maxAmountRequired, asset } = atomic;\n const requirements = {\n scheme: \"exact\" as const,\n network: cfg.network,\n maxAmountRequired,\n payTo: cfg.recipient,\n asset: asset.address,\n maxTimeoutSeconds: 300,\n resource: `x402://${name}`,\n mimeType: \"application/json\" as const,\n description,\n extra: \"eip712\" in asset ? asset.eip712 : undefined\n };\n\n // Get token either from MCP _meta or from header\n const headers = extra?.requestInfo?.headers ?? {};\n const token =\n (extra?._meta?.[\"x402/payment\"] as string | undefined) ??\n headers[\"X-PAYMENT\"];\n\n const paymentRequired = (\n reason = \"PAYMENT_REQUIRED\",\n extraFields: Record<string, unknown> = {}\n ) => {\n const payload = {\n x402Version,\n error: reason,\n accepts: [requirements],\n ...extraFields\n };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n };\n\n if (!token || typeof token !== \"string\") return paymentRequired();\n\n // Decode & verify\n let decoded: PaymentPayload;\n try {\n decoded = exact.evm.decodePayment(token);\n decoded.x402Version = x402Version;\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n const vr = await verify(decoded, requirements);\n if (!vr.isValid) {\n return paymentRequired(vr.invalidReason ?? \"INVALID_PAYMENT\", {\n payer: vr.payer\n });\n }\n\n // Execute tool\n let result: CallToolResult;\n let failed = false;\n try {\n result = await cb(args, extra);\n if (\n result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError\n ) {\n failed = true;\n }\n } catch (e) {\n failed = true;\n result = {\n isError: true,\n content: [\n { type: \"text\", text: `Tool execution failed: ${String(e)}` }\n ]\n };\n }\n\n // Settle only on success\n if (!failed) {\n try {\n const s = await settle(decoded, requirements);\n if (s.success) {\n result._meta ??= {};\n result._meta[\"x402/payment-response\"] = {\n success: true,\n transaction: s.transaction,\n network: s.network,\n payer: s.payer\n };\n } else {\n return paymentRequired(s.errorReason ?? \"SETTLEMENT_FAILED\");\n }\n } catch {\n return paymentRequired(\"SETTLEMENT_FAILED\");\n }\n }\n\n return result;\n }) as ToolCallback<Args>\n );\n }\n\n Object.defineProperty(server, \"paidTool\", {\n value: paidTool,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n // Tell TS the object now also has the paidTool method\n return server as T & X402AugmentedServer;\n}\n\n/*\n ======= CLIENT SIDE =======\n*/\n\nconst toChain = (network: Network): Chain => {\n switch (network) {\n case \"base\":\n return base;\n case \"base-sepolia\":\n return baseSepolia;\n default:\n throw new Error(`Unsupported network: ${network}`);\n }\n};\n\nexport interface X402AugmentedClient {\n callTool(\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): Promise<CallToolResult>;\n}\n\nexport type X402ClientConfig = {\n network: Network; // we only support base and base-sepolia for now\n account: Account;\n maxPaymentValue?: bigint;\n version?: number;\n confirmationCallback?: (payment: PaymentRequirements[]) => Promise<boolean>; // Confirmation callback for payment\n};\n\nexport function withX402Client<T extends MCPClient>(\n client: T,\n x402Config: X402ClientConfig\n): X402AugmentedClient & T {\n const { network, account, version } = x402Config;\n const wallet = createWalletClient({\n account,\n transport: http(),\n chain: toChain(network)\n });\n\n const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(0.1 * 10 ** 6); // 0.10 USDC\n\n const _listTools = client.listTools.bind(client);\n\n // Wrap the original method to include payment information in the description\n const listTools: typeof _listTools = async (params, options) => {\n const toolsRes = await _listTools(params, options);\n toolsRes.tools = toolsRes.tools.map((tool) => {\n let description = tool.description;\n // Check _meta for payment information (agents-x402/ is our extension for pre-advertising prices)\n if (tool._meta?.[\"agents-x402/paymentRequired\"]) {\n const cost = tool._meta?.[\"agents-x402/priceUSD\"]\n ? `$${tool._meta?.[\"agents-x402/priceUSD\"]}`\n : \"an unknown amount\";\n description += ` (This is a paid tool, you will be charged ${cost} for its execution)`;\n }\n return {\n ...tool,\n description\n };\n });\n\n // Wrap each tool to add payment support\n\n return toolsRes;\n };\n\n const _callTool = client.callTool.bind(client);\n\n const callToolWithPayment = async (\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): ReturnType<typeof client.callTool> => {\n // call the tool\n const res = await _callTool(params, resultSchema, options);\n console.log(\"res\", res);\n\n // If it errored and returned accepts, we need to confirm payment\n const maybeX402Error = res._meta?.[\"x402/error\"] as\n | { accepts: PaymentRequirements[] }\n | undefined;\n\n if (\n res.isError &&\n maybeX402Error &&\n maybeX402Error.accepts &&\n Array.isArray(maybeX402Error.accepts) &&\n maybeX402Error.accepts.length > 0\n ) {\n const accepts = maybeX402Error.accepts;\n const confirmationCallback =\n x402ConfirmationCallback ?? x402Config.confirmationCallback;\n\n // Use the x402 confirmation callback if provided\n if (confirmationCallback && !(await confirmationCallback(accepts))) {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"User declined payment\" }]\n };\n }\n\n // Pick the first exact-scheme requirement that matches our network\n // (we're only setting one on the McpAgent side for now)\n const req =\n accepts.find((a) => a?.scheme === \"exact\" && a?.network === network) ??\n accepts[0];\n\n if (!req || req.scheme !== \"exact\") return res;\n\n const maxAmountRequired = BigInt(req.maxAmountRequired);\n if (maxAmountRequired > maxPaymentValue) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Payment exceeds client cap: ${maxAmountRequired} > ${maxPaymentValue}`\n }\n ]\n };\n }\n\n // Use x402/client to get the X-PAYMENT token\n const token = await createPaymentHeader(\n wallet as Wallet,\n version ?? 1,\n req\n );\n\n // Call the tool with the payment token\n return _callTool(\n {\n ...params,\n _meta: {\n ...params._meta,\n \"x402/payment\": token\n }\n },\n resultSchema,\n options\n );\n }\n\n return res;\n };\n\n const _client = client as X402AugmentedClient & T;\n _client.listTools = listTools;\n Object.defineProperty(_client, \"callTool\", {\n value: callToolWithPayment,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n return _client;\n}\n"],"mappings":";;;;;;;;AA4DA,SAAgB,SACd,QACA,KACyB;CACzB,MAAM,EAAE,QAAQ,WAAW,eAAe,IAAI,YAAY;CAC1D,MAAM,cAAc,IAAI,WAAW;CAEnC,SAAS,SACP,MACA,aACA,UACA,cACA,aACA,IACgB;AAChB,SAAO,OAAO,aACZ,MACA;GACE;GACA,aAAa;GACb;GACA,OAAO;IACL,+BAA+B;IAC/B,wBAAwB;IACzB;GACF,GACA,OAAO,MAAM,UAAU;GAEtB,MAAM,SAAS,2BAA2B,UAAU,IAAI,QAAQ;AAChE,OAAI,WAAW,QAAQ;IACrB,MAAM,UAAU;KAAE;KAAa,OAAO;KAAwB;AAC9D,WAAO;KACL,SAAS;KACT,OAAO,EAAE,cAAc,SAAS;KAChC,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,KAAK,UAAU,QAAQ;MAAE,CAAC;KAC3D;;GAEH,MAAM,EAAE,mBAAmB,UAAU;GACrC,MAAM,eAAe;IACnB,QAAQ;IACR,SAAS,IAAI;IACb;IACA,OAAO,IAAI;IACX,OAAO,MAAM;IACb,mBAAmB;IACnB,UAAU,UAAU;IACpB,UAAU;IACV;IACA,OAAO,YAAY,QAAQ,MAAM,SAAS;IAC3C;GAGD,MAAM,UAAU,OAAO,aAAa,WAAW,EAAE;GACjD,MAAM,QACH,OAAO,QAAQ,mBAChB,QAAQ;GAEV,MAAM,mBACJ,SAAS,oBACT,cAAuC,EAAE,KACtC;IACH,MAAM,UAAU;KACd;KACA,OAAO;KACP,SAAS,CAAC,aAAa;KACvB,GAAG;KACJ;AACD,WAAO;KACL,SAAS;KACT,OAAO,EAAE,cAAc,SAAS;KAChC,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,KAAK,UAAU,QAAQ;MAAE,CAAC;KAC3D;;AAGH,OAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO,iBAAiB;GAGjE,IAAIA;AACJ,OAAI;AACF,cAAU,MAAM,IAAI,cAAc,MAAM;AACxC,YAAQ,cAAc;WAChB;AACN,WAAO,gBAAgB,kBAAkB;;GAG3C,MAAM,KAAK,MAAM,OAAO,SAAS,aAAa;AAC9C,OAAI,CAAC,GAAG,QACN,QAAO,gBAAgB,GAAG,iBAAiB,mBAAmB,EAC5D,OAAO,GAAG,OACX,CAAC;GAIJ,IAAIC;GACJ,IAAI,SAAS;AACb,OAAI;AACF,aAAS,MAAM,GAAG,MAAM,MAAM;AAC9B,QACE,UACA,OAAO,WAAW,YAClB,aAAa,UACb,OAAO,QAEP,UAAS;YAEJ,GAAG;AACV,aAAS;AACT,aAAS;KACP,SAAS;KACT,SAAS,CACP;MAAE,MAAM;MAAQ,MAAM,0BAA0B,OAAO,EAAE;MAAI,CAC9D;KACF;;AAIH,OAAI,CAAC,OACH,KAAI;IACF,MAAM,IAAI,MAAM,OAAO,SAAS,aAAa;AAC7C,QAAI,EAAE,SAAS;AACb,YAAO,UAAU,EAAE;AACnB,YAAO,MAAM,2BAA2B;MACtC,SAAS;MACT,aAAa,EAAE;MACf,SAAS,EAAE;MACX,OAAO,EAAE;MACV;UAED,QAAO,gBAAgB,EAAE,eAAe,oBAAoB;WAExD;AACN,WAAO,gBAAgB,oBAAoB;;AAI/C,UAAO;KAEV;;AAGH,QAAO,eAAe,QAAQ,YAAY;EACxC,OAAO;EACP,UAAU;EACV,YAAY;EACZ,cAAc;EACf,CAAC;AAGF,QAAO;;AAOT,MAAM,WAAW,YAA4B;AAC3C,SAAQ,SAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,eACH,QAAO;EACT,QACE,OAAM,IAAI,MAAM,wBAAwB,UAAU;;;AAyBxD,SAAgB,eACd,QACA,YACyB;CACzB,MAAM,EAAE,SAAS,SAAS,YAAY;CACtC,MAAM,SAAS,mBAAmB;EAChC;EACA,WAAW,MAAM;EACjB,OAAO,QAAQ,QAAQ;EACxB,CAAC;CAEF,MAAM,kBAAkB,WAAW,mBAAmB,OAAO,KAAM,MAAM,EAAE;CAE3E,MAAM,aAAa,OAAO,UAAU,KAAK,OAAO;CAGhD,MAAMC,YAA+B,OAAO,QAAQ,YAAY;EAC9D,MAAM,WAAW,MAAM,WAAW,QAAQ,QAAQ;AAClD,WAAS,QAAQ,SAAS,MAAM,KAAK,SAAS;GAC5C,IAAI,cAAc,KAAK;AAEvB,OAAI,KAAK,QAAQ,gCAAgC;IAC/C,MAAM,OAAO,KAAK,QAAQ,0BACtB,IAAI,KAAK,QAAQ,4BACjB;AACJ,mBAAe,8CAA8C,KAAK;;AAEpE,UAAO;IACL,GAAG;IACH;IACD;IACD;AAIF,SAAO;;CAGT,MAAM,YAAY,OAAO,SAAS,KAAK,OAAO;CAE9C,MAAM,sBAAsB,OAC1B,0BAGA,QACA,cAGA,YACuC;EAEvC,MAAM,MAAM,MAAM,UAAU,QAAQ,cAAc,QAAQ;AAC1D,UAAQ,IAAI,OAAO,IAAI;EAGvB,MAAM,iBAAiB,IAAI,QAAQ;AAInC,MACE,IAAI,WACJ,kBACA,eAAe,WACf,MAAM,QAAQ,eAAe,QAAQ,IACrC,eAAe,QAAQ,SAAS,GAChC;GACA,MAAM,UAAU,eAAe;GAC/B,MAAM,uBACJ,4BAA4B,WAAW;AAGzC,OAAI,wBAAwB,CAAE,MAAM,qBAAqB,QAAQ,CAC/D,QAAO;IACL,SAAS;IACT,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM;KAAyB,CAAC;IAC3D;GAKH,MAAM,MACJ,QAAQ,MAAM,MAAM,GAAG,WAAW,WAAW,GAAG,YAAY,QAAQ,IACpE,QAAQ;AAEV,OAAI,CAAC,OAAO,IAAI,WAAW,QAAS,QAAO;GAE3C,MAAM,oBAAoB,OAAO,IAAI,kBAAkB;AACvD,OAAI,oBAAoB,gBACtB,QAAO;IACL,SAAS;IACT,SAAS,CACP;KACE,MAAM;KACN,MAAM,+BAA+B,kBAAkB,KAAK;KAC7D,CACF;IACF;GAIH,MAAM,QAAQ,MAAM,oBAClB,QACA,WAAW,GACX,IACD;AAGD,UAAO,UACL;IACE,GAAG;IACH,OAAO;KACL,GAAG,OAAO;KACV,gBAAgB;KACjB;IACF,EACD,cACA,QACD;;AAGH,SAAO;;CAGT,MAAM,UAAU;AAChB,SAAQ,YAAY;AACpB,QAAO,eAAe,SAAS,YAAY;EACzC,OAAO;EACP,UAAU;EACV,YAAY;EACZ,cAAc;EACf,CAAC;AAEF,QAAO"}
1
+ {"version":3,"file":"x402.js","names":[],"sources":["../../src/mcp/x402.ts"],"sourcesContent":["/**\n * X402 MCP Integration\n *\n * Based on:\n * - Coinbase's x402 (Apache 2.0): https://github.com/coinbase/x402\n * - @ethanniser and his work at https://github.com/ethanniser/x402-mcp\n */\n\nimport type {\n McpServer,\n RegisteredTool,\n ToolCallback\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Client as MCPClient } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type {\n CallToolResultSchema,\n CompatibilityCallToolResultSchema,\n CallToolRequest,\n CallToolResult,\n ToolAnnotations\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ZodRawShape } from \"zod\";\nimport { base, baseSepolia, type Chain } from \"viem/chains\";\n\nimport { processPriceToAtomicAmount } from \"x402/shared\";\nimport { exact } from \"x402/schemes\";\nimport { useFacilitator } from \"x402/verify\";\nimport type {\n FacilitatorConfig,\n Network,\n PaymentPayload,\n PaymentRequirements,\n Wallet\n} from \"x402/types\";\nimport type { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport { createWalletClient, http, type Account } from \"viem\";\nimport { createPaymentHeader } from \"x402/client\";\n\n/*\n ======= SERVER SIDE =======\n*/\n\nexport type X402Config = {\n network: Network;\n recipient: `0x${string}`;\n facilitator: FacilitatorConfig;\n version?: number;\n};\n\nexport interface X402AugmentedServer {\n paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool;\n}\n\nexport function withX402<T extends McpServer>(\n server: McpServer,\n cfg: X402Config\n): T & X402AugmentedServer {\n const { verify, settle } = useFacilitator(cfg.facilitator);\n const x402Version = cfg.version ?? 1;\n\n function paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool {\n return server.registerTool(\n name,\n {\n description,\n inputSchema: paramsSchema,\n annotations,\n _meta: {\n \"agents-x402/paymentRequired\": true,\n \"agents-x402/priceUSD\": priceUSD\n }\n },\n (async (args, extra) => {\n // Build PaymentRequirements for this call\n const atomic = processPriceToAtomicAmount(priceUSD, cfg.network);\n if (\"error\" in atomic) {\n const payload = { x402Version, error: \"PRICE_COMPUTE_FAILED\" };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n }\n const { maxAmountRequired, asset } = atomic;\n const requirements = {\n scheme: \"exact\" as const,\n network: cfg.network,\n maxAmountRequired,\n payTo: cfg.recipient,\n asset: asset.address,\n maxTimeoutSeconds: 300,\n resource: `x402://${name}`,\n mimeType: \"application/json\" as const,\n description,\n extra: \"eip712\" in asset ? asset.eip712 : undefined\n };\n\n // Get token either from MCP _meta or from header\n const headers = extra?.requestInfo?.headers ?? {};\n const token =\n (extra?._meta?.[\"x402/payment\"] as string | undefined) ??\n headers[\"X-PAYMENT\"];\n\n const paymentRequired = (\n reason = \"PAYMENT_REQUIRED\",\n extraFields: Record<string, unknown> = {}\n ) => {\n const payload = {\n x402Version,\n error: reason,\n accepts: [requirements],\n ...extraFields\n };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n };\n\n if (!token || typeof token !== \"string\") return paymentRequired();\n\n // Decode & verify\n let decoded: PaymentPayload;\n try {\n decoded = exact.evm.decodePayment(token);\n decoded.x402Version = x402Version;\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n const vr = await verify(decoded, requirements);\n if (!vr.isValid) {\n return paymentRequired(vr.invalidReason ?? \"INVALID_PAYMENT\", {\n payer: vr.payer\n });\n }\n\n // Execute tool\n let result: CallToolResult;\n let failed = false;\n try {\n result = await cb(args, extra);\n if (\n result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError\n ) {\n failed = true;\n }\n } catch (e) {\n failed = true;\n result = {\n isError: true,\n content: [\n { type: \"text\", text: `Tool execution failed: ${String(e)}` }\n ]\n };\n }\n\n // Settle only on success\n if (!failed) {\n try {\n const s = await settle(decoded, requirements);\n if (s.success) {\n result._meta ??= {};\n result._meta[\"x402/payment-response\"] = {\n success: true,\n transaction: s.transaction,\n network: s.network,\n payer: s.payer\n };\n } else {\n return paymentRequired(s.errorReason ?? \"SETTLEMENT_FAILED\");\n }\n } catch {\n return paymentRequired(\"SETTLEMENT_FAILED\");\n }\n }\n\n return result;\n }) as ToolCallback<Args>\n );\n }\n\n Object.defineProperty(server, \"paidTool\", {\n value: paidTool,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n // Tell TS the object now also has the paidTool method\n return server as T & X402AugmentedServer;\n}\n\n/*\n ======= CLIENT SIDE =======\n*/\n\nconst toChain = (network: Network): Chain => {\n switch (network) {\n case \"base\":\n return base;\n case \"base-sepolia\":\n return baseSepolia;\n default:\n throw new Error(`Unsupported network: ${network}`);\n }\n};\n\nexport interface X402AugmentedClient {\n callTool(\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): Promise<CallToolResult>;\n}\n\nexport type X402ClientConfig = {\n network: Network; // we only support base and base-sepolia for now\n account: Account;\n maxPaymentValue?: bigint;\n version?: number;\n confirmationCallback?: (payment: PaymentRequirements[]) => Promise<boolean>; // Confirmation callback for payment\n};\n\nexport function withX402Client<T extends MCPClient>(\n client: T,\n x402Config: X402ClientConfig\n): X402AugmentedClient & T {\n const { network, account, version } = x402Config;\n const wallet = createWalletClient({\n account,\n transport: http(),\n chain: toChain(network)\n });\n\n const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(0.1 * 10 ** 6); // 0.10 USDC\n\n const _listTools = client.listTools.bind(client);\n\n // Wrap the original method to include payment information in the description\n const listTools: typeof _listTools = async (params, options) => {\n const toolsRes = await _listTools(params, options);\n toolsRes.tools = toolsRes.tools.map((tool) => {\n let description = tool.description;\n // Check _meta for payment information (agents-x402/ is our extension for pre-advertising prices)\n if (tool._meta?.[\"agents-x402/paymentRequired\"]) {\n const cost = tool._meta?.[\"agents-x402/priceUSD\"]\n ? `$${tool._meta?.[\"agents-x402/priceUSD\"]}`\n : \"an unknown amount\";\n description += ` (This is a paid tool, you will be charged ${cost} for its execution)`;\n }\n return {\n ...tool,\n description\n };\n });\n\n // Wrap each tool to add payment support\n\n return toolsRes;\n };\n\n const _callTool = client.callTool.bind(client);\n\n const callToolWithPayment = async (\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): ReturnType<typeof client.callTool> => {\n // call the tool\n const res = await _callTool(params, resultSchema, options);\n console.log(\"res\", res);\n\n // If it errored and returned accepts, we need to confirm payment\n const maybeX402Error = res._meta?.[\"x402/error\"] as\n | { accepts: PaymentRequirements[] }\n | undefined;\n\n if (\n res.isError &&\n maybeX402Error &&\n maybeX402Error.accepts &&\n Array.isArray(maybeX402Error.accepts) &&\n maybeX402Error.accepts.length > 0\n ) {\n const accepts = maybeX402Error.accepts;\n const confirmationCallback =\n x402ConfirmationCallback ?? x402Config.confirmationCallback;\n\n // Use the x402 confirmation callback if provided\n if (confirmationCallback && !(await confirmationCallback(accepts))) {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"User declined payment\" }]\n };\n }\n\n // Pick the first exact-scheme requirement that matches our network\n // (we're only setting one on the McpAgent side for now)\n const req =\n accepts.find((a) => a?.scheme === \"exact\" && a?.network === network) ??\n accepts[0];\n\n if (!req || req.scheme !== \"exact\") return res;\n\n const maxAmountRequired = BigInt(req.maxAmountRequired);\n if (maxAmountRequired > maxPaymentValue) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Payment exceeds client cap: ${maxAmountRequired} > ${maxPaymentValue}`\n }\n ]\n };\n }\n\n // Use x402/client to get the X-PAYMENT token\n const token = await createPaymentHeader(\n wallet as Wallet,\n version ?? 1,\n req\n );\n\n // Call the tool with the payment token\n return _callTool(\n {\n ...params,\n _meta: {\n ...params._meta,\n \"x402/payment\": token\n }\n },\n resultSchema,\n options\n );\n }\n\n return res;\n };\n\n const _client = client as X402AugmentedClient & T;\n _client.listTools = listTools;\n Object.defineProperty(_client, \"callTool\", {\n value: callToolWithPayment,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n return _client;\n}\n"],"mappings":"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"}
@@ -58,4 +58,4 @@ type MCPObservabilityEvent =
58
58
  | BaseEvent<"mcp:client:discover", {}>;
59
59
  //#endregion
60
60
  export { BaseEvent as n, MCPObservabilityEvent as t };
61
- //# sourceMappingURL=mcp-AK39tq6H.d.ts.map
61
+ //# sourceMappingURL=mcp-BwPscEiF.d.ts.map
@@ -1,2 +1,2 @@
1
- import { n as ObservabilityEvent, r as genericObservability, t as Observability } from "../index-B7Ny-XfU.js";
1
+ import { n as ObservabilityEvent, r as genericObservability, t as Observability } from "../index-N6791tVt.js";
2
2
  export { Observability, ObservabilityEvent, genericObservability };
@@ -1,7 +1,7 @@
1
- import "../client-CEO0P7vN.js";
2
- import "../internal_context-oN047Id3.js";
3
- import "../client-0lfEZpSQ.js";
4
- import "../do-oauth-client-provider-BfPFgQU0.js";
5
- import { p as genericObservability } from "../src-C_iKczoR.js";
1
+ import "../email-XHsSYsTO.js";
2
+ import "../internal_context-D9eKFth1.js";
3
+ import "../client-6CeOh-EV.js";
4
+ import "../do-oauth-client-provider-DDg8QrEA.js";
5
+ import { d as genericObservability } from "../src-BFP4sOQ4.js";
6
6
 
7
7
  export { genericObservability };
package/dist/react.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { Method, RPCMethod } from "./serializable.js";
2
2
  import { StreamOptions } from "./client.js";
3
- import "./internal_context-neg89p5n.js";
4
- import "./client-Cxno-5sH.js";
3
+ import "./internal_context-CEu5ji80.js";
4
+ import "./email-8ljcpvwV.js";
5
+ import "./client-DGpERepg.js";
6
+ import "./workflow-types-Z_Oem1FJ.js";
5
7
  import { Agent, MCPServersState } from "./index.js";
6
8
  import { PartySocket } from "partysocket";
7
9
  import { usePartySocket } from "partysocket/react";
@@ -43,20 +45,58 @@ type UseAgentOptions<State = unknown> = Omit<
43
45
  Parameters<typeof usePartySocket>[0],
44
46
  "party" | "room" | "query"
45
47
  > & {
46
- /** Name of the agent to connect to */
47
- agent: string;
48
- /** Name of the specific Agent instance */
48
+ /** Name of the agent to connect to (ignored if basePath is set) */ agent: string; /** Name of the specific Agent instance (ignored if basePath is set) */
49
49
  name?: string;
50
- /** Query parameters - can be static object or async function */
51
- query?: QueryObject | (() => Promise<QueryObject>);
52
- /** Dependencies for async query caching */
53
- queryDeps?: unknown[];
54
- /** Cache TTL in milliseconds for auth tokens/time-sensitive data */
55
- cacheTtl?: number;
56
- /** Called when the Agent's state is updated */
57
- onStateUpdate?: (state: State, source: "server" | "client") => void;
58
- /** Called when MCP server state is updated */
50
+ /**
51
+ * Full URL path - bypasses agent/name URL construction.
52
+ * When set, the client connects to this path directly.
53
+ * Server must handle routing manually (e.g., with getAgentByName + fetch).
54
+ * @example
55
+ * // Client connects to /user, server routes based on session
56
+ * useAgent({ agent: "UserAgent", basePath: "user" })
57
+ */
58
+ basePath?: string; /** Query parameters - can be static object or async function */
59
+ query?:
60
+ | QueryObject
61
+ | (() => Promise<QueryObject>); /** Dependencies for async query caching */
62
+ queryDeps?: unknown[]; /** Cache TTL in milliseconds for auth tokens/time-sensitive data */
63
+ cacheTtl?: number; /** Called when the Agent's state is updated */
64
+ onStateUpdate?: (
65
+ state: State,
66
+ source: "server" | "client"
67
+ ) => void; /** Called when MCP server state is updated */
59
68
  onMcpUpdate?: (mcpServers: MCPServersState) => void;
69
+ /**
70
+ * Called when the server sends the agent's identity on connect.
71
+ * Useful when using basePath, as the actual instance name is determined server-side.
72
+ * @param name The actual agent instance name
73
+ * @param agent The agent class name (kebab-case)
74
+ */
75
+ onIdentity?: (name: string, agent: string) => void;
76
+ /**
77
+ * Called when identity changes on reconnect (different instance than before).
78
+ * If not provided and identity changes, a warning will be logged.
79
+ * @param oldName Previous instance name
80
+ * @param newName New instance name
81
+ * @param oldAgent Previous agent class name
82
+ * @param newAgent New agent class name
83
+ */
84
+ onIdentityChange?: (
85
+ oldName: string,
86
+ newName: string,
87
+ oldAgent: string,
88
+ newAgent: string
89
+ ) => void;
90
+ /**
91
+ * Additional path to append to the URL.
92
+ * Works with both standard routing and basePath.
93
+ * @example
94
+ * // With basePath: /user/settings
95
+ * { basePath: "user", path: "settings" }
96
+ * // Standard: /agents/my-agent/room/settings
97
+ * { agent: "MyAgent", name: "room", path: "settings" }
98
+ */
99
+ path?: string;
60
100
  };
61
101
  type AllOptional<T> = T extends [infer A, ...infer R]
62
102
  ? undefined extends A
@@ -80,24 +120,24 @@ type RequiredAgentMethods<T> = Omit<
80
120
  AgentMethods<T>,
81
121
  keyof OptionalAgentMethods<T>
82
122
  >;
83
- type AgentPromiseReturnType<T, K$1 extends keyof AgentMethods<T>> =
84
- ReturnType<AgentMethods<T>[K$1]> extends Promise<any>
85
- ? ReturnType<AgentMethods<T>[K$1]>
86
- : Promise<ReturnType<AgentMethods<T>[K$1]>>;
123
+ type AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =
124
+ ReturnType<AgentMethods<T>[K]> extends Promise<any>
125
+ ? ReturnType<AgentMethods<T>[K]>
126
+ : Promise<ReturnType<AgentMethods<T>[K]>>;
87
127
  type OptionalArgsAgentMethodCall<AgentT> = <
88
- K$1 extends keyof OptionalAgentMethods<AgentT>
128
+ K extends keyof OptionalAgentMethods<AgentT>
89
129
  >(
90
- method: K$1,
91
- args?: Parameters<OptionalAgentMethods<AgentT>[K$1]>,
130
+ method: K,
131
+ args?: Parameters<OptionalAgentMethods<AgentT>[K]>,
92
132
  streamOptions?: StreamOptions
93
- ) => AgentPromiseReturnType<AgentT, K$1>;
133
+ ) => AgentPromiseReturnType<AgentT, K>;
94
134
  type RequiredArgsAgentMethodCall<AgentT> = <
95
- K$1 extends keyof RequiredAgentMethods<AgentT>
135
+ K extends keyof RequiredAgentMethods<AgentT>
96
136
  >(
97
- method: K$1,
98
- args: Parameters<RequiredAgentMethods<AgentT>[K$1]>,
137
+ method: K,
138
+ args: Parameters<RequiredAgentMethods<AgentT>[K]>,
99
139
  streamOptions?: StreamOptions
100
- ) => AgentPromiseReturnType<AgentT, K$1>;
140
+ ) => AgentPromiseReturnType<AgentT, K>;
101
141
  type AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &
102
142
  RequiredArgsAgentMethodCall<AgentT>;
103
143
  type UntypedAgentMethodCall = <T = unknown>(
@@ -119,6 +159,8 @@ declare function useAgent<State = unknown>(
119
159
  ): PartySocket & {
120
160
  agent: string;
121
161
  name: string;
162
+ identified: boolean;
163
+ ready: Promise<void>;
122
164
  setState: (state: State) => void;
123
165
  call: UntypedAgentMethodCall;
124
166
  stub: UntypedAgentStub;
@@ -133,6 +175,8 @@ declare function useAgent<
133
175
  ): PartySocket & {
134
176
  agent: string;
135
177
  name: string;
178
+ identified: boolean;
179
+ ready: Promise<void>;
136
180
  setState: (state: State) => void;
137
181
  call: AgentMethodCall<AgentT>;
138
182
  stub: AgentStub<AgentT>;
package/dist/react.js CHANGED
@@ -1,19 +1,9 @@
1
- import { t as MessageType } from "./types-4b5tlB0u.js";
1
+ import { t as MessageType } from "./types-BITaDFf-.js";
2
+ import { t as camelCaseToKebabCase } from "./utils-B49TmLCI.js";
2
3
  import { usePartySocket } from "partysocket/react";
3
4
  import { use, useCallback, useEffect, useMemo, useRef, useState } from "react";
4
5
 
5
6
  //#region src/react.tsx
6
- /**
7
- * Convert a camelCase string to a kebab-case string
8
- * @param str The string to convert
9
- * @returns The kebab-case string
10
- */
11
- function camelCaseToKebabCase(str) {
12
- if (str === str.toUpperCase() && str !== str.toLowerCase()) return str.toLowerCase().replace(/_/g, "-");
13
- let kebabified = str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
14
- kebabified = kebabified.startsWith("-") ? kebabified.slice(1) : kebabified;
15
- return kebabified.replace(/_/g, "-").replace(/-$/, "");
16
- }
17
7
  const queryCache = /* @__PURE__ */ new Map();
18
8
  function createCacheKey(agentNamespace, name, deps) {
19
9
  return JSON.stringify([
@@ -113,12 +103,40 @@ function useAgent(options) {
113
103
  resolvedQuery = queryResult;
114
104
  }
115
105
  } else resolvedQuery = query;
106
+ const [identity, setIdentity] = useState({
107
+ name: options.name || "default",
108
+ agent: agentNamespace,
109
+ identified: false
110
+ });
111
+ const previousIdentityRef = useRef({
112
+ name: null,
113
+ agent: null
114
+ });
115
+ const readyRef = useRef(void 0);
116
+ const resetReady = () => {
117
+ let resolve;
118
+ readyRef.current = {
119
+ promise: new Promise((r) => {
120
+ resolve = r;
121
+ }),
122
+ resolve
123
+ };
124
+ };
125
+ if (!readyRef.current) resetReady();
116
126
  const agent = usePartySocket({
117
- party: agentNamespace,
118
- prefix: "agents",
119
- room: options.name || "default",
120
- query: resolvedQuery,
121
- ...restOptions,
127
+ ...options.basePath ? {
128
+ basePath: options.basePath,
129
+ path: options.path,
130
+ query: resolvedQuery,
131
+ ...restOptions
132
+ } : {
133
+ party: agentNamespace,
134
+ prefix: "agents",
135
+ room: options.name || "default",
136
+ path: options.path,
137
+ query: resolvedQuery,
138
+ ...restOptions
139
+ },
122
140
  onMessage: (message) => {
123
141
  if (typeof message.data === "string") {
124
142
  let parsedMessage;
@@ -127,6 +145,34 @@ function useAgent(options) {
127
145
  } catch (_error) {
128
146
  return options.onMessage?.(message);
129
147
  }
148
+ if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {
149
+ const oldName = previousIdentityRef.current.name;
150
+ const oldAgent = previousIdentityRef.current.agent;
151
+ const newName = parsedMessage.name;
152
+ const newAgent = parsedMessage.agent;
153
+ setIdentity({
154
+ name: newName,
155
+ agent: newAgent,
156
+ identified: true
157
+ });
158
+ readyRef.current?.resolve();
159
+ if (oldName !== null && oldAgent !== null && (oldName !== newName || oldAgent !== newAgent)) if (options.onIdentityChange) options.onIdentityChange(oldName, newName, oldAgent, newAgent);
160
+ else {
161
+ const agentChanged = oldAgent !== newAgent;
162
+ const nameChanged = oldName !== newName;
163
+ let changeDescription = "";
164
+ if (agentChanged && nameChanged) changeDescription = `agent "${oldAgent}" → "${newAgent}", instance "${oldName}" → "${newName}"`;
165
+ else if (agentChanged) changeDescription = `agent "${oldAgent}" → "${newAgent}"`;
166
+ else changeDescription = `instance "${oldName}" → "${newName}"`;
167
+ console.warn(`[agents] Identity changed on reconnect: ${changeDescription}. This can happen with server-side routing (e.g., basePath with getAgentByName) where the instance is determined by auth/session. Provide onIdentityChange callback to handle this explicitly, or ignore if this is expected for your routing pattern.`);
168
+ }
169
+ previousIdentityRef.current = {
170
+ name: newName,
171
+ agent: newAgent
172
+ };
173
+ options.onIdentity?.(newName, newAgent);
174
+ return;
175
+ }
130
176
  if (parsedMessage.type === MessageType.CF_AGENT_STATE) {
131
177
  options.onStateUpdate?.(parsedMessage.state, "server");
132
178
  return;
@@ -158,11 +204,25 @@ function useAgent(options) {
158
204
  }
159
205
  }
160
206
  options.onMessage?.(message);
207
+ },
208
+ onClose: (event) => {
209
+ resetReady();
210
+ setIdentity((prev) => ({
211
+ ...prev,
212
+ identified: false
213
+ }));
214
+ const error = /* @__PURE__ */ new Error("Connection closed");
215
+ for (const pending of pendingCallsRef.current.values()) {
216
+ pending.reject(error);
217
+ pending.stream?.onError?.("Connection closed");
218
+ }
219
+ pendingCallsRef.current.clear();
220
+ options.onClose?.(event);
161
221
  }
162
222
  });
163
223
  const call = useCallback((method, args = [], streamOptions) => {
164
224
  return new Promise((resolve, reject) => {
165
- const id = Math.random().toString(36).slice(2);
225
+ const id = crypto.randomUUID();
166
226
  pendingCallsRef.current.set(id, {
167
227
  reject,
168
228
  resolve,
@@ -185,10 +245,12 @@ function useAgent(options) {
185
245
  options.onStateUpdate?.(state, "client");
186
246
  };
187
247
  agent.call = call;
188
- agent.agent = agentNamespace;
189
- agent.name = options.name || "default";
248
+ agent.agent = identity.agent;
249
+ agent.name = identity.name;
250
+ agent.identified = identity.identified;
251
+ agent.ready = readyRef.current.promise;
190
252
  agent.stub = createStubProxy(call);
191
- if (agent.agent !== agent.agent.toLowerCase()) console.warn(`Agent name: ${agent.agent} should probably be in lowercase. Received: ${agent.agent}`);
253
+ if (identity.agent !== identity.agent.toLowerCase()) console.warn("Agent name: " + identity.agent + " should probably be in lowercase. Received: " + identity.agent);
192
254
  return agent;
193
255
  }
194
256
 
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":["entry: CacheEntry","resolvedQuery: QueryObject | undefined","parsedMessage: Record<string, unknown>","request: RPCRequest"],"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef, use, useMemo, useState, useEffect } from \"react\";\nimport type { Agent, MCPServersState, RPCRequest, RPCResponse } from \"./\";\nimport type { StreamOptions } from \"./client\";\nimport type { Method, RPCMethod } from \"./serializable\";\nimport { MessageType } from \"./types\";\n\n/**\n * Convert a camelCase string to a kebab-case string\n * @param str The string to convert\n * @returns The kebab-case string\n */\nfunction camelCaseToKebabCase(str: string): string {\n // If string is all uppercase, convert to lowercase\n if (str === str.toUpperCase() && str !== str.toLowerCase()) {\n return str.toLowerCase().replace(/_/g, \"-\");\n }\n\n // Otherwise handle camelCase to kebab-case\n let kebabified = str.replace(\n /[A-Z]/g,\n (letter) => `-${letter.toLowerCase()}`\n );\n kebabified = kebabified.startsWith(\"-\") ? kebabified.slice(1) : kebabified;\n // Convert any remaining underscores to hyphens and remove trailing -'s\n return kebabified.replace(/_/g, \"-\").replace(/-$/, \"\");\n}\n\ntype QueryObject = Record<string, string | null>;\n\ninterface CacheEntry {\n promise: Promise<QueryObject>;\n expiresAt: number;\n}\n\nconst queryCache = new Map<string, CacheEntry>();\n\nfunction createCacheKey(\n agentNamespace: string,\n name: string | undefined,\n deps: unknown[]\n): string {\n return JSON.stringify([agentNamespace, name || \"default\", ...deps]);\n}\n\nfunction getCacheEntry(key: string): CacheEntry | undefined {\n const entry = queryCache.get(key);\n if (!entry) return undefined;\n\n if (Date.now() >= entry.expiresAt) {\n queryCache.delete(key);\n return undefined;\n }\n\n return entry;\n}\n\nfunction setCacheEntry(\n key: string,\n promise: Promise<QueryObject>,\n cacheTtl: number\n): CacheEntry {\n const entry: CacheEntry = {\n promise,\n expiresAt: Date.now() + cacheTtl\n };\n queryCache.set(key, entry);\n return entry;\n}\n\nfunction deleteCacheEntry(key: string): void {\n queryCache.delete(key);\n}\n\n/**\n * Creates a proxy that wraps RPC method calls.\n * Internal JS methods (toJSON, then, etc.) return undefined to avoid\n * triggering RPC calls during serialization (e.g., console.log)\n */\nfunction createStubProxy<T = Record<string, Method>>(\n call: (method: string, args: unknown[]) => unknown\n): T {\n // biome-ignore lint/suspicious/noExplicitAny: proxy needs any for dynamic method access\n return new Proxy<any>(\n {},\n {\n get: (_target, method) => {\n // Skip internal JavaScript methods that shouldn't trigger RPC calls.\n // These are commonly accessed by console.log, JSON.stringify, and other\n // serialization utilities.\n if (\n typeof method === \"symbol\" ||\n method === \"toJSON\" ||\n method === \"then\" ||\n method === \"catch\" ||\n method === \"finally\" ||\n method === \"valueOf\" ||\n method === \"toString\" ||\n method === \"constructor\" ||\n method === \"prototype\" ||\n method === \"$$typeof\" ||\n method === \"@@toStringTag\" ||\n method === \"asymmetricMatch\" ||\n method === \"nodeType\"\n ) {\n return undefined;\n }\n return (...args: unknown[]) => call(method as string, args);\n }\n }\n );\n}\n\n// Export for testing purposes\nexport const _testUtils = {\n queryCache,\n setCacheEntry,\n getCacheEntry,\n deleteCacheEntry,\n clearCache: () => queryCache.clear(),\n createStubProxy\n};\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\" | \"query\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n /** Query parameters - can be static object or async function */\n query?: QueryObject | (() => Promise<QueryObject>);\n /** Dependencies for async query caching */\n queryDeps?: unknown[];\n /** Cache TTL in milliseconds for auth tokens/time-sensitive data */\n cacheTtl?: number;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n /** Called when MCP server state is updated */\n onMcpUpdate?: (mcpServers: MCPServersState) => void;\n};\n\ntype AllOptional<T> = T extends [infer A, ...infer R]\n ? undefined extends A\n ? AllOptional<R>\n : false\n : true; // no params means optional by default\n\ntype RPCMethods<T> = {\n [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;\n};\n\ntype OptionalParametersMethod<T extends RPCMethod> =\n AllOptional<Parameters<T>> extends true ? T : never;\n\n// all methods of the Agent, excluding the ones that are declared in the base Agent class\n// biome-ignore lint: suppressions/parse\ntype AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;\n\ntype OptionalAgentMethods<T> = {\n [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<\n AgentMethods<T>[K]\n >\n ? K\n : never]: OptionalParametersMethod<AgentMethods<T>[K]>;\n};\n\ntype RequiredAgentMethods<T> = Omit<\n AgentMethods<T>,\n keyof OptionalAgentMethods<T>\n>;\n\ntype AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =\n // biome-ignore lint: suppressions/parse\n ReturnType<AgentMethods<T>[K]> extends Promise<any>\n ? ReturnType<AgentMethods<T>[K]>\n : Promise<ReturnType<AgentMethods<T>[K]>>;\n\ntype OptionalArgsAgentMethodCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: Parameters<OptionalAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentMethodCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: Parameters<RequiredAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &\n RequiredArgsAgentMethodCall<AgentT>;\n\ntype UntypedAgentMethodCall = <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n) => Promise<T>;\n\ntype AgentStub<T> = {\n [K in keyof AgentMethods<T>]: (\n ...args: Parameters<AgentMethods<T>[K]>\n ) => AgentPromiseReturnType<AgentMethods<T>, K>;\n};\n\n// we neet to use Method instead of RPCMethod here for retro-compatibility\ntype UntypedAgentStub = Record<string, Method>;\n\n/**\n * React hook for connecting to an Agent\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n};\nexport function useAgent<\n AgentT extends {\n get state(): State;\n },\n State\n>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: AgentMethodCall<AgentT>;\n stub: AgentStub<AgentT>;\n};\nexport function useAgent<State>(\n options: UseAgentOptions<unknown>\n): PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall | AgentMethodCall<unknown>;\n stub: UntypedAgentStub;\n} {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n const { query, queryDeps, cacheTtl, ...restOptions } = options;\n\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >()\n );\n\n const cacheKey = useMemo(\n () => createCacheKey(agentNamespace, options.name, queryDeps || []),\n [agentNamespace, options.name, queryDeps]\n );\n\n const ttl = cacheTtl ?? 5 * 60 * 1000;\n\n // Track cache invalidation to force re-render when TTL expires\n const [cacheInvalidatedAt, setCacheInvalidatedAt] = useState<number>(0);\n\n // Get or create the query promise\n // biome-ignore lint/correctness/useExhaustiveDependencies: cacheInvalidatedAt intentionally forces re-evaluation when TTL expires\n const queryPromise = useMemo(() => {\n if (!query || typeof query !== \"function\") {\n return null;\n }\n\n // Always check cache first to deduplicate concurrent requests\n const cached = getCacheEntry(cacheKey);\n if (cached) {\n return cached.promise;\n }\n\n // Create new promise\n const promise = query().catch((error) => {\n console.error(\n `[useAgent] Query failed for agent \"${options.agent}\":`,\n error\n );\n deleteCacheEntry(cacheKey);\n throw error;\n });\n\n // Always cache to deduplicate concurrent requests\n setCacheEntry(cacheKey, promise, ttl);\n\n return promise;\n }, [cacheKey, query, options.agent, ttl, cacheInvalidatedAt]);\n\n // Schedule cache invalidation when TTL expires\n useEffect(() => {\n if (!queryPromise || ttl <= 0) return;\n\n const entry = getCacheEntry(cacheKey);\n if (!entry) return;\n\n const timeUntilExpiry = entry.expiresAt - Date.now();\n\n // Always set a timer (with min 0ms) to ensure cleanup function is returned\n const timer = setTimeout(\n () => {\n deleteCacheEntry(cacheKey);\n setCacheInvalidatedAt(Date.now());\n },\n Math.max(0, timeUntilExpiry)\n );\n\n return () => clearTimeout(timer);\n }, [cacheKey, queryPromise, ttl]);\n\n let resolvedQuery: QueryObject | undefined;\n\n if (query) {\n if (typeof query === \"function\") {\n // Use React's use() to resolve the promise\n const queryResult = use(queryPromise!);\n\n // Check for non-primitive values and warn\n if (queryResult) {\n for (const [key, value] of Object.entries(queryResult)) {\n if (\n value !== null &&\n value !== undefined &&\n typeof value !== \"string\" &&\n typeof value !== \"number\" &&\n typeof value !== \"boolean\"\n ) {\n console.warn(\n `[useAgent] Query parameter \"${key}\" is an object and will be converted to \"[object Object]\". ` +\n \"Query parameters should be string, number, boolean, or null.\"\n );\n }\n }\n resolvedQuery = queryResult;\n }\n } else {\n // Sync query - use directly\n resolvedQuery = query;\n }\n }\n\n const agent = usePartySocket({\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n query: resolvedQuery,\n ...restOptions,\n onMessage: (message) => {\n if (typeof message.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(message.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return options.onMessage?.(message);\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_MCP_SERVERS) {\n options.onMcpUpdate?.(parsedMessage.mcp as MCPServersState);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = pendingCallsRef.current.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n }\n return;\n }\n }\n options.onMessage?.(message);\n }\n }) as PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n };\n // Create the call method\n const call = useCallback(\n <T = unknown,>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> => {\n return new Promise((resolve, reject) => {\n const id = Math.random().toString(36).slice(2);\n pendingCallsRef.current.set(id, {\n reject,\n resolve: resolve as (value: unknown) => void,\n stream: streamOptions\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n agent.send(JSON.stringify(request));\n });\n },\n [agent]\n );\n\n agent.setState = (state: State) => {\n agent.send(JSON.stringify({ state, type: MessageType.CF_AGENT_STATE }));\n options.onStateUpdate?.(state, \"client\");\n };\n\n agent.call = call;\n agent.agent = agentNamespace;\n agent.name = options.name || \"default\";\n agent.stub = createStubProxy(call);\n\n // warn if agent isn't in lowercase\n if (agent.agent !== agent.agent.toLowerCase()) {\n console.warn(\n `Agent name: ${agent.agent} should probably be in lowercase. Received: ${agent.agent}`\n );\n }\n\n return agent;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef, use, useMemo, useState, useEffect } from \"react\";\nimport type { Agent, MCPServersState, RPCRequest, RPCResponse } from \"./\";\nimport type { StreamOptions } from \"./client\";\nimport { camelCaseToKebabCase } from \"./utils\";\nimport type { Method, RPCMethod } from \"./serializable\";\nimport { MessageType } from \"./types\";\n\ntype QueryObject = Record<string, string | null>;\n\ninterface CacheEntry {\n promise: Promise<QueryObject>;\n expiresAt: number;\n}\n\nconst queryCache = new Map<string, CacheEntry>();\n\nfunction createCacheKey(\n agentNamespace: string,\n name: string | undefined,\n deps: unknown[]\n): string {\n return JSON.stringify([agentNamespace, name || \"default\", ...deps]);\n}\n\nfunction getCacheEntry(key: string): CacheEntry | undefined {\n const entry = queryCache.get(key);\n if (!entry) return undefined;\n\n if (Date.now() >= entry.expiresAt) {\n queryCache.delete(key);\n return undefined;\n }\n\n return entry;\n}\n\nfunction setCacheEntry(\n key: string,\n promise: Promise<QueryObject>,\n cacheTtl: number\n): CacheEntry {\n const entry: CacheEntry = {\n promise,\n expiresAt: Date.now() + cacheTtl\n };\n queryCache.set(key, entry);\n return entry;\n}\n\nfunction deleteCacheEntry(key: string): void {\n queryCache.delete(key);\n}\n\n/**\n * Creates a proxy that wraps RPC method calls.\n * Internal JS methods (toJSON, then, etc.) return undefined to avoid\n * triggering RPC calls during serialization (e.g., console.log)\n */\nfunction createStubProxy<T = Record<string, Method>>(\n call: (method: string, args: unknown[]) => unknown\n): T {\n // biome-ignore lint/suspicious/noExplicitAny: proxy needs any for dynamic method access\n return new Proxy<any>(\n {},\n {\n get: (_target, method) => {\n // Skip internal JavaScript methods that shouldn't trigger RPC calls.\n // These are commonly accessed by console.log, JSON.stringify, and other\n // serialization utilities.\n if (\n typeof method === \"symbol\" ||\n method === \"toJSON\" ||\n method === \"then\" ||\n method === \"catch\" ||\n method === \"finally\" ||\n method === \"valueOf\" ||\n method === \"toString\" ||\n method === \"constructor\" ||\n method === \"prototype\" ||\n method === \"$$typeof\" ||\n method === \"@@toStringTag\" ||\n method === \"asymmetricMatch\" ||\n method === \"nodeType\"\n ) {\n return undefined;\n }\n return (...args: unknown[]) => call(method as string, args);\n }\n }\n );\n}\n\n// Export for testing purposes\nexport const _testUtils = {\n queryCache,\n setCacheEntry,\n getCacheEntry,\n deleteCacheEntry,\n clearCache: () => queryCache.clear(),\n createStubProxy\n};\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\" | \"query\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the client connects to this path directly.\n * Server must handle routing manually (e.g., with getAgentByName + fetch).\n * @example\n * // Client connects to /user, server routes based on session\n * useAgent({ agent: \"UserAgent\", basePath: \"user\" })\n */\n basePath?: string;\n /** Query parameters - can be static object or async function */\n query?: QueryObject | (() => Promise<QueryObject>);\n /** Dependencies for async query caching */\n queryDeps?: unknown[];\n /** Cache TTL in milliseconds for auth tokens/time-sensitive data */\n cacheTtl?: number;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n /** Called when MCP server state is updated */\n onMcpUpdate?: (mcpServers: MCPServersState) => void;\n /**\n * Called when the server sends the agent's identity on connect.\n * Useful when using basePath, as the actual instance name is determined server-side.\n * @param name The actual agent instance name\n * @param agent The agent class name (kebab-case)\n */\n onIdentity?: (name: string, agent: string) => void;\n /**\n * Called when identity changes on reconnect (different instance than before).\n * If not provided and identity changes, a warning will be logged.\n * @param oldName Previous instance name\n * @param newName New instance name\n * @param oldAgent Previous agent class name\n * @param newAgent New agent class name\n */\n onIdentityChange?: (\n oldName: string,\n newName: string,\n oldAgent: string,\n newAgent: string\n ) => void;\n /**\n * Additional path to append to the URL.\n * Works with both standard routing and basePath.\n * @example\n * // With basePath: /user/settings\n * { basePath: \"user\", path: \"settings\" }\n * // Standard: /agents/my-agent/room/settings\n * { agent: \"MyAgent\", name: \"room\", path: \"settings\" }\n */\n path?: string;\n};\n\ntype AllOptional<T> = T extends [infer A, ...infer R]\n ? undefined extends A\n ? AllOptional<R>\n : false\n : true; // no params means optional by default\n\ntype RPCMethods<T> = {\n [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;\n};\n\ntype OptionalParametersMethod<T extends RPCMethod> =\n AllOptional<Parameters<T>> extends true ? T : never;\n\n// all methods of the Agent, excluding the ones that are declared in the base Agent class\n// biome-ignore lint: suppressions/parse\ntype AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;\n\ntype OptionalAgentMethods<T> = {\n [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<\n AgentMethods<T>[K]\n >\n ? K\n : never]: OptionalParametersMethod<AgentMethods<T>[K]>;\n};\n\ntype RequiredAgentMethods<T> = Omit<\n AgentMethods<T>,\n keyof OptionalAgentMethods<T>\n>;\n\ntype AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =\n // biome-ignore lint: suppressions/parse\n ReturnType<AgentMethods<T>[K]> extends Promise<any>\n ? ReturnType<AgentMethods<T>[K]>\n : Promise<ReturnType<AgentMethods<T>[K]>>;\n\ntype OptionalArgsAgentMethodCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: Parameters<OptionalAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentMethodCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: Parameters<RequiredAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &\n RequiredArgsAgentMethodCall<AgentT>;\n\ntype UntypedAgentMethodCall = <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n) => Promise<T>;\n\ntype AgentStub<T> = {\n [K in keyof AgentMethods<T>]: (\n ...args: Parameters<AgentMethods<T>[K]>\n ) => AgentPromiseReturnType<AgentMethods<T>, K>;\n};\n\n// we neet to use Method instead of RPCMethod here for retro-compatibility\ntype UntypedAgentStub = Record<string, Method>;\n\n/**\n * React hook for connecting to an Agent\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n};\nexport function useAgent<\n AgentT extends {\n get state(): State;\n },\n State\n>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n setState: (state: State) => void;\n call: AgentMethodCall<AgentT>;\n stub: AgentStub<AgentT>;\n};\nexport function useAgent<State>(\n options: UseAgentOptions<unknown>\n): PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall | AgentMethodCall<unknown>;\n stub: UntypedAgentStub;\n} {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n const { query, queryDeps, cacheTtl, ...restOptions } = options;\n\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >()\n );\n\n const cacheKey = useMemo(\n () => createCacheKey(agentNamespace, options.name, queryDeps || []),\n [agentNamespace, options.name, queryDeps]\n );\n\n const ttl = cacheTtl ?? 5 * 60 * 1000;\n\n // Track cache invalidation to force re-render when TTL expires\n const [cacheInvalidatedAt, setCacheInvalidatedAt] = useState<number>(0);\n\n // Get or create the query promise\n // biome-ignore lint/correctness/useExhaustiveDependencies: cacheInvalidatedAt intentionally forces re-evaluation when TTL expires\n const queryPromise = useMemo(() => {\n if (!query || typeof query !== \"function\") {\n return null;\n }\n\n // Always check cache first to deduplicate concurrent requests\n const cached = getCacheEntry(cacheKey);\n if (cached) {\n return cached.promise;\n }\n\n // Create new promise\n const promise = query().catch((error) => {\n console.error(\n `[useAgent] Query failed for agent \"${options.agent}\":`,\n error\n );\n deleteCacheEntry(cacheKey);\n throw error;\n });\n\n // Always cache to deduplicate concurrent requests\n setCacheEntry(cacheKey, promise, ttl);\n\n return promise;\n }, [cacheKey, query, options.agent, ttl, cacheInvalidatedAt]);\n\n // Schedule cache invalidation when TTL expires\n useEffect(() => {\n if (!queryPromise || ttl <= 0) return;\n\n const entry = getCacheEntry(cacheKey);\n if (!entry) return;\n\n const timeUntilExpiry = entry.expiresAt - Date.now();\n\n // Always set a timer (with min 0ms) to ensure cleanup function is returned\n const timer = setTimeout(\n () => {\n deleteCacheEntry(cacheKey);\n setCacheInvalidatedAt(Date.now());\n },\n Math.max(0, timeUntilExpiry)\n );\n\n return () => clearTimeout(timer);\n }, [cacheKey, queryPromise, ttl]);\n\n let resolvedQuery: QueryObject | undefined;\n\n if (query) {\n if (typeof query === \"function\") {\n // Use React's use() to resolve the promise\n const queryResult = use(queryPromise!);\n\n // Check for non-primitive values and warn\n if (queryResult) {\n for (const [key, value] of Object.entries(queryResult)) {\n if (\n value !== null &&\n value !== undefined &&\n typeof value !== \"string\" &&\n typeof value !== \"number\" &&\n typeof value !== \"boolean\"\n ) {\n console.warn(\n `[useAgent] Query parameter \"${key}\" is an object and will be converted to \"[object Object]\". ` +\n \"Query parameters should be string, number, boolean, or null.\"\n );\n }\n }\n resolvedQuery = queryResult;\n }\n } else {\n // Sync query - use directly\n resolvedQuery = query;\n }\n }\n\n // Store identity in React state for reactivity\n const [identity, setIdentity] = useState({\n name: options.name || \"default\",\n agent: agentNamespace,\n identified: false\n });\n\n // Track previous identity for change detection\n const previousIdentityRef = useRef<{\n name: string | null;\n agent: string | null;\n }>({ name: null, agent: null });\n\n // Ready promise - resolves when identity is received, resets on close\n const readyRef = useRef<\n { promise: Promise<void>; resolve: () => void } | undefined\n >(undefined);\n\n const resetReady = () => {\n let resolve: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n readyRef.current = { promise, resolve: resolve! };\n };\n\n if (!readyRef.current) {\n resetReady();\n }\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? {\n basePath: options.basePath,\n path: options.path,\n query: resolvedQuery,\n ...restOptions\n }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: options.path,\n query: resolvedQuery,\n ...restOptions\n };\n\n const agent = usePartySocket({\n ...socketOptions,\n onMessage: (message) => {\n if (typeof message.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(message.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return options.onMessage?.(message);\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = previousIdentityRef.current.name;\n const oldAgent = previousIdentityRef.current.agent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n // Update reactive state (triggers re-render)\n setIdentity({ name: newName, agent: newAgent, identified: true });\n\n // Resolve ready promise\n readyRef.current?.resolve();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (options.onIdentityChange) {\n options.onIdentityChange(oldName, newName, oldAgent, newAgent);\n } else {\n const agentChanged = oldAgent !== newAgent;\n const nameChanged = oldName !== newName;\n let changeDescription = \"\";\n if (agentChanged && nameChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\", instance \"${oldName}\" → \"${newName}\"`;\n } else if (agentChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\"`;\n } else {\n changeDescription = `instance \"${oldName}\" → \"${newName}\"`;\n }\n console.warn(\n `[agents] Identity changed on reconnect: ${changeDescription}. ` +\n \"This can happen with server-side routing (e.g., basePath with getAgentByName) \" +\n \"where the instance is determined by auth/session. \" +\n \"Provide onIdentityChange callback to handle this explicitly, \" +\n \"or ignore if this is expected for your routing pattern.\"\n );\n }\n }\n\n // Track for next change detection\n previousIdentityRef.current = { name: newName, agent: newAgent };\n\n // Call onIdentity callback\n options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_MCP_SERVERS) {\n options.onMcpUpdate?.(parsedMessage.mcp as MCPServersState);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = pendingCallsRef.current.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n }\n return;\n }\n }\n options.onMessage?.(message);\n },\n onClose: (event: CloseEvent) => {\n // Reset ready state for next connection\n resetReady();\n setIdentity((prev) => ({ ...prev, identified: false }));\n\n // Reject all pending calls (consistent with AgentClient behavior)\n const error = new Error(\"Connection closed\");\n for (const pending of pendingCallsRef.current.values()) {\n pending.reject(error);\n pending.stream?.onError?.(\"Connection closed\");\n }\n pendingCallsRef.current.clear();\n\n // Call user's onClose if provided\n options.onClose?.(event);\n }\n }) as PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n };\n // Create the call method\n const call = useCallback(\n <T = unknown,>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> => {\n return new Promise((resolve, reject) => {\n const id = crypto.randomUUID();\n pendingCallsRef.current.set(id, {\n reject,\n resolve: resolve as (value: unknown) => void,\n stream: streamOptions\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n agent.send(JSON.stringify(request));\n });\n },\n [agent]\n );\n\n agent.setState = (state: State) => {\n agent.send(JSON.stringify({ state, type: MessageType.CF_AGENT_STATE }));\n options.onStateUpdate?.(state, \"client\");\n };\n\n agent.call = call;\n // Use reactive identity state (updates on identity message)\n agent.agent = identity.agent;\n agent.name = identity.name;\n agent.identified = identity.identified;\n agent.ready = readyRef.current!.promise;\n agent.stub = createStubProxy(call);\n\n // warn if agent isn't in lowercase\n if (identity.agent !== identity.agent.toLowerCase()) {\n console.warn(\n \"Agent name: \" +\n identity.agent +\n \" should probably be in lowercase. Received: \" +\n identity.agent\n );\n }\n\n return agent;\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { z } from "zod/v3";
2
2
 
3
3
  //#region src/schedule.d.ts
4
-
5
4
  /**
6
5
  * Get the schedule prompt for a given event
7
6
  * @param event - The event to get the schedule prompt for
@@ -15,7 +14,29 @@ declare function getSchedulePrompt(event: { date: Date }): string;
15
14
  */
16
15
  declare function unstable_getSchedulePrompt(event: { date: Date }): string;
17
16
  /**
18
- * The schema for the schedule prompt
17
+ * The schema for parsing natural language scheduling requests.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { generateObject } from "ai";
22
+ * import { scheduleSchema, getSchedulePrompt } from "agents/schedule";
23
+ *
24
+ * const result = await generateObject({
25
+ * model,
26
+ * prompt: `${getSchedulePrompt({ date: new Date() })} Input: "${userInput}"`,
27
+ * schema: scheduleSchema,
28
+ * // Required for OpenAI to avoid strict JSON schema validation errors
29
+ * providerOptions: {
30
+ * openai: { strictJsonSchema: false }
31
+ * }
32
+ * });
33
+ * ```
34
+ *
35
+ * @remarks
36
+ * When using this schema with OpenAI models via the AI SDK, you must pass
37
+ * `providerOptions: { openai: { strictJsonSchema: false } }` to `generateObject`.
38
+ * This is because the schema uses optional fields which are not compatible with
39
+ * OpenAI's strict structured outputs mode.
19
40
  */
20
41
  declare const scheduleSchema: z.ZodObject<
21
42
  {
package/dist/schedule.js CHANGED
@@ -69,7 +69,29 @@ function unstable_getSchedulePrompt(event) {
69
69
  return getSchedulePrompt(event);
70
70
  }
71
71
  /**
72
- * The schema for the schedule prompt
72
+ * The schema for parsing natural language scheduling requests.
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * import { generateObject } from "ai";
77
+ * import { scheduleSchema, getSchedulePrompt } from "agents/schedule";
78
+ *
79
+ * const result = await generateObject({
80
+ * model,
81
+ * prompt: `${getSchedulePrompt({ date: new Date() })} Input: "${userInput}"`,
82
+ * schema: scheduleSchema,
83
+ * // Required for OpenAI to avoid strict JSON schema validation errors
84
+ * providerOptions: {
85
+ * openai: { strictJsonSchema: false }
86
+ * }
87
+ * });
88
+ * ```
89
+ *
90
+ * @remarks
91
+ * When using this schema with OpenAI models via the AI SDK, you must pass
92
+ * `providerOptions: { openai: { strictJsonSchema: false } }` to `generateObject`.
93
+ * This is because the schema uses optional fields which are not compatible with
94
+ * OpenAI's strict structured outputs mode.
73
95
  */
74
96
  const scheduleSchema = z.object({
75
97
  description: z.string().describe("A description of the task"),
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.js","names":[],"sources":["../src/schedule.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\n/**\n * Get the schedule prompt for a given event\n * @param event - The event to get the schedule prompt for\n * @returns The schedule prompt\n */\nexport function getSchedulePrompt(event: { date: Date }) {\n return `\n[Schedule Parser Component]\n\nCurrent time: ${event.date.toUTCString()}\n\nThis component parses natural language scheduling requests into a structured format. It extracts:\n1. A clean task description (without timing information)\n2. Scheduling details in one of these formats:\n - scheduled: Specific date/time events\n - delayed: Relative time delays (in seconds)\n - cron: Recurring patterns\n - no-schedule: Tasks without timing\n\nRules:\n- Task descriptions should be clean and focused on the action\n- Use numbers (0-6) for days in cron patterns (0=Sunday)\n- For recurring tasks, use standard cron syntax\n- For relative times, convert to seconds\n- For specific dates, use the current time as reference\n\nExample outputs:\n{\n \"description\": \"meeting with team\",\n \"when\": {\n \"type\": \"scheduled\",\n \"date\": \"tomorrow at 14:00\"\n }\n}\n\n{\n \"description\": \"backup database\",\n \"when\": {\n \"type\": \"cron\",\n \"cron\": \"0 0 * * *\"\n }\n}\n\n{\n \"description\": \"send report\",\n \"when\": {\n \"type\": \"delayed\",\n \"delayInSeconds\": 1800\n }\n}\n\n[End Schedule Parser Component]\n`;\n}\n\nlet didWarnAboutUnstableGetSchedulePrompt = false;\n\n/**\n * @deprecated this has been renamed to getSchedulePrompt, and unstable_getSchedulePrompt will be removed in the next major version\n * @param event - The event to get the schedule prompt for\n * @returns The schedule prompt\n */\nexport function unstable_getSchedulePrompt(event: { date: Date }) {\n if (!didWarnAboutUnstableGetSchedulePrompt) {\n didWarnAboutUnstableGetSchedulePrompt = true;\n console.warn(\n \"unstable_getSchedulePrompt is deprecated, use getSchedulePrompt instead. unstable_getSchedulePrompt will be removed in the next major version.\"\n );\n }\n return getSchedulePrompt(event);\n}\n\n/**\n * The schema for the schedule prompt\n */\nexport const scheduleSchema = z.object({\n description: z.string().describe(\"A description of the task\"),\n when: z.object({\n cron: z\n .string()\n .optional()\n .describe(\n \"execute task on a recurring interval specified as cron syntax (only use if the type is cron)\"\n ),\n date: z.coerce\n .date()\n .optional()\n .describe(\n \"execute task at the specified date and time (only use if the type is scheduled)\"\n ),\n delayInSeconds: z\n .number()\n .optional()\n .describe(\n \"execute task after a delay in seconds (only use if the type is delayed)\"\n ),\n type: z\n .enum([\"scheduled\", \"delayed\", \"cron\", \"no-schedule\"])\n .describe(\"The type of scheduling details\")\n })\n});\n\n/**\n * The type for the schedule prompt\n */\nexport type Schedule = z.infer<typeof scheduleSchema>;\n\n/**\n * @deprecated this has been renamed to scheduleSchema, and unstable_scheduleSchema will be removed in the next major version\n * @returns The schedule schema\n */\nexport const unstable_scheduleSchema = scheduleSchema;\n"],"mappings":";;;;;;;;AAOA,SAAgB,kBAAkB,OAAuB;AACvD,QAAO;;;gBAGO,MAAM,KAAK,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CzC,IAAI,wCAAwC;;;;;;AAO5C,SAAgB,2BAA2B,OAAuB;AAChE,KAAI,CAAC,uCAAuC;AAC1C,0CAAwC;AACxC,UAAQ,KACN,iJACD;;AAEH,QAAO,kBAAkB,MAAM;;;;;AAMjC,MAAa,iBAAiB,EAAE,OAAO;CACrC,aAAa,EAAE,QAAQ,CAAC,SAAS,4BAA4B;CAC7D,MAAM,EAAE,OAAO;EACb,MAAM,EACH,QAAQ,CACR,UAAU,CACV,SACC,+FACD;EACH,MAAM,EAAE,OACL,MAAM,CACN,UAAU,CACV,SACC,kFACD;EACH,gBAAgB,EACb,QAAQ,CACR,UAAU,CACV,SACC,0EACD;EACH,MAAM,EACH,KAAK;GAAC;GAAa;GAAW;GAAQ;GAAc,CAAC,CACrD,SAAS,iCAAiC;EAC9C,CAAC;CACH,CAAC;;;;;AAWF,MAAa,0BAA0B"}
1
+ {"version":3,"file":"schedule.js","names":[],"sources":["../src/schedule.ts"],"sourcesContent":["import { z } from \"zod/v3\";\n\n/**\n * Get the schedule prompt for a given event\n * @param event - The event to get the schedule prompt for\n * @returns The schedule prompt\n */\nexport function getSchedulePrompt(event: { date: Date }) {\n return `\n[Schedule Parser Component]\n\nCurrent time: ${event.date.toUTCString()}\n\nThis component parses natural language scheduling requests into a structured format. It extracts:\n1. A clean task description (without timing information)\n2. Scheduling details in one of these formats:\n - scheduled: Specific date/time events\n - delayed: Relative time delays (in seconds)\n - cron: Recurring patterns\n - no-schedule: Tasks without timing\n\nRules:\n- Task descriptions should be clean and focused on the action\n- Use numbers (0-6) for days in cron patterns (0=Sunday)\n- For recurring tasks, use standard cron syntax\n- For relative times, convert to seconds\n- For specific dates, use the current time as reference\n\nExample outputs:\n{\n \"description\": \"meeting with team\",\n \"when\": {\n \"type\": \"scheduled\",\n \"date\": \"tomorrow at 14:00\"\n }\n}\n\n{\n \"description\": \"backup database\",\n \"when\": {\n \"type\": \"cron\",\n \"cron\": \"0 0 * * *\"\n }\n}\n\n{\n \"description\": \"send report\",\n \"when\": {\n \"type\": \"delayed\",\n \"delayInSeconds\": 1800\n }\n}\n\n[End Schedule Parser Component]\n`;\n}\n\nlet didWarnAboutUnstableGetSchedulePrompt = false;\n\n/**\n * @deprecated this has been renamed to getSchedulePrompt, and unstable_getSchedulePrompt will be removed in the next major version\n * @param event - The event to get the schedule prompt for\n * @returns The schedule prompt\n */\nexport function unstable_getSchedulePrompt(event: { date: Date }) {\n if (!didWarnAboutUnstableGetSchedulePrompt) {\n didWarnAboutUnstableGetSchedulePrompt = true;\n console.warn(\n \"unstable_getSchedulePrompt is deprecated, use getSchedulePrompt instead. unstable_getSchedulePrompt will be removed in the next major version.\"\n );\n }\n return getSchedulePrompt(event);\n}\n\n/**\n * The schema for parsing natural language scheduling requests.\n *\n * @example\n * ```typescript\n * import { generateObject } from \"ai\";\n * import { scheduleSchema, getSchedulePrompt } from \"agents/schedule\";\n *\n * const result = await generateObject({\n * model,\n * prompt: `${getSchedulePrompt({ date: new Date() })} Input: \"${userInput}\"`,\n * schema: scheduleSchema,\n * // Required for OpenAI to avoid strict JSON schema validation errors\n * providerOptions: {\n * openai: { strictJsonSchema: false }\n * }\n * });\n * ```\n *\n * @remarks\n * When using this schema with OpenAI models via the AI SDK, you must pass\n * `providerOptions: { openai: { strictJsonSchema: false } }` to `generateObject`.\n * This is because the schema uses optional fields which are not compatible with\n * OpenAI's strict structured outputs mode.\n */\nexport const scheduleSchema = z.object({\n description: z.string().describe(\"A description of the task\"),\n when: z.object({\n cron: z\n .string()\n .optional()\n .describe(\n \"execute task on a recurring interval specified as cron syntax (only use if the type is cron)\"\n ),\n date: z.coerce\n .date()\n .optional()\n .describe(\n \"execute task at the specified date and time (only use if the type is scheduled)\"\n ),\n delayInSeconds: z\n .number()\n .optional()\n .describe(\n \"execute task after a delay in seconds (only use if the type is delayed)\"\n ),\n type: z\n .enum([\"scheduled\", \"delayed\", \"cron\", \"no-schedule\"])\n .describe(\"The type of scheduling details\")\n })\n});\n\n/**\n * The type for the schedule prompt\n */\nexport type Schedule = z.infer<typeof scheduleSchema>;\n\n/**\n * @deprecated this has been renamed to scheduleSchema, and unstable_scheduleSchema will be removed in the next major version\n * @returns The schedule schema\n */\nexport const unstable_scheduleSchema = scheduleSchema;\n"],"mappings":";;;;;;;;AAOA,SAAgB,kBAAkB,OAAuB;AACvD,QAAO;;;gBAGO,MAAM,KAAK,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CzC,IAAI,wCAAwC;;;;;;AAO5C,SAAgB,2BAA2B,OAAuB;AAChE,KAAI,CAAC,uCAAuC;AAC1C,0CAAwC;AACxC,UAAQ,KACN,iJACD;;AAEH,QAAO,kBAAkB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BjC,MAAa,iBAAiB,EAAE,OAAO;CACrC,aAAa,EAAE,QAAQ,CAAC,SAAS,4BAA4B;CAC7D,MAAM,EAAE,OAAO;EACb,MAAM,EACH,QAAQ,CACR,UAAU,CACV,SACC,+FACD;EACH,MAAM,EAAE,OACL,MAAM,CACN,UAAU,CACV,SACC,kFACD;EACH,gBAAgB,EACb,QAAQ,CACR,UAAU,CACV,SACC,0EACD;EACH,MAAM,EACH,KAAK;GAAC;GAAa;GAAW;GAAQ;GAAc,CAAC,CACrD,SAAS,iCAAiC;EAC9C,CAAC;CACH,CAAC;;;;;AAWF,MAAa,0BAA0B"}