# @healthcloudai/hc-ams

> HealthCloud AMS SDK — application-agent discovery for AMS Services.

Latest version **3.6.0** (published 2026-09-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install @healthcloudai/hc-ams
pnpm add @healthcloudai/hc-ams
yarn add @healthcloudai/hc-ams
bun add @healthcloudai/hc-ams
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.6.0 |
| Published | 2026-09-23 |
| First published | 2026-09-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 151.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Healthcheck Systems Inc |
| Maintainers | health-cloud |
| Keywords | health-cloud, healthcloud, ams, agents, typescript, sdk |

## Links

- npm: https://www.npmjs.com/package/@healthcloudai/hc-ams
- Repository: https://github.com/healthcloudservices/healthcloud-sdk
- Homepage: https://github.com/healthcloudservices/healthcloud-sdk#readme
- Issues: https://github.com/healthcloudservices/healthcloud-sdk/issues
- npm.io page: https://npm.io/package/@healthcloudai/hc-ams

## Alternatives

- [@openai/codex-sdk](https://npm.io/package/@openai/codex-sdk.md) — 731.4K weekly downloads
- [babel-plugin-transform-react-jsx](https://npm.io/package/babel-plugin-transform-react-jsx.md) — 565.0K weekly downloads
- [babel-helper-remove-or-void](https://npm.io/package/babel-helper-remove-or-void.md) — 508.5K weekly downloads
- [@pnpm/store-controller-types](https://npm.io/package/@pnpm/store-controller-types.md) — 186.9K weekly downloads
- [react-native-signature-canvas](https://npm.io/package/react-native-signature-canvas.md) — 155.6K weekly downloads

## Recent versions

- 3.6.0 (latest) — 2026-09-23
- 3.5.1 — 2026-09-23
- 0.0.1 — 2026-09-22

## README

# HealthCloud AMS SDK for NodeJS / TypeScript

Typed access to AMS Services: agent/department/team/skill/policy/guardrail
CRUD, the data-source and tool catalogs, synthetic test-patient personas,
conversation history, and the real-time WebSocket agent-chat runtime.

## Installation

```bash
npm install @healthcloudai/hc-ams
```

## Quick start

```ts
import { HCAmsSDK } from "@healthcloudai/hc-ams";

const sdk = new HCAmsSDK({ environment: "dev" });

const agents = await sdk.ams.getAgentsForTenant("<TENANT_ID>");
// { public: [...], orchestrator: [...] }
```

## Authentication

`ams.getAgentsForTenant` is public and requires no access token.

Every other REST client (`agents`, `departments`, `teams`, `skills`,
`policies`, `guardrails`, `dataSources`, `tools`, `testPersonas`) requires a
**Tenant Admin** Bearer token, set via `accessToken` in the constructor or
`sdk.setAccessToken(token)`. This SDK does not obtain that token itself —
get one from AMS's own `sdk.auth.login(...)` or from
`@healthcloudai/hc-tenantadmin`, and pass it in.

The WebSocket runtime (`sdk.connectAgentChat(...)` / `WssClient`) is
authenticated with a **patient** Health Cloud access token instead — obtain
one via `sdk.testPersonas.login(credentialId)` for testing, or from your
own patient auth flow in production.

## REST clients

| Client | Resource | Notes |
| --- | --- | --- |
| `sdk.ams` | Public application-agent discovery | No auth required |
| `sdk.agents` | Agent CRUD, transfer candidates, conversation history | `create`/`update`/`delete` may 405 if the tenant has `disable_direct_agent_mutations` enabled (see below) |
| `sdk.departments` | Department CRUD + activate/deactivate | |
| `sdk.teams` | Team CRUD | |
| `sdk.skills` | Skill CRUD | |
| `sdk.policies` | Policy CRUD | |
| `sdk.guardrails` | Guardrail CRUD | |
| `sdk.dataSources` | Data source catalog | Read-only — AMS exposes no create/update/delete |
| `sdk.tools` | Tool catalog | Read-only — AMS exposes no create/update/delete |
| `sdk.testPersonas` | Synthetic QA patient persona CRUD + login | `login()` mints a real Health Cloud patient token |
| `sdk.auth` | AMS's own Tenant Admin auth proxy (`/api/auth/*`) | Resolves against a different base path than every other client |

```ts
const sdk = new HCAmsSDK({ environment: "dev", accessToken: tenantAdminToken });

const department = await sdk.departments.create({ name: "Cardiology", created_by_user_id: "admin-1" });
const agent = await sdk.agents.create({ name: "Cardiology Intake", department_id: department.id });
const history = await sdk.agents.getConversation(agent.id, `${tenantId}/${patientId}`);
```

### Direct agent mutation

Some tenants run with `disable_direct_agent_mutations` enabled, in which
case AMS's plain `POST/PUT/DELETE /agents` routes respond 405 and real agent
authoring happens through the Vibe Coder plan/apply flow instead. That flow
is intentionally out of scope for this SDK — `sdk.agents.create/update/delete`
only cover the plain-CRUD path.

## WebSocket agent-chat runtime

> **Since 3.5.1**: the patient token is sent as the first WebSocket frame
> (`{"type":"auth","token":"..."}`) right after the socket opens, never in
> the connect URL or as a WS subprotocol — `chat.connect()` doesn't resolve
> until the server replies `auth_ok`. This is handled internally; you don't
> need to change any calling code that already passes `healthcloudToken` or
> `getAccessToken`. It **does require the AMS backend to be on the matching
> version** (the corresponding server-side change is
> [healthcloudservices/healthcloud-ams-services#280](https://github.com/healthcloudservices/healthcloud-ams-services/issues/280),
> merged via #288) — against an older backend, `connect()` will reject with
> an auth timeout instead of connecting. `WssClientOptions.tokenTransport`
> (0.0.1) is removed; if your code set it explicitly, delete that line.

```ts
const sdk = new HCAmsSDK({ environment: "dev", tenantId: "<TENANT_ID>", accessToken: tenantAdminToken });

// Mint a patient token for a synthetic test persona.
const session = await sdk.testPersonas.login(personaCredentialId);

// Connect and hold a multi-turn conversation with one agent.
const chat = sdk.connectAgentChat({
  patientId: session.patient_id,
  healthcloudToken: session.access_token,
  agentId: "<AGENT_ID>", // omit to use the tenant's default agent
});
await chat.connect();

const turn = await chat.sendAndAwaitTurn("Hi, I'd like to schedule a check-up.");
console.log(turn.message, turn.transfers, turn.artifacts, turn.notifications, turn.activity);

chat.close();
```

**Note:** the `HCAmsSDK` instance's own `accessToken` (Tenant Admin) above
is only needed because this example uses `testPersonas.login` to mint a
*synthetic* test patient — a testing convenience, not a production
pattern. `connectAgentChat`/`WssClient` never read that `accessToken`;
they only ever use the `healthcloudToken` you pass them explicitly. A real
patient-facing app needs **no Tenant Admin token at all** — get the
patient token from your own patient auth (`@healthcloudai/hc-sdk`), e.g.:

```ts
import { HCSDK } from "@healthcloudai/hc-sdk";
import { HCAmsSDK } from "@healthcloudai/hc-ams";

const patientSdk = new HCSDK({ environment: "dev", tenantId: "<TENANT_ID>" });
const login = await patientSdk.auth.login({ email, password }); // real patient credentials

const amsSdk = new HCAmsSDK({ environment: "dev", tenantId: "<TENANT_ID>" }); // no accessToken needed
const chat = amsSdk.connectAgentChat({
  patientId: login.fhir_patient_id,
  healthcloudToken: login.access_token,
  agentId: "<AGENT_ID>",
});
await chat.connect();
```

`WssClient` also exposes raw typed event subscription for finer-grained
control:

```ts
chat.on("turn_started", (e) => console.log("turn started", e.turn_id));
chat.on("chat", (e) => process.stdout.write(e.content));
chat.on("transfer", (e) => console.log("agent switched", e.to_agent_id));
```

The entire multi-agent conversation (orchestrator plus any number of
downstream specialist agents) lives on this **one** WebSocket connection —
agent switches arrive as `transfer` events, not reconnects.

For a **reconnect** (network drop, or your own periodic re-auth), pass
`getAccessToken` instead of a static `healthcloudToken` so a fresh token is
resolved on every `connect()` call rather than replaying a captured,
possibly-expired one:

```ts
const chat = sdk.connectAgentChat({
  patientId,
  getAccessToken: () => myAuthStore.getCurrentPatientToken(), // called on every connect()
  agentId,
});
```

### Guest chat before sign-in, then handoff to an authenticated conversation

For an agent configured with `requires_auth: false` (a public, pre-login
agent), no patient login or access token is needed. The connection still
requires a `patientId` to form its session ID; generate a random guest ID
for that — it is **not** a real FHIR patient ID, and the server never
resolves it against a real patient record for a `requires_auth: false`
agent.

```ts
const { public: publicAgents, orchestrator } = await amsSdk.ams.getAgentsForTenant(tenantId);

const guestId = crypto.randomUUID();
const guestChat = amsSdk.connectAgentChat({
  patientId: guestId,
  healthcloudToken: "", // no token needed for a requires_auth: false agent
  agentId: publicAgents[0],
});
await guestChat.connect();

const guestTurn = await guestChat.sendAndAwaitTurn("What services are available?");
console.log(guestTurn.message);
```

Once the patient signs in, start a **new** connection with the real
`patientId`/`healthcloudToken` — and pass `handoff` with the guest
transcript so the orchestrator's first greeting can acknowledge it,
instead of the conversation starting as if nothing was said:

```ts
guestChat.close();

const login = await patientSdk.auth.login({ email, password });

const chat = amsSdk.connectAgentChat({
  patientId: login.fhir_patient_id,
  healthcloudToken: login.access_token,
  agentId: orchestrator[0],
  handoff: [
    { role: "user", content: "What services are available?" },
    { role: "assistant", content: guestTurn.message },
  ],
});
await chat.connect();
```

`handoff` is sent once, at connect time — the server reads it before
generating the first greeting, so the greeting itself can reference the
handed-off content (e.g. "I see you were asking about X — let's continue
from there"). It is **not** the same as `sendHandoff(messages)` (a
post-connect frame kept only for callers on the older contract): that one
can only silently append to history after the greeting has already gone
out.

On Node < 21 (no global `WebSocket`), pass a compatible implementation:

```ts
import WebSocket from "ws";

const chat = sdk.connectAgentChat({
  patientId,
  healthcloudToken,
  WebSocketImpl: WebSocket as any,
});
```

See [`TEST_LIST.md`](./TEST_LIST.md) for a full end-to-end flow: creating a
department/team/agents/test-persona, logging in as the persona, and
validating a multi-turn conversation's turns, transfers, artifacts,
notifications, and activity.

## Configuration

| Option | Description |
| --- | --- |
| `environment` | `"dev"` \| `"uat"` \| `"prod"` — resolves the AMS base URL (`{env-}amsservices.health.cloud/api/ams`, no prefix for `prod`). |
| `tenantId` | Optional default tenant ID, used by `connectAgentChat` when no `tenantId` is passed per-call. |
| `accessToken` | Optional Tenant Admin bearer token for authenticated REST methods. |
| `baseUrlOverride` | Overrides the resolved AMS base URL (e.g. for local/staging testing). |
| `timeout` | Request timeout in milliseconds. Defaults to 30000. |

---
_Source: https://npm.io/package/@healthcloudai/hc-ams · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
