{"_id":"@a2anet/react","_rev":"3-36408365f0d78ec8353620d6bc1c1914","name":"@a2anet/react","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.0":{"name":"@a2anet/react","version":"0.0.0","keywords":["a2a","agents","react","sdk"],"author":{"name":"A2A Net","email":"hello@a2anet.com"},"license":"Apache-2.0","_id":"@a2anet/react@0.0.0","maintainers":[{"name":"benclarkenpm","email":"ben@a2anet.com"}],"homepage":"https://github.com/a2anet/a2anet-sdk/tree/main/packages/react#readme","bugs":{"url":"https://github.com/a2anet/a2anet-sdk/issues"},"dist":{"shasum":"36e581824d7912311926a8b36b9d0510d1615026","tarball":"https://registry.npmjs.org/@a2anet/react/-/react-0.0.0.tgz","fileCount":7,"integrity":"sha512-mU8jKvqdLNGZJnyDGhIeYAEhOtfatndrLK8VyPx8eYxWROEBEhmgUqPJE5x43uSfQWQGs4tW+YJb1Cuqx3PDKA==","signatures":[{"sig":"MEYCIQC15BDYq7P/2G430wEjwXN7rZKWIfQGinQ/RU5Q1kHPogIhAOGsOvOPu2jUhj/E8kmtglgC1+qmmMTd+hVkc8jb/jF2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13390},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"85398fcd5c011623e7b4c71281fe99a27f2ea663","scripts":{"test":"bun test","build":"tsc","typecheck":"tsc --noEmit","test:coverage":"bun test --coverage"},"_npmUser":{"name":"benclarkenpm","email":"ben@a2anet.com"},"repository":{"url":"git+https://github.com/a2anet/a2anet-sdk.git","type":"git","directory":"packages/react"},"_npmVersion":"10.9.4","description":"React SDK for A2A Net","directories":{},"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.0.0","@types/react":"^19.0.0"},"peerDependencies":{"react":"^18.2.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.0.0_1786392815105_0.453610677587297","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@a2anet/react","version":"0.1.0","keywords":["a2a","agents","react","sdk"],"author":{"name":"A2A Net","email":"hello@a2anet.com"},"license":"Apache-2.0","_id":"@a2anet/react@0.1.0","maintainers":[{"name":"benclarkenpm","email":"ben@a2anet.com"}],"homepage":"https://github.com/a2anet/a2anet-sdk/tree/main/packages/react#readme","bugs":{"url":"https://github.com/a2anet/a2anet-sdk/issues"},"dist":{"shasum":"50ed26c016ae974554f2fbdde61575782643cd20","tarball":"https://registry.npmjs.org/@a2anet/react/-/react-0.1.0.tgz","fileCount":19,"integrity":"sha512-tjSWdkE5W26Q5c99ytEzWZvYfVKKk2POmM7tj36g70SYsVujpPETreCThu5UU4kL73TvxEP8m+FMgusIIjIcIg==","signatures":[{"sig":"MEQCIGhhWiSB5qa8NrZjf/6lErOyY4dMD4yqRFGVaNUvlogFAiAaRelpOf77ZeUGMsQieVkTE3OJDIfTSIdhHHp92Pupkg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a2anet%2freact@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":66127},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"66b5dfc2d04d22a31d24223da0d947e9ec0a49fd","scripts":{"test":"bun test && bun run test:types && bun run test:vite","build":"tsc","test:vite":"bun run build && vite build --logLevel error tests/vite","typecheck":"tsc --noEmit","test:types":"tsc -p tsconfig.tests.json","test:coverage":"bun test --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:75b7d431-0d0a-4815-bda9-6e2378ee3b10"}},"repository":{"url":"git+https://github.com/a2anet/a2anet-sdk.git","type":"git","directory":"packages/react"},"_npmVersion":"11.16.0","description":"React SDK for A2A Net","directories":{},"_nodeVersion":"24.18.0","dependencies":{"rxjs":"7.8.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.1","react":"^19.0.0","react-dom":"^19.0.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@testing-library/react":"^16.3.2","@happy-dom/global-registrator":"^20.0.8"},"peerDependencies":{"react":"^18.2.0 || ^19.0.0","@ag-ui/client":"^0.0.57","@copilotkit/react-core":"^1.62.3"},"_npmOperationalInternal":{"tmp":"tmp/react_0.1.0_1786468512630_0.056524684320249596","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@a2anet/react","version":"0.2.0","description":"React SDK for A2A Net","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"bun test && bun run test:types && bun run test:vite","test:coverage":"bun test --coverage","test:types":"tsc -p tsconfig.tests.json","test:vite":"bun run build && vite build --logLevel error tests/vite"},"keywords":["a2a","agents","react","sdk"],"author":{"name":"A2A Net","email":"hello@a2anet.com"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/a2anet/a2anet-sdk.git","directory":"packages/react"},"bugs":{"url":"https://github.com/a2anet/a2anet-sdk/issues"},"homepage":"https://github.com/a2anet/a2anet-sdk/tree/main/packages/react#readme","publishConfig":{"access":"public"},"peerDependencies":{"@ag-ui/client":"^0.0.57","@copilotkit/react-core":"^1.62.3","react":"^18.2.0 || ^19.0.0"},"dependencies":{"rxjs":"7.8.1"},"devDependencies":{"@happy-dom/global-registrator":"^20.0.8","@testing-library/react":"^16.3.2","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","react":"^19.0.0","react-dom":"^19.0.0","vite":"^7.3.1"},"gitHead":"b1a842ccf2749278d567fb0c15cb23889dfd47ab","_id":"@a2anet/react@0.2.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-E9i0rTMb732LOE/2OBnNc3KY0QRttokB9fQ8yQFNgf/u3+K6wjkzetHMzWuSBxW4SgBIgYM624ozAlrnGJmEqw==","shasum":"884ac1e1e878a31280917926be669166009ff421","tarball":"https://registry.npmjs.org/@a2anet/react/-/react-0.2.0.tgz","fileCount":19,"unpackedSize":75388,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@a2anet%2freact@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBTUtWJYHaxcIBq8iN35se4B0o+PNGQ7cwS30kaamAraAiAtdEGojbs7BwpDYYrYALOyyFnOtop8/3xyoW/CJXJqGg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:75b7d431-0d0a-4815-bda9-6e2378ee3b10"}},"directories":{},"maintainers":[{"name":"benclarkenpm","email":"ben@a2anet.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react_0.2.0_1787216436939_0.452687772967711"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T20:13:34.940Z","modified":"2026-08-20T09:00:37.629Z","0.0.0":"2026-08-10T20:13:35.268Z","0.1.0":"2026-08-11T17:15:12.851Z","0.2.0":"2026-08-20T09:00:37.080Z"},"bugs":{"url":"https://github.com/a2anet/a2anet-sdk/issues"},"author":{"name":"A2A Net","email":"hello@a2anet.com"},"license":"Apache-2.0","homepage":"https://github.com/a2anet/a2anet-sdk/tree/main/packages/react#readme","keywords":["a2a","agents","react","sdk"],"repository":{"type":"git","url":"git+https://github.com/a2anet/a2anet-sdk.git","directory":"packages/react"},"description":"React SDK for A2A Net","maintainers":[{"name":"benclarkenpm","email":"ben@a2anet.com"}],"readme":"# `@a2anet/react`\n\nReact SDK for [A2A Net](https://a2anet.com). It connects your app to an agent and gives\n[CopilotKit](https://www.copilotkit.ai/) everything it needs to render the conversation.\n\n## Install\n\n```bash\nnpm install @a2anet/react @ag-ui/client @copilotkit/react-core\n```\n\n## Credentials\n\nFor performance reasons, the chat connects to A2A Net from the browser without going\nthrough a server-side endpoint or proxy. For browsers to authenticate with A2A Net, they\nuse a short-lived JWT token, which your backend mints with your A2A Net API key. The key\nnever leaves the server.\n\nAdd an endpoint that authenticates the user, mints a customer token, and returns it along\nwith the agent it is for. `POST /api/token` is the path this SDK's example uses, and yours\nis whatever you name in `getCredentials`:\n\n```ts\n{\n    token: string;\n    expiresAt: string;\n    agentId: string;\n}\n```\n\nThe token is minted for one agent, so the server that mints it is the one place that names\nit. Requests from the browser go to `https://agent.a2anet.com`, exported as\n`A2ANET_RUNTIME_URL`; pass `runtimeUrl` to the provider to point at a runtime of your own\nduring local development.\n\n`A2ANetProvider` calls `getCredentials` on mount, and again whenever the token it holds is\nspent. Send whatever your backend needs to authenticate the user, the same as any other\nrequest to it:\n\n```tsx\nimport { useCallback } from \"react\";\nimport { A2ANetProvider, type A2ANetCredentials } from \"@a2anet/react\";\n\nexport function Root() {\n    const getCredentials = useCallback(async (): Promise<A2ANetCredentials> => {\n        const response = await fetch(\"/api/token\", {\n            method: \"POST\",\n            headers: { Authorization: `Bearer ${await getAccessToken()}` },\n        });\n        if (!response.ok) throw new Error(`Credential request failed with ${response.status}`);\n        return response.json();\n    }, []);\n\n    return (\n        <A2ANetProvider getCredentials={getCredentials}>\n            <App />\n        </A2ANetProvider>\n    );\n}\n```\n\nMount the provider above anything that can unmount, such as a drawer. It holds the agent,\nwhich owns the conversation.\n\nA working endpoint and provider, ready to copy, are in\n[`examples/website-app`](../../examples/website-app).\n\n### Renewal\n\nA minted token is short-lived, and the provider replaces it for you. It gives the agent a\n`fetch` of its own that checks the token and mints a replacement before each request, so a\nspent token is replaced by whatever the user does next — sending a message, reconnecting to\na thread, stopping a run. No timer renews one: a background tab or a sleeping machine defers\ntimers well past a token's life, and a session waiting on one signs its requests with a dead\ntoken.\n\n`status` turns to `Error` only once no usable token is left, so a single failed mint does\nnot tear down a working conversation.\n\nThe one gap is requests the provider does not make. CopilotKit's thread endpoints — listing,\nrenaming, archiving and deleting conversations — build a `fetch` of their own and carry\nwhatever token the last render gave them, and a user can reach all of them without ever\nsending a message. Await `checkAndMintCredentials` before those:\n\n```tsx\nconst { checkAndMintCredentials } = useA2ANet();\nconst { refetchThreads } = useThreads({ agentId });\n\nconst showThreads = async () => {\n    await checkAndMintCredentials();\n    refetchThreads();\n};\n```\n\n## Rendering the chat\n\n`useA2ANet` returns the properties CopilotKit needs, plus the credential's status. The SDK\ndoes not mount CopilotKit, so the loading and error UI stay yours:\n\n```tsx\nimport { CopilotChat, CopilotKitProvider } from \"@copilotkit/react-core/v2\";\nimport { A2ANetStatus, useA2ANet } from \"@a2anet/react\";\n\nexport function App() {\n    const { copilotKitProps, status, error, retry } = useA2ANet();\n\n    if (status === A2ANetStatus.Loading) return <p>Connecting…</p>;\n    if (status === A2ANetStatus.Error) {\n        return <button onClick={retry}>{error?.message ?? \"Try again\"}</button>;\n    }\n\n    return (\n        <CopilotKitProvider {...copilotKitProps}>\n            <CopilotChat agentId={copilotKitProps.agent} />\n        </CopilotKitProvider>\n    );\n}\n```\n\n## Artifacts\n\nFiles the agent produces arrive as events rather than messages, so render them yourself.\n`useA2ANetArtifacts` collects them, keyed by the message each one followed, and\n`downloadArtifact` saves one. Render this inside `CopilotKitProvider`:\n\n```tsx\nimport { useMemo } from \"react\";\nimport { downloadArtifact, useA2ANetArtifacts } from \"@a2anet/react\";\nimport {\n    CopilotChat,\n    CopilotChatAssistantMessage,\n    useAgent,\n    type CopilotChatAssistantMessageProps,\n} from \"@copilotkit/react-core/v2\";\n\nfunction Chat({ agentId, threadId }: { agentId: string; threadId: string }) {\n    const { agent } = useAgent({ agentId, updates: [] });\n    const artifacts = useA2ANetArtifacts(agent, threadId);\n\n    // Object.assign carries over the slot's static members, which its type requires.\n    const assistantMessage = useMemo(\n        () =>\n            Object.assign(\n                (props: CopilotChatAssistantMessageProps) => (\n                    <>\n                        <CopilotChatAssistantMessage {...props} />\n                        {(artifacts.get(props.message.id) ?? []).map((file) => (\n                            <button\n                                key={file.id}\n                                type=\"button\"\n                                onClick={() => downloadArtifact(file)}\n                            >\n                                {file.filename}\n                            </button>\n                        ))}\n                    </>\n                ),\n                CopilotChatAssistantMessage,\n            ),\n        [artifacts],\n    );\n\n    return <CopilotChat agentId={agentId} threadId={threadId} messageView={{ assistantMessage }} />;\n}\n```\n\n## Context\n\nPass `getContext` to tell the agent what the user is looking at. It is read on every run, so\nit can return whatever the current page holds:\n\n```tsx\n<A2ANetProvider getCredentials={getCredentials} getContext={() => ({ \"venue-name\": venue })}>\n```\n\nContext values are prepended to the user's message. The agent sees them and they stay in its\nsession, but they are not saved to the AG-UI transcript that the user sees.\n","readmeFilename":"README.md"}