@cerebro-labs/agentnava-sdk 0.53.2 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/agent.d.ts +57 -7
- package/agent.js +69 -9
- package/agent.js.map +1 -1
- package/attach.d.ts +3 -0
- package/attach.js.map +1 -1
- package/connection.d.ts +10 -0
- package/connection.js +13 -2
- package/connection.js.map +1 -1
- package/conversation.d.ts +37 -1
- package/conversation.js +28 -2
- package/conversation.js.map +1 -1
- package/end-user.d.ts +10 -0
- package/end-user.js +7 -0
- package/end-user.js.map +1 -1
- package/errors.d.ts +20 -0
- package/errors.js +24 -0
- package/errors.js.map +1 -1
- package/http.d.ts +4 -1
- package/http.js +21 -9
- package/http.js.map +1 -1
- package/import-tools.d.ts +5 -0
- package/import-tools.js +47 -6
- package/import-tools.js.map +1 -1
- package/index.d.ts +4 -3
- package/index.js +2 -1
- package/index.js.map +1 -1
- package/knowledge-base.d.ts +18 -18
- package/knowledge-base.js +28 -0
- package/knowledge-base.js.map +1 -1
- package/package.json +1 -1
- package/partner-app.d.ts +70 -0
- package/partner-app.js +125 -0
- package/partner-app.js.map +1 -0
- package/react.css +32 -1
- package/react.js +8 -0
- package/react.js.map +1 -1
- package/secret.d.ts +6 -0
- package/secret.js +15 -0
- package/secret.js.map +1 -1
- package/turn.js +6 -0
- package/turn.js.map +1 -1
- package/types.d.ts +144 -0
- package/types.js.map +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/workspace.d.ts +35 -1
- package/workspace.js +35 -0
- package/workspace.js.map +1 -1
package/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4DAA4D;AAkB5D;;;mCAGmC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC","sourcesContent":["// The shapes this SDK hands back. Transcribed from design/sdk-design.md's own\n// Types section so the reference and the code cannot drift.\n\n// Type-only: erased from the emitted JavaScript, so these add no runtime cycle\n// with the modules that import their own shapes from here.\nimport type { AppId } from './apps.generated.ts';\nimport type { Connection } from './connection.ts';\n\n/** The quality of model an agent's turns run on, and what each turn costs.\n *\n * `standard` is the default: the fastest model the platform runs. `lite` is\n * the lowest price. `premium` costs the same as `standard` and thinks harder,\n * answering more slowly. `best` is the strongest model.\n *\n * Renamed in 0.49.0: the grade that was `fast` is now `standard`, and the one\n * that was `standard` is now `lite`. The platform still accepts `fast` from\n * older code and treats it as `standard`. */\nexport type Grade = (typeof GRADE_NAMES)[number];\n\n/** Every grade, as a list a reply can be checked against. This SDK is\n * published and cannot import the platform's private price list, so it keeps\n * its own copy of the NAMES; a test in the platform's monorepo fails the\n * moment the two lists differ. */\nexport const GRADE_NAMES = ['lite', 'standard', 'premium', 'best'] as const;\nexport type Filesystem = 'drive' | 'none';\n\n/** Where a SECRET is supplied.\n *\n * 'fixed' is set once on the agent and used by every conversation. 'conversation'\n * is asked for when a conversation starts, so each user brings their own. The\n * two DO NOT substitute for each other: a value set on the agent does not\n * satisfy a declaration scoped 'conversation'.\n *\n * Connections stopped using this in 0.44. A connection says WHOSE ACCOUNT it\n * uses instead: the agent creator's (`account`) or each end user's own\n * (`endUser: true`). See `AgentConnection`. */\nexport type Scope = 'fixed' | 'conversation';\n\nexport interface WorkspaceInfo {\n\tid: string;\n\tname: string;\n\tcredits: number;\n\tcreatedAt: string;\n}\n\n/** One procedure the agent follows when its `when` matches what is in front of\n * it. `when` is one line and is not optional: it is what the agent reads to\n * decide the workflow applies, so a vague one makes a good workflow invisible. */\nexport interface Workflow {\n\tname: string;\n\twhen: string;\n\tcontent: string;\n}\n\n// `SessionMode` is deliberately NOT exposed.\n//\n// The API has one ('per-user' | 'per-call') and 'per-user' makes the server\n// resume a person's most recent conversation. That is the behaviour `start`\n// refuses to have: a verb that sometimes returns something you already had, and\n// which has to guess which one the moment a person has two.\n//\n// Its other effect, fanning a scheduled firing out across the people who have\n// conversations with an agent, is real and worth exposing one day. It should\n// arrive under a name that says THAT, not under a mode that also silently\n// changes what `start` returns.\n\nexport type Trigger =\n\t| { kind: 'chat' }\n\t| ({ kind: 'schedule'; enabled?: boolean; cron: string; timezone?: string; message: string } & TriggerTarget)\n\t| { kind: 'interval'; seconds: number; maxRuns?: number; message: string }\n\t| ({\n\t\t\tkind: 'webhook';\n\t\t\tmessage?: string;\n\t\t\t/**\n\t\t\t * Where your system POSTs, set by the platform. Read it from the agent\n\t\t\t * that `setTriggers()` returns: `agent.data?.triggers`. Anything you\n\t\t\t * send here is ignored, so passing back a list you read is safe and\n\t\t\t * keeps the same URL. One webhook per agent; `rotateWebhookUrl()`\n\t\t\t * replaces the URL.\n\t\t\t */\n\t\t\turl?: string;\n\t\t\t/**\n\t\t\t * Check WHO sent each delivery, beyond knowing the URL. See\n\t\t\t * WebhookVerify for the schemes and an example. Leave it out to keep\n\t\t\t * what the webhook has. The secret is stored encrypted and never read\n\t\t\t * back: a read says `secretSet: true` instead.\n\t\t\t */\n\t\t\tverify?: WebhookVerify;\n\t } & TriggerTarget);\n\n/**\n * How a webhook checks its sender. Platforms that send webhooks sign every\n * delivery with a secret they show you when you add the URL there; give it\n * here, and a delivery whose signature does not match is refused (401) and\n * never runs the agent.\n *\n * ```ts\n * { kind: 'webhook', verify: { kind: 'stripe', secret: 'whsec_...' } }\n * { kind: 'webhook', verify: { kind: 'header', header: 'X-Webhook-Secret', secret: '...' } }\n * ```\n *\n * The schemes: `stripe`, `github`, `shopify`, `slack` and\n * `standard` (the Standard Webhooks spec) check that platform's signature;\n * `header` checks a header your sender adds (Zapier, Make, n8n, your own code\n * can all add one); `none` relies on the URL alone.\n */\nexport type WebhookVerify =\n\t| { kind: 'none' }\n\t| { kind: 'stripe' | 'github' | 'shopify' | 'slack' | 'standard'; secret?: string; secretSet?: boolean }\n\t| { kind: 'header'; header: string; secret?: string; secretSet?: boolean };\n\n/** One delivery a webhook received, newest first from `agent.webhookDeliveries()`. */\nexport interface WebhookDelivery {\n\tid: string;\n\treceivedAt: string;\n\t/** `pending`: checked and starting. `repeat`: the sender retried a delivery\n\t * already accepted; the agent did not run again. */\n\toutcome: 'pending' | 'accepted' | 'refused' | 'repeat' | 'test';\n\t/** Why it was refused. */\n\treason?: string;\n\t/** The sender's own id for it, when it gave one. */\n\tdeliveryId?: string;\n\t/** The conversation it ran in. */\n\tconversationId?: string;\n}\n\n/**\n * WHERE a schedule or webhook runs. Name a conversation, or an end user, or\n * neither; never both.\n *\n * ```ts\n * const conversation = await agent.start({ endUserId: 'ops-app' });\n * await agent.setTriggers([\n * { kind: 'chat' },\n * // Every firing lands in THIS conversation: its history, its drive.\n * { kind: 'schedule', cron: '0 15 * * *', message: 'REFRESH', conversationId: conversation.id },\n * ]);\n * ```\n */\nexport type TriggerTarget =\n\t| {\n\t\t\t/**\n\t\t\t * The conversation every firing CONTINUES: it sees that conversation's\n\t\t\t * history and its drive, and its end user comes with it. Each firing\n\t\t\t * also moves the conversation to the agent's latest version, so a fix\n\t\t\t * you publish reaches it.\n\t\t\t *\n\t\t\t * This is the ONLY way a trigger continues one of your conversations.\n\t\t\t * One end user can have many, so naming the end user cannot say which.\n\t\t\t *\n\t\t\t * Must be a conversation of this agent, started for one of your end\n\t\t\t * users (the id `agent.start()` returned). Anything else is refused\n\t\t\t * when you set the trigger. If the conversation is deleted later, the\n\t\t\t * firings fail and say so; none is opened in its place.\n\t\t\t */\n\t\t\tconversationId: string;\n\t\t\tuserId?: undefined;\n\t }\n\t| {\n\t\t\tconversationId?: undefined;\n\t\t\t/**\n\t\t\t * The end user each firing is for, when it names no conversation. Each\n\t\t\t * firing STARTS A NEW CONVERSATION for them, with an empty drive, and it\n\t\t\t * is listed by `agent.conversations({ endUser })`. To keep adding to\n\t\t\t * one conversation instead, name it with `conversationId`.\n\t\t\t *\n\t\t\t * Your id, as in `agent.start({ endUserId })`; the platform's prefixes\n\t\t\t * (`member:`, `visitor:`, `job:`) are refused.\n\t\t\t *\n\t\t\t * Name neither and the trigger keeps one conversation of its own that\n\t\t\t * every firing continues.\n\t\t\t */\n\t\t\tuserId?: string;\n\t };\n\n/**\n * One connection in an agent's setup, as it reads back: a NAME, an APP, and\n * WHOSE ACCOUNT. Exactly one of these two:\n *\n * | the connection says | whose account | the person signs in |\n * |---|---|---|\n * | `account: '<id>'` | the agent creator's: one account in this workspace, from `ws.accounts.connect()` | once, and every conversation uses it |\n * | `endUser: true` | the end user's: each person talking to the agent | once each, remembered for them |\n *\n * A turn uses EXACTLY the account the setup names, and never another one.\n * There is no fallback to some other account of the same app: an account that\n * is not signed in leaves the connection unavailable, and the agent says so.\n *\n * `name` tells two connections of one app apart, such as `work-gmail` and\n * `personal-gmail`. 1 to 64 characters, lowercase letters, digits and dashes,\n * no dash at either end, unique on the agent. Left out when sent, it is the\n * app's id.\n *\n * Part of the agent's CONFIGURATION, so changing a connection publishes a\n * version. The account itself is not versioned: signing in again reaches every\n * agent that names it. To send one, build it with `Connection.creatorAccount()`\n * or `Connection.endUserAccount()`.\n */\nexport type AgentConnection =\n\t| {\n\t\t\tname: string;\n\t\t\t/** The app's id: `App.GMAIL` is `'gmail'`. */\n\t\t\tapp: AppId;\n\t\t\t/** An account id in this workspace whose app is `app`. */\n\t\t\taccount: string;\n\t\t\tendUser?: never;\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tapp: AppId;\n\t\t\tendUser: true;\n\t\t\taccount?: never;\n\t };\n\n/** What an agent NEEDS, not the stored value. `Secret` is the value. */\nexport interface SecretRequirement {\n\tname: string;\n\tscope: Scope;\n\trequired?: boolean;\n}\n\nexport interface Parameter {\n\tname: string;\n\ttype: 'string' | 'number' | 'date' | 'choice';\n\trequired?: boolean;\n\tdefault?: string;\n\tchoices?: string[];\n}\n\nexport interface McpServer {\n\tname: string;\n\turl: string;\n\ttransport?: 'http' | 'sse';\n\theaders?: Record<string, string>;\n\ttimeoutMs?: number;\n}\n\nexport interface HttpToolParam {\n\ttype: 'string' | 'number' | 'boolean' | 'object' | 'array';\n\tdescription?: string;\n\trequired?: boolean;\n\tchoices?: (string | number | boolean | null)[];\n\tnullable?: boolean;\n\tinteger?: boolean;\n\tproperties?: Record<string, HttpToolParam>;\n\titems?: HttpToolParam;\n\tadditionalProperties?: boolean;\n}\n\nexport interface HttpTool {\n\tname: string;\n\tdescription: string;\n\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\turl: string;\n\theaders?: Record<string, string>;\n\tbody?: string;\n\tparams?: Record<string, HttpToolParam>;\n\tsecrets?: string[];\n\ttimeoutMs?: number;\n}\n\n/**\n * Guardrails: what the platform enforces on an agent, even when someone tries to\n * talk the agent out of it. An agent's `instructions` are what it TRIES to do;\n * its guardrails are checked by the platform before the agent reads a message,\n * so a person cannot argue it past them.\n *\n * ```ts\n * await agent.update({\n * guardrails: {\n * stayOnTopic: true,\n * rules: ['Never offer discounts or change prices.'],\n * },\n * });\n * ```\n *\n * A message that breaks one is declined before the agent reads it, and the agent\n * replies politely in its own voice instead; an action that breaks one does not\n * happen; a reply that breaks one is taken back and answered again. The turn's\n * stream says which rule fired (`{ type: 'guardrail' }`).\n *\n * Part of the CONFIGURATION, like `connections`, so changing it publishes a\n * version, and a conversation already in progress keeps the version it began on.\n */\nexport interface Guardrails {\n\t/** Decline anything outside this agent's job, judged from its own\n\t * instructions: other work (code, homework, poems), \"ignore your\n\t * instructions\", requests for its prompt or files, and \"I'm the owner\"\n\t * claims made to get special treatment. ON unless set to `false`. */\n\tstayOnTopic?: boolean;\n\t/** Your own rules, one plain-English sentence each (at most 20, each under\n\t * 500 characters). Each is checked on the message, on every action the agent\n\t * tries, and on its reply. A break is declined, blocked or taken back, and the\n\t * stream names the rule. */\n\trules?: string[];\n\t/** Check each message before the agent reads it, so one that breaks a\n\t * guardrail never reaches the agent and nothing it asked for is done. Costs\n\t * about 0.2 s per message. ON unless set to `false`: off, the agent answers\n\t * at once, and its replies and actions are still checked. */\n\tcheckMessagesFirst?: boolean;\n}\n\nexport interface AgentData {\n\tid: string;\n\tname: string;\n\tinstructions: string;\n\tgreeting?: string;\n\t/** Always present, with the defaults filled in: what is enforced now. */\n\tguardrails: { stayOnTopic: boolean; rules: string[]; checkMessagesFirst: boolean };\n\t/** How its website chat looks. Absent: the default look, starting closed. */\n\tappearance?: WebsiteChatAppearance;\n\tgrade: Grade;\n\tfilesystem: Filesystem;\n\ttools: string[];\n\tworkflows: Workflow[];\n\t/** The apps it uses, each saying whose account. See `AgentConnection`. */\n\tconnections: AgentConnection[];\n\tsecrets: SecretRequirement[];\n\tparameters: Parameter[];\n\ttriggers: Trigger[];\n\tmcpServers: McpServer[];\n\thttpTools: HttpTool[];\n\t/** Workspace knowledge bases this agent reads, by key. Always present, empty\n\t * when none are attached, so a caller never has to distinguish \"none\" from\n\t * \"an older server that did not send the field\". */\n\tknowledgeBases: string[];\n\t/** Workspace databases this agent may query, by key. Always present, like\n\t * `knowledgeBases`. */\n\tdatabases: string[];\n\tversion: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Where it is live, as the portal shows it. The API works it out by the\n\t * same rule it runs the agent by, so `channels.api === 'on'` is exactly\n\t * \"a turn will be taken\". Read-only: nothing sets it. Sent by `agent.get()`\n\t * and `ws.agents.list()`; absent from what create and update return, so\n\t * call `get()` for it. */\n\treadonly status?: AgentStatus;\n}\n\n/** Who can chat with an agent's website chat. 'restricted' (the default):\n * members of your workspace signed in to AgentNava, and visitors on the\n * allowed websites. 'anyone': anyone with the link, on any website. */\nexport type WebsiteChatAccess = 'restricted' | 'anyone';\n\n/** What `agent.websiteChat.get()` gives back. */\nexport interface WebsiteChat {\n\t/** Who can chat. */\n\treadonly access: WebsiteChatAccess;\n\t/** The hosted chat page, the share link. Share it, or open it in an iframe. */\n\treadonly chatUrl: string;\n\t/** The id the embed script's `data-agent-id` takes. */\n\treadonly embedAgentId: string;\n}\n\n/** Where an agent is live. See `AgentData.status`. */\nexport interface AgentStatus {\n\t/** True when any channel is on. */\n\treadonly live: boolean;\n\t/** Paused by its owner: nothing runs it until it is resumed. */\n\treadonly paused: boolean;\n\t/** Archived: nothing runs it again. */\n\treadonly archived: boolean;\n\treadonly channels: {\n\t\t/** 'on' when the API takes new turns for it. */\n\t\treadonly api: 'on' | 'off';\n\t\t/** 'on' when its website chat page answers visitors. 'unavailable' when it\n\t\t * needs what each user brings (`eachUserBrings`), which a visitor cannot. */\n\t\treadonly websiteChat: 'on' | 'off' | 'unavailable';\n\t};\n\t/** Required accounts and secrets of its own that are not set up yet, on the\n\t * version a new conversation runs. It still runs: the tools that use them\n\t * fail until they are set up. Empty when nothing is missing. */\n\treadonly needs: readonly { kind: 'connection' | 'secret'; name: string }[];\n\t/** The accounts and secrets each user supplies for themselves. */\n\treadonly eachUserBrings: readonly { kind: 'connection' | 'secret'; name: string }[];\n}\n\n/**\n * One of an agent's connections as it stands right now: the account it names,\n * and whether that account works. What `agent.connections.list()` returns.\n *\n * DECLARED IS NOT CONNECTED, and this is the read that tells them apart. A\n * connection can name an account nobody has finished signing in to, or one that\n * was disconnected since; that is the state a setup checklist has to show, and\n * without this the only way to find it is to start a conversation and watch\n * the agent fail.\n *\n * Reshaped in 0.44: it used to be keyed by `provider`, with `declared`,\n * `required`, `scope` and `suppliedBy`. A connection is now keyed by its\n * `name`, and it says whose account it uses instead of where one might come\n * from.\n */\nexport interface ConnectionStatus {\n\tname: string;\n\tapp: AppId;\n\t/** The agent creator's account the connection names, read fresh. Absent on\n\t * an end user's connection, and on one whose account is gone. */\n\taccount?: AccountData;\n\t/** True when each person talking to the agent signs in with their own. */\n\tendUser?: true;\n\t/** Whether the connection works now, as the API reports it. For an agent\n\t * creator's account it follows that account's status. */\n\tstatus: string;\n\t/** Only in the agent's unpublished draft, so no conversation uses it yet. */\n\tinDraft: boolean;\n\t/** Removed in the agent's unpublished draft, and still used until the draft\n\t * is published. */\n\tremovedInDraft: boolean;\n}\n\n/** Where one account's sign-in stands.\n *\n * 'pending' made, and nobody has finished signing in yet\n * 'connected' signed in and working\n * 'needs_sign_in' it worked, and the app now wants the person to sign in again\n * 'error' the app refused it for another reason\n */\nexport type AccountStatus = 'pending' | 'connected' | 'needs_sign_in' | 'error';\n\n/** An agent whose setup names an account, and the connection that names it.\n * Counted from the agent's latest published version and its draft, never\n * from older versions. */\nexport interface UsedBy {\n\t/** The agent's id: the same value as `Agent.id`, so compare this one. */\n\tid: string;\n\t/** AgentNava's internal handle for the same agent (`agt_...`), not `Agent.id`. */\n\tagentId: string;\n\tagentName: string;\n\tconnectionName: string;\n\t/** Named in the agent's unpublished draft. */\n\tinDraft: boolean;\n\t/** Named in the agent's latest published version. */\n\tpublished: boolean;\n}\n\n/**\n * One saved sign-in to one app.\n *\n * TWO OWNERS, and the difference is who signs in:\n *\n * | `owner` | whose | a connection uses it as |\n * |---|---|---|\n * | `'workspace'` | the agent creator's, signed in once, usable by any agent | `Connection.creatorAccount(app, account)` |\n * | `'end-user'` | one of YOUR end users', remembered for that person | `Connection.endUserAccount(app)`, in that person's conversations |\n *\n * Both owners are read and changed through the same routes and the same\n * `Account` handle; `owner` says which this is.\n *\n * Nobody handles a token: the person signs in on the app's own page, and this\n * record says who they signed in as, never how.\n */\nexport interface AccountData {\n\tid: string;\n\t/** The app's id: `App.GMAIL` is `'gmail'`. */\n\tapp: AppId;\n\t/** Who it is signed in as: the email or username the app reports. Null until\n\t * somebody has finished signing in. */\n\tlabel: string | null;\n\t/** Your own name for it, such as `'Support inbox'`. Null when none was given. */\n\tnickname: string | null;\n\tstatus: AccountStatus;\n\t/** True while a reconnect waits for the person to sign in again. The\n\t * account keeps working meanwhile, so `status` can still say\n\t * `'connected'`; `waitUntilConnected()` waits for this to clear. */\n\treconnecting: boolean;\n\towner: 'workspace' | 'end-user';\n\t/** The end user it belongs to, when `owner` is `'end-user'`. An id from YOUR\n\t * database, never a workspace member's. */\n\tendUserId?: string;\n\tconnectedAt: string | null;\n\tlastCheckedAt: string | null;\n\t/** The agents whose setup names this account. Empty for an end user's\n\t * account, which a setup never names by id. */\n\tusedBy: UsedBy[];\n}\n\n/** An end user's account a conversation still needs, with the link that\n * person signs in at. From `conversation.accountsNeeded()`. */\nexport interface AccountNeeded {\n\t/** The connection's name on the agent. */\n\tname: string;\n\tapp: AppId;\n\t/** Send the person here. They sign in once, and every later conversation\n\t * of theirs has it. */\n\turl: string;\n}\n\n/** Something a conversation is still missing before it can work. */\nexport interface Requirement {\n\tkind: 'secret' | 'connection';\n\tname: string;\n\trequired: boolean;\n}\n\nexport interface AgentConversationData {\n\tid: string;\n\tagentId: string;\n\t/** The number of the agent version this conversation runs, as `agent.version`\n\t * numbers them. Fixed at start, except that a schedule or webhook naming the\n\t * conversation moves it to the latest version at each firing. */\n\tversion: number;\n\tstartedAt: string;\n\ttitle?: string;\n\t/** True when nothing REQUIRED is outstanding. An optional gap leaves this\n\t * true, because the conversation genuinely does work without it. */\n\tready: boolean;\n\trequires: Requirement[];\n}\n\nexport interface ProjectConversationData {\n\tid: string;\n\tprojectId: string;\n\tstartedAt: string;\n\ttitle?: string;\n\tready: boolean;\n\trequires: Requirement[];\n}\n\n/** An AGENT on a project, not a person.\n *\n * Called `ProjectAgent` and not `Member`, which is what it was. `Member` is\n * the word this product uses for a HUMAN on the account, so a public type of\n * that name holding an `agentId` was the same trap as `userId` meaning two\n * populations: `import { Member }` handed you the agent one, and the human one\n * had to carry a prefix to get out of its way.\n *\n * The people are `WorkspaceMember`, from `ws.members()`. Nothing here is a\n * person. */\nexport interface ProjectAgent {\n\tagentId: string;\n\tname: string;\n\taddedAt: string;\n}\n\nexport interface ProjectData {\n\tid: string;\n\tname: string;\n\tgoal: string | null;\n\tmanagerInstructions: string | null;\n\tgrade: Grade;\n\tstatus: 'active' | 'archived';\n\tagents: ProjectAgent[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface Step {\n\tid: string;\n\tlabel: string;\n\tkind: 'read' | 'write' | 'edit' | 'search' | 'shell' | 'web' | 'data' | 'task' | 'plan' | 'other';\n\tstatus: 'active' | 'done' | 'error';\n}\n\nexport type TurnEvent =\n\t/** First, before anything else: the id the API gave this turn. */\n\t| { type: 'start'; turnId: string }\n\t/** Carries the WHOLE step list every time, not a change to it. Replace what\n\t * you are showing rather than merging; that is what makes reconnecting\n\t * safe. Sent after each tool event that changes the list, with the steps\n\t * and words the portal shows. */\n\t| { type: 'progress'; steps: Step[] }\n\t/** `name` is the tool's identifier, for code. `label` is what a person sees,\n\t * the portal's words (\"Searching the web: <query>\"). */\n\t| { type: 'tool'; name: string; state: 'start' | 'end'; label?: string; ok?: boolean }\n\t/** A fragment, not a line. Append; do not assemble. */\n\t| { type: 'text'; text: string }\n\t/** A file the agent wrote in the conversation's drive. Pass `path` to\n\t * conversation.readFile(). Sent once per file per turn. */\n\t| { type: 'file'; path: string }\n\t/** A widget the agent is drawing inside its reply, sent whole each time it\n\t * grows: replace the one with the same `surfaceId`. Only on a conversation\n\t * started with `widgets: true`. */\n\t| { type: 'widget'; widget: Widget }\n\t/** `widgets` is the reply's final widget list, present when it has any:\n\t * what to keep, whatever arrived live. */\n\t/** One of the agent's guardrails fired. `rule` is the one, as you wrote it,\n\t * or 'Stay on topic'.\n\t * - `message`: the person's message broke it and was declined. The agent\n\t * never read it; the words that follow are its polite refusal.\n\t * - `reply`: the agent's reply broke it and was taken back (a `reset` came\n\t * first); the words that follow are its answer within the rule.\n\t * - `tool`: an action the agent tried (`tool`) broke one of your rules and\n\t * did not happen; the agent explains in the words that follow. Which rule\n\t * is not reported for this stage. */\n\t| { type: 'guardrail'; stage: 'message'; rule: string; action: 'declined' }\n\t| { type: 'guardrail'; stage: 'reply'; rule: string; action: 'replaced' }\n\t| { type: 'guardrail'; stage: 'tool'; tool: string; action: 'blocked' }\n\t/** Replace the words you have shown for this reply with `text`, often empty:\n\t * earlier words were withdrawn (a guardrail) or a step was retried. Clear the\n\t * reply's widgets too; any that still belong are sent again. */\n\t| { type: 'reset'; text: string }\n\t| { type: 'done'; reply: string; widgets?: Widget[] }\n\t| { type: 'error'; message: string; retryable: boolean };\n\n/**\n * One part of a widget, in Google's open A2UI v0.9 format with AgentNava's own\n * set of parts: an id, which kind of\n * part it is (`Column`, `Row`, `Card`, `Text`, `Stat`, `KeyValue`, `Table`,\n * `Chart`, `Image`, `List`, `Note`, `Badge`, `Link`, `Button`, `Suggestions`,\n * `Divider`), and that kind's props. A container lists its children by id.\n */\nexport interface WidgetPart {\n\tid: string;\n\tcomponent: string;\n\t[prop: string]: unknown;\n}\n\n/**\n * A card, table or chart the agent drew inside a reply. Draw it with `WidgetView`\n * from `@cerebro-labs/agentnava-sdk/react`, or your own components starting\n * from the part with id `root`.\n * `at` is where it sits in the reply's text, as a character count, so it goes\n * between the right sentences.\n */\nexport interface Widget {\n\tsurfaceId: string;\n\tat: number;\n\tcomponents: WidgetPart[];\n\t/** Every part arrived. False only while it streams, or on a reply cut short. */\n\tclosed: boolean;\n}\n\nexport interface Message {\n\trole: 'user' | 'assistant';\n\tcontent: string;\n\tat: string;\n\t/** The widgets in an assistant reply, when it has any. */\n\twidgets?: Widget[];\n}\n\n/** An image goes to the model as an image. Anything else is written into the\n * conversation's drive before the turn starts, so the agent can parse it,\n * compute over it, and still have it next turn. */\nexport interface Attachment {\n\tkind: 'image' | 'file';\n\tname?: string;\n\tmimeType: string;\n\t/** base64, without a data: prefix. */\n\tdata: string;\n}\n\n/** A knowledge base: a named folder of files at WORKSPACE scope that an agent\n * configuration attaches by key. */\nexport interface KnowledgeBaseData {\n\t/** Workspace-unique. This is what an agent configuration stores, and it is\n\t * not editable, because renaming it would move every attachment silently. */\n\tkey: string;\n\tname: string;\n\tdescription?: string;\n\t/** Counted when read, so it never disagrees with the files it counts. */\n\tfileCount: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/** One file in a knowledge base. PATH, not a flat name: a base is a folder, and\n * the session mount reproduces the shape verbatim. */\n/**\n * Whether an agent can read a file in a knowledge base.\n *\n * Text and markdown are readable as they stand. A PDF, a scan or a spreadsheet\n * has to be turned into text first, which happens when the file is uploaded\n * rather than when a question is asked, so an agent never waits on it.\n *\n * 'readable' an agent can read this now\n * 'processing' being prepared, check back shortly\n * 'unreadable' cannot be read, and `reason` says why\n */\nexport type KnowledgeFileStatus = 'readable' | 'processing' | 'unreadable';\n\nexport interface KnowledgeFileEntry {\n\tpath: string;\n\tmimeType: string;\n\tsize: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Whether an agent can read this file. */\n\tstatus: KnowledgeFileStatus;\n\t/** Why it cannot be read, as a sentence you could show someone.\n\t *\n\t * The same text reaches the agent in place of the file, so a developer\n\t * reading this and a model reading the base get one explanation rather than\n\t * two that can drift apart. Absent unless `status` is 'unreadable'. */\n\treason?: string;\n}\n\nexport interface FileEntry {\n\tpath: string;\n\tkind: 'file' | 'directory';\n\tmimeType: string;\n\tsize: number;\n\tmodifiedAt: string;\n}\n\n/** Fields accepted when creating or updating an agent. Everything is optional on\n * an update: what you do not send is inherited from the current version, which\n * is the whole reason updating is safe. */\nexport interface AgentFields {\n\tid?: string;\n\tname?: string;\n\tinstructions?: string;\n\tgreeting?: string;\n\t/** What the platform enforces on every incoming message. See `Guardrails`. */\n\tguardrails?: Guardrails;\n\t/**\n\t * How the agent's website chat looks, on the share link and through the\n\t * embed script. Merged by setting: `{ accent: '#B4532A' }` changes the colour\n\t * and keeps the rest; `null` clears one setting, and `appearance: null` goes\n\t * back to the default look. See `WebsiteChatAppearance`.\n\t */\n\tappearance?: { [K in keyof WebsiteChatAppearance]?: WebsiteChatAppearance[K] | null } | null;\n\tgrade?: Grade;\n\tfilesystem?: Filesystem;\n\t/**\n\t * Knowledge bases this agent reads, by workspace-unique key.\n\t *\n\t * Mounted READ-ONLY at `/knowledge/<key>/` when a session starts, so the\n\t * agent finds things with `ls`, `grep` and `cat` rather than a retrieval API.\n\t *\n\t * Which bases an agent reads is part of its CONFIGURATION, so changing this\n\t * publishes a version you can diff and roll back. The CONTENTS of a base are\n\t * not versioned: correcting a file changes what every attached agent sees on\n\t * its next turn, which is the same by-reference promise `agent.knowledge`\n\t * already makes.\n\t *\n\t * A key that names no base is refused when the configuration is saved, and\n\t * deleting a base is refused while any agent attaches it, so an attachment\n\t * that was valid stays valid.\n\t */\n\tknowledgeBases?: string[];\n\t/**\n\t * Workspace databases this agent may query, by key.\n\t *\n\t * Register the database first with `ws.databases.create()`, which logs in\n\t * and gives it the key; then name the key here. Naming it is the grant: a\n\t * database answers only the agents whose configuration names it, and the\n\t * agent's prompt lists them so it knows what to query.\n\t *\n\t * Part of the CONFIGURATION, so changing it publishes a version. A key that\n\t * names no database is refused when the configuration is saved, and\n\t * removing a database is refused while any agent names it.\n\t */\n\tdatabases?: string[];\n\ttools?: string[];\n\t/**\n\t * \"Answer with widgets\": on unless `false`. When on, the agent draws cards,\n\t * tables and charts inside its answers, on a conversation started with\n\t * `widgets: true`. Set `false` for an agent that should answer in text only.\n\t */\n\twidgets?: boolean;\n\tworkflows?: Workflow[];\n\t/**\n\t * The apps this agent uses, each a NAMED connection that says whose account\n\t * it uses: the agent creator's account, or each end user's own. See\n\t * `Connection` and `AgentConnection`.\n\t *\n\t * ```ts\n\t * connections: [\n\t * Connection.creatorAccount(App.GMAIL, work, { name: 'work-gmail' }),\n\t * Connection.creatorAccount(App.GMAIL, personal, { name: 'personal-gmail' }),\n\t * Connection.endUserAccount(App.GOOGLE_CALENDAR),\n\t * ]\n\t * ```\n\t *\n\t * The builders make plain objects, `{ app, account: '<id>' }` and\n\t * `{ app, endUser: true }`, and those objects are accepted as they are.\n\t * `App.GMAIL` is the string `'gmail'`, so a plain app id works too.\n\t *\n\t * Part of the CONFIGURATION, like `databases`, so changing it publishes a\n\t * version. An unknown account id, an account of a different app, a repeated\n\t * name or a name of the wrong shape is refused when the configuration is\n\t * saved, naming the problem.\n\t */\n\tconnections?: Connection[];\n\tsecrets?: SecretRequirement[];\n\tparameters?: Parameter[];\n\ttriggers?: Trigger[];\n\tmcpServers?: McpServer[];\n\thttpTools?: HttpTool[];\n}\n\nexport interface ProjectFields {\n\tname?: string;\n\tgoal?: string;\n\tmanagerInstructions?: string;\n\tgrade?: Grade;\n\tagents?: string[];\n}\n\n/** Secret VALUES supplied to an agent (`agent.attach`) or to one conversation\n * (`conversation.attach`): the secrets its agent declared.\n *\n * Accounts are no longer supplied this way (0.44). An agent's setup names the\n * account each connection uses, so there is nothing left to attach. */\nexport interface Bindings {\n\tsecrets?: Record<string, string>;\n}\n\n/** One markdown file read off disk: a workflow or a subagent.\n *\n * `when` is OPTIONAL here and required at publish. A file on disk has no `when`\n * until someone writes one, and refusing to read it would be the wrong place to\n * say so; the API says it at publish, with a message naming the file. */\nexport interface SpecFile {\n\tname: string;\n\tcontent: string;\n\twhen?: string;\n}\n\n/** What a loaded agent directory produces: the fields `ws.agents.create()` takes,\n * plus the id the caller chose and the few legacy names the loader still reads\n * off an existing directory. */\nexport interface SpecInput extends Omit<AgentFields, 'workflows'> {\n\tkey: string;\n\tworkflows?: SpecFile[];\n\tsubagents?: SpecFile[];\n\tsandbox?: Filesystem;\n\trole?: string;\n\t/** Retired in favour of `tools: ['web_search']`, still read off an existing\n\t * agent directory so one written before the rename still loads. */\n\twebSearch?: boolean;\n}\n\n/** A PERSON with access to this workspace: your colleague, on a seat.\n *\n * NOT one of your end users, and the difference is the sharpest naming trap in\n * this SDK. A workspace member signs in here, we issued their id, and we\n * authenticate it. A `EndUser` is the person YOUR application serves, never\n * signs in here, and carries an id from YOUR database that we store verbatim\n * and never check.\n *\n * `userId` below is therefore a PLATFORM id and is not interchangeable with\n * `agent.start({ endUserId })`. Both fields were once spelled `userId`, which\n * made passing one where the other belonged a call that could not fail: a\n * end-user id is never validated against anything, so it silently labelled a\n * conversation with a colleague's internal id. The two names now differ.\n *\n * Named WorkspaceMember rather than Member because a public `Member` type used\n * to mean an AGENT attached to a project. That one is now `ProjectAgent`, so\n * the prefix here is no longer load-bearing; it stays because it says which of\n * the two populations this is at every call site, and that is worth four\n * characters.\n *\n * Read-only, like everything else on the account surface: the SDK can see who\n * is on the account and what they may do, and cannot add, remove or re-role\n * anyone. Those are decisions a person makes while signed in, not something a\n * key should be able to do on their behalf. */\nexport interface WorkspaceMember {\n\t/** A PLATFORM user id (`usr_...`), issued by us. Never pass this to\n\t * `agent.start({ endUserId })` or `ws.endUser()`. */\n\tuserId: string;\n\temail: string;\n\tname: string | null;\n\t/** 'owner' is the account's creator; 'admin' can manage it; 'member' cannot. */\n\trole: 'owner' | 'admin' | 'member';\n\t/** Unix seconds. */\n\tjoinedAt: number;\n}\n\n/** What is left to spend.\n *\n * `credits` is the balance in credits, where one credit is one US dollar. The\n * turn counts are the same balance expressed in the unit people actually\n * reason with, because \"12.5 credits\" answers nothing on its own. */\nexport interface Credits {\n\tcredits: number;\n\tstandardTurnsRemaining: number;\n\tpremiumTurnsRemaining: number;\n}\n\n/** The seat plan this workspace is on.\n *\n * Seats are a SEPARATE purchase from credits: a plan says how many people may\n * share the account, credits pay for the work their agents do. Being on the\n * free plan does not make turns free. */\nexport interface SeatPlan {\n\tkey: string;\n\tlabel: string;\n\t/** People allowed. `null` means negotiated, which is NOT unlimited and\n\t * should never be shown to anyone as a number. */\n\tseats: number | null;\n\t/** Monthly price in US cents. `null` means there is no published price and\n\t * the answer is a conversation, which is the opposite fact from 0 (free). */\n\tusdCentsPerMonth: number | null;\n}\n\n/** A stored secret, WITHOUT its value.\n *\n * The value is never returned by any read. It is written once, encrypted at\n * rest, and substituted into an HTTP tool's url, headers or body server-side at\n * call time, so it is never part of anything the model can see or repeat. To\n * change one, write it again; to be sure of one, replace it. */\nexport interface SecretMeta {\n\tid: string;\n\tname: string;\n\tdescription?: string | null;\n\t/** The agent this secret is scoped to, or null when the whole workspace\n\t * reads it. An agent-scoped secret of the same name wins. */\n\tagentId?: string | null;\n\t/** The end user this secret belongs to, or null when it is the workspace's.\n\t * One of YOUR user ids, stored verbatim: we never resolve or authenticate\n\t * it. A secret with one can only be attached to a conversation launched for\n\t * that same person. */\n\tendUserId?: string | null;\n\tcreatedAt?: string;\n\tupdatedAt?: string;\n\tlastUsedAt?: string | null;\n}\n\n/** A SQL engine AgentNava can query. */\nexport type DatabaseEngine = 'postgres' | 'mysql' | 'sqlserver';\n\n/** How the connection to a database is encrypted. `verify` (the default)\n * encrypts and always checks the server's certificate: against public and\n * cloud CAs and the host name, or, for a database with its own home-made CA,\n * against the CA AgentNava trusted the first time it connected. `disable` is\n * for a server with no SSL at all. */\nexport type DatabaseTls = 'verify' | 'disable';\n\n/**\n * How to log in to a database: a connection string, OR the same login as\n * separate fields. Never both; a request with both is refused.\n *\n * Read-only unless `writable: true`, which no SQL the agent sends can override.\n */\nexport type DatabaseLogin =\n\t| {\n\t\t\t/** `postgres://`, `postgresql://` or `mysql://`, with the user (and the\n\t\t\t * password, when there is one) in it. An `sslmode` in the string sets `tls`. */\n\t\t\turl: string;\n\t\t\tengine?: DatabaseEngine;\n\t\t\t/** Overrides the string's `sslmode`. */\n\t\t\ttls?: DatabaseTls;\n\t\t\twritable?: boolean;\n\t }\n\t| {\n\t\t\tengine: DatabaseEngine;\n\t\t\thost: string;\n\t\t\tport: number;\n\t\t\tdatabase: string;\n\t\t\tusername: string;\n\t\t\t/** Leave it out for a database that takes a user name alone. */\n\t\t\tpassword?: string;\n\t\t\ttls?: DatabaseTls;\n\t\t\twritable?: boolean;\n\t };\n\n/** What `ws.databases.create()` takes: the key agents will name it by, an\n * optional label, and a login. */\nexport type DatabaseFields = DatabaseLogin & {\n\t/** Lowercase letters, digits and dashes, like `shop` or `sales-db`. What an\n\t * agent configuration stores, so it is not editable afterwards. */\n\tkey: string;\n\t/** A label for people. Defaults to the key. */\n\tname?: string;\n};\n\n/** A registered database as AgentNava reports it: where it is, never how to\n * log in. Neither the password nor the connection string is ever returned. */\nexport interface DatabaseData {\n\tkey: string;\n\t/** The underlying connection's id. */\n\tid: string;\n\tname: string;\n\tengine: DatabaseEngine | null;\n\thost: string | null;\n\tport: number | null;\n\tdatabase: string | null;\n\ttls: DatabaseTls | null;\n\twritable: boolean;\n\tstatus: string;\n\tcreatedAt: string;\n\t/** The agents whose configuration names this database. */\n\tusedBy: DatabaseUsedBy[];\n}\n\n/** An agent whose configuration names a database: in its latest published\n * version, in its draft, or in both. */\nexport interface DatabaseUsedBy {\n\t/** The agent's id: the same value as `Agent.id`, so compare this one. */\n\tid: string;\n\t/** AgentNava's internal handle for the same agent (`agt_...`), not `Agent.id`. */\n\tagentId: string;\n\t/** The agent's display name. */\n\tname: string;\n\t/** Named in the agent's latest published version, so its conversations can\n\t * query the database now. */\n\tpublished: boolean;\n\t/** Named in the configuration being edited: the draft when there is one,\n\t * else the published version itself. */\n\tdraft: boolean;\n}\n\n/** One table or view in a database. */\nexport interface DatabaseTable {\n\tschema: string;\n\tname: string;\n\tkind: 'table' | 'view';\n}\n\n/** One column of a table. */\nexport interface DatabaseColumn {\n\tname: string;\n\tdataType: string;\n\tnullable: boolean;\n\tisPrimaryKey: boolean;\n}\n\n/** What `ws.databases.test()` reports. A refused login is an answer, not an\n * exception, because it is the answer the call exists to get. */\nexport type DatabaseTestResult =\n\t| { ok: true; engine: DatabaseEngine; tableCount: number; tables: DatabaseTable[] }\n\t| { ok: false; error: { code: string; message: string } };\n\n/**\n * How an agent's website chat looks (the share link, and the chat the embed\n * script opens on a website). Every setting is optional; one left out keeps the\n * default. Part of the agent's configuration, so a change is published with a\n * version like any other field.\n */\nexport interface WebsiteChatAppearance {\n\t/** An image id from `agent.websiteChat.uploadLogo()`, shown in a circle in\n\t * the chat's header. Without one, the name's first letter. */\n\tlogo?: string;\n\t/** The name the chat shows, up to 40 characters. Without one, the agent's name. */\n\ttitle?: string;\n\ttheme?: 'light' | 'dark';\n\t/** One colour, written like `#B4532A`: the avatar, the visitor's messages,\n\t * the send button, chips, prices on cards, and the round button. Where it\n\t * is too light to read as text, words use a darker shade of it. */\n\taccent?: string;\n\t/** `clean` is the default. */\n\tfont?: 'clean' | 'friendly' | 'classic' | 'elegant';\n\t/** Whether the embed script opens the chat when a page loads, on screens\n\t * wider than a phone. New agents start `open`; absent means closed. */\n\topens?: 'open' | 'closed';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4DAA4D;AAkB5D;;;mCAGmC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC","sourcesContent":["// The shapes this SDK hands back. Transcribed from design/sdk-design.md's own\n// Types section so the reference and the code cannot drift.\n\n// Type-only: erased from the emitted JavaScript, so these add no runtime cycle\n// with the modules that import their own shapes from here.\nimport type { AppId } from './apps.generated.ts';\nimport type { Connection } from './connection.ts';\n\n/** The quality of model an agent's turns run on, and what each turn costs.\n *\n * `standard` is the default: the fastest model the platform runs. `lite` is\n * the lowest price. `premium` costs the same as `standard` and thinks harder,\n * answering more slowly. `best` is the strongest model.\n *\n * Renamed in 0.49.0: the grade that was `fast` is now `standard`, and the one\n * that was `standard` is now `lite`. The platform still accepts `fast` from\n * older code and treats it as `standard`. */\nexport type Grade = (typeof GRADE_NAMES)[number];\n\n/** Every grade, as a list a reply can be checked against. This SDK is\n * published and cannot import the platform's private price list, so it keeps\n * its own copy of the NAMES; a test in the platform's monorepo fails the\n * moment the two lists differ. */\nexport const GRADE_NAMES = ['lite', 'standard', 'premium', 'best'] as const;\nexport type Filesystem = 'drive' | 'none';\n\n/** Where a SECRET is supplied.\n *\n * 'fixed' is set once on the agent and used by every conversation. 'conversation'\n * is asked for when a conversation starts, so each user brings their own. The\n * two DO NOT substitute for each other: a value set on the agent does not\n * satisfy a declaration scoped 'conversation'.\n *\n * Connections stopped using this in 0.44. A connection says WHOSE ACCOUNT it\n * uses instead: the agent creator's (`account`) or each end user's own\n * (`endUser: true`). See `AgentConnection`. */\nexport type Scope = 'fixed' | 'conversation';\n\nexport interface WorkspaceInfo {\n\tid: string;\n\tname: string;\n\tcredits: number;\n\tcreatedAt: string;\n}\n\n/** One procedure the agent follows when its `when` matches what is in front of\n * it. `when` is one line and is not optional: it is what the agent reads to\n * decide the workflow applies, so a vague one makes a good workflow invisible. */\nexport interface Workflow {\n\tname: string;\n\twhen: string;\n\tcontent: string;\n}\n\n// `SessionMode` is deliberately NOT exposed.\n//\n// The API has one ('per-user' | 'per-call') and 'per-user' makes the server\n// resume a person's most recent conversation. That is the behaviour `start`\n// refuses to have: a verb that sometimes returns something you already had, and\n// which has to guess which one the moment a person has two.\n//\n// Its other effect, fanning a scheduled firing out across the people who have\n// conversations with an agent, is real and worth exposing one day. It should\n// arrive under a name that says THAT, not under a mode that also silently\n// changes what `start` returns.\n\nexport type Trigger =\n\t| { kind: 'chat' }\n\t| ({ kind: 'schedule'; enabled?: boolean; cron: string; timezone?: string; message: string } & TriggerTarget)\n\t| { kind: 'interval'; seconds: number; maxRuns?: number; message: string }\n\t| ({\n\t\t\tkind: 'webhook';\n\t\t\tmessage?: string;\n\t\t\t/**\n\t\t\t * Where your system POSTs, set by the platform. Read it from the agent\n\t\t\t * that `setTriggers()` returns: `agent.data?.triggers`. Anything you\n\t\t\t * send here is ignored, so passing back a list you read is safe and\n\t\t\t * keeps the same URL. One webhook per agent; `rotateWebhookUrl()`\n\t\t\t * replaces the URL.\n\t\t\t */\n\t\t\turl?: string;\n\t\t\t/**\n\t\t\t * Check WHO sent each delivery, beyond knowing the URL. See\n\t\t\t * WebhookVerify for the schemes and an example. Leave it out to keep\n\t\t\t * what the webhook has. The secret is stored encrypted and never read\n\t\t\t * back: a read says `secretSet: true` instead.\n\t\t\t */\n\t\t\tverify?: WebhookVerify;\n\t } & TriggerTarget);\n\n/**\n * How a webhook checks its sender. Platforms that send webhooks sign every\n * delivery with a secret they show you when you add the URL there; give it\n * here, and a delivery whose signature does not match is refused (401) and\n * never runs the agent.\n *\n * ```ts\n * { kind: 'webhook', verify: { kind: 'stripe', secret: 'whsec_...' } }\n * { kind: 'webhook', verify: { kind: 'header', header: 'X-Webhook-Secret', secret: '...' } }\n * ```\n *\n * The schemes: `stripe`, `github`, `shopify`, `slack` and\n * `standard` (the Standard Webhooks spec) check that platform's signature;\n * `header` checks a header your sender adds (Zapier, Make, n8n, your own code\n * can all add one); `none` relies on the URL alone.\n */\nexport type WebhookVerify =\n\t| { kind: 'none' }\n\t| { kind: 'stripe' | 'github' | 'shopify' | 'slack' | 'standard'; secret?: string; secretSet?: boolean }\n\t| { kind: 'header'; header: string; secret?: string; secretSet?: boolean };\n\n/** One delivery a webhook received, newest first from `agent.webhookDeliveries()`. */\nexport interface WebhookDelivery {\n\tid: string;\n\treceivedAt: string;\n\t/** `pending`: checked and starting. `repeat`: the sender retried a delivery\n\t * already accepted; the agent did not run again. */\n\toutcome: 'pending' | 'accepted' | 'refused' | 'repeat' | 'test';\n\t/** Why it was refused. */\n\treason?: string;\n\t/** The sender's own id for it, when it gave one. */\n\tdeliveryId?: string;\n\t/** The conversation it ran in. */\n\tconversationId?: string;\n}\n\n/**\n * WHERE a schedule or webhook runs. Name a conversation, or an end user, or\n * neither; never both.\n *\n * ```ts\n * const conversation = await agent.start({ endUserId: 'ops-app' });\n * await agent.setTriggers([\n * { kind: 'chat' },\n * // Every firing lands in THIS conversation: its history, its drive.\n * { kind: 'schedule', cron: '0 15 * * *', message: 'REFRESH', conversationId: conversation.id },\n * ]);\n * ```\n */\nexport type TriggerTarget =\n\t| {\n\t\t\t/**\n\t\t\t * The conversation every firing CONTINUES: it sees that conversation's\n\t\t\t * history and its drive, and its end user comes with it. Each firing\n\t\t\t * also moves the conversation to the agent's latest version, so a fix\n\t\t\t * you publish reaches it.\n\t\t\t *\n\t\t\t * This is the ONLY way a trigger continues one of your conversations.\n\t\t\t * One end user can have many, so naming the end user cannot say which.\n\t\t\t *\n\t\t\t * Must be a conversation of this agent, started for one of your end\n\t\t\t * users (the id `agent.start()` returned). Anything else is refused\n\t\t\t * when you set the trigger. If the conversation is deleted later, the\n\t\t\t * firings fail and say so; none is opened in its place.\n\t\t\t */\n\t\t\tconversationId: string;\n\t\t\tuserId?: undefined;\n\t }\n\t| {\n\t\t\tconversationId?: undefined;\n\t\t\t/**\n\t\t\t * The end user each firing is for, when it names no conversation. Each\n\t\t\t * firing STARTS A NEW CONVERSATION for them, with an empty drive, and it\n\t\t\t * is listed by `agent.conversations({ endUser })`. To keep adding to\n\t\t\t * one conversation instead, name it with `conversationId`.\n\t\t\t *\n\t\t\t * Your id, as in `agent.start({ endUserId })`; the platform's prefixes\n\t\t\t * (`member:`, `visitor:`, `job:`) are refused.\n\t\t\t *\n\t\t\t * Name neither and the trigger keeps one conversation of its own that\n\t\t\t * every firing continues.\n\t\t\t */\n\t\t\tuserId?: string;\n\t };\n\n/**\n * One connection in an agent's setup, as it reads back: a NAME, an APP, and\n * WHOSE ACCOUNT. Exactly one of these two:\n *\n * | the connection says | whose account | the person signs in |\n * |---|---|---|\n * | `account: '<id>'` | the agent creator's: one account in this workspace, from `ws.accounts.connect()` | once, and every conversation uses it |\n * | `endUser: true` | the end user's: each person talking to the agent | once each, remembered for them |\n *\n * A turn uses EXACTLY the account the setup names, and never another one.\n * There is no fallback to some other account of the same app: an account that\n * is not signed in leaves the connection unavailable, and the agent says so.\n *\n * `name` tells two connections of one app apart, such as `work-gmail` and\n * `personal-gmail`. 1 to 64 characters, lowercase letters, digits and dashes,\n * no dash at either end, unique on the agent. Left out when sent, it is the\n * app's id.\n *\n * Part of the agent's CONFIGURATION, so changing a connection publishes a\n * version. The account itself is not versioned: signing in again reaches every\n * agent that names it. To send one, build it with `Connection.creatorAccount()`\n * or `Connection.endUserAccount()`.\n */\nexport type AgentConnection =\n\t| {\n\t\t\tname: string;\n\t\t\t/** The app's id: `App.GMAIL` is `'gmail'`. */\n\t\t\tapp: AppId;\n\t\t\t/** An account id in this workspace whose app is `app`. */\n\t\t\taccount: string;\n\t\t\tendUser?: never;\n\t\t\t/** Which of the app's own tools the agent may use; absent for the app's default. */\n\t\t\ttools?: string[];\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tapp: AppId;\n\t\t\tendUser: true;\n\t\t\taccount?: never;\n\t\t\ttools?: string[];\n\t };\n\n/** What an agent NEEDS, not the stored value. `Secret` is the value. */\nexport interface SecretRequirement {\n\tname: string;\n\tscope: Scope;\n\trequired?: boolean;\n}\n\nexport interface Parameter {\n\tname: string;\n\ttype: 'string' | 'number' | 'date' | 'choice';\n\trequired?: boolean;\n\tdefault?: string;\n\tchoices?: string[];\n}\n\nexport interface McpServer {\n\tname: string;\n\turl: string;\n\ttransport?: 'http' | 'sse';\n\theaders?: Record<string, string>;\n\ttimeoutMs?: number;\n}\n\nexport interface HttpToolParam {\n\ttype: 'string' | 'number' | 'boolean' | 'object' | 'array';\n\tdescription?: string;\n\trequired?: boolean;\n\tchoices?: (string | number | boolean | null)[];\n\tnullable?: boolean;\n\tinteger?: boolean;\n\tproperties?: Record<string, HttpToolParam>;\n\titems?: HttpToolParam;\n\tadditionalProperties?: boolean;\n\t/**\n\t * A regular expression the whole value must match (strings only). Checked\n\t * before the call; a value that does not match is refused, so what a person\n\t * typed cannot change the request it is written into. Patterns that repeat a\n\t * repeating group, like `(a+)+`, are refused when saved.\n\t *\n\t * ```ts\n\t * order_number: { type: 'string', required: true, pattern: '[0-9]{1,10}' }\n\t * ```\n\t */\n\tpattern?: string;\n\t/** The longest value accepted (strings only). 2000 when a pattern is set\n\t * and this is not. */\n\tmaxLength?: number;\n}\n\n/** One check on an HTTP tool's answer: the value at `field` (a dotted path,\n * numbers for list positions) must equal `equals`, which may use\n * `{{params.NAME}}`. */\nexport interface HttpToolMatch {\n\tfield: string;\n\tequals: string;\n\tignoreCase?: boolean;\n}\n\n/** Something the agent may ask the website page to do, such as add to cart.\n * The page carries it out with `window.AgentNava.page.handle(name, fn)`, and\n * what `fn` returns goes back to the agent. Only a website chat has a page; in\n * any other conversation the agent is told it cannot. */\nexport interface PageAction {\n\t/** Lowercase letters, digits and `_`; never one of the agent's HTTP tool names. */\n\tname: string;\n\t/** What it does and when the agent should use it. */\n\tdescription: string;\n\t/** What the agent fills in; the page's handler receives these as its argument. */\n\tparams?: Record<string, HttpToolParam>;\n}\n\nexport interface HttpTool {\n\tname: string;\n\tdescription: string;\n\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\turl: string;\n\theaders?: Record<string, string>;\n\tbody?: string;\n\tparams?: Record<string, HttpToolParam>;\n\tsecrets?: string[];\n\ttimeoutMs?: number;\n\t/**\n\t * Checks on the answer, all of which must pass. If any fails, or the call\n\t * answers with an error or a body that is not JSON, the agent gets only\n\t * `notFound`, never the answer. Use it for \"show an order only when the\n\t * number and the email both match\":\n\t *\n\t * ```ts\n\t * requireMatch: [\n\t * { field: 'data.orders.nodes.0.name', equals: '#{{params.order_number}}' },\n\t * { field: 'data.orders.nodes.0.email', equals: '{{params.email}}', ignoreCase: true },\n\t * ],\n\t * notFound: 'No order matches that number and email.',\n\t * ```\n\t */\n\trequireMatch?: HttpToolMatch[];\n\t/** What the agent gets when a check fails. Default: \"Not found.\" */\n\tnotFound?: string;\n\t/**\n\t * Sign the request in with one of the agent's connections (its `name`)\n\t * instead of a stored key. The connection's provider adds a current\n\t * credential and keeps it fresh, so the credential never leaves it. The\n\t * address must start with `https://` and a written-out host, and that host\n\t * must be the connected account's own API; leave out `Authorization`.\n\t *\n\t * ```ts\n\t * { name: 'look_up_order', method: 'POST', signInWith: 'shopify',\n\t * url: 'https://my-store.myshopify.com/admin/api/2026-04/graphql.json', ... }\n\t * ```\n\t */\n\tsignInWith?: string;\n\t/**\n\t * Values the website page supplies for this visitor, used as\n\t * `{{pageEncoded.NAME}}` in the address, `{{pageJson.NAME}}` in a JSON body,\n\t * or `{{page.NAME}}` for a plain token (letters, digits, `- _ . ~` only).\n\t * On the page, the chat script's public call sets them:\n\t * `window.AgentNava.page.set('cart_id', value)`. They are kept per\n\t * conversation and filled in at call time; the model sees one only if the\n\t * API's answer repeats it, and logs redact them. Names: lowercase letters, digits, `_`.\n\t */\n\tpageValues?: string[];\n}\n\n/**\n * Guardrails: what the platform enforces on an agent, even when someone tries to\n * talk the agent out of it. An agent's `instructions` are what it TRIES to do;\n * its guardrails are checked by the platform before the agent reads a message,\n * so a person cannot argue it past them.\n *\n * ```ts\n * await agent.update({\n * guardrails: {\n * stayOnTopic: true,\n * rules: ['Never offer discounts or change prices.'],\n * },\n * });\n * ```\n *\n * A message that breaks one is declined before the agent reads it, and the agent\n * replies politely in its own voice instead; an action that breaks one does not\n * happen; a reply that breaks one is taken back and answered again. The turn's\n * stream says which rule fired (`{ type: 'guardrail' }`).\n *\n * Part of the CONFIGURATION, like `connections`, so changing it publishes a\n * version, and a conversation already in progress keeps the version it began on.\n */\nexport interface Guardrails {\n\t/** Decline anything outside this agent's job, judged from its own\n\t * instructions: other work (code, homework, poems), \"ignore your\n\t * instructions\", requests for its prompt or files, and \"I'm the owner\"\n\t * claims made to get special treatment. ON unless set to `false`. */\n\tstayOnTopic?: boolean;\n\t/** Your own rules, one plain-English sentence each (at most 20, each under\n\t * 500 characters). Each is checked on the message, on every action the agent\n\t * tries, and on its reply. A break is declined, blocked or taken back, and the\n\t * stream names the rule. */\n\trules?: string[];\n\t/** Check each message before the agent reads it, so one that breaks a\n\t * guardrail never reaches the agent and nothing it asked for is done. Costs\n\t * about 0.2 s per message. ON unless set to `false`: off, the agent answers\n\t * at once, and its replies and actions are still checked. */\n\tcheckMessagesFirst?: boolean;\n}\n\nexport interface AgentData {\n\tid: string;\n\tname: string;\n\tinstructions: string;\n\tgreeting?: string;\n\t/** Always present, with the defaults filled in: what is enforced now. */\n\tguardrails: { stayOnTopic: boolean; rules: string[]; checkMessagesFirst: boolean };\n\t/** How its website chat looks. Absent: the default look, starting closed. */\n\tappearance?: WebsiteChatAppearance;\n\tgrade: Grade;\n\tfilesystem: Filesystem;\n\ttools: string[];\n\tworkflows: Workflow[];\n\t/** The apps it uses, each saying whose account. See `AgentConnection`. */\n\tconnections: AgentConnection[];\n\tsecrets: SecretRequirement[];\n\tparameters: Parameter[];\n\ttriggers: Trigger[];\n\tmcpServers: McpServer[];\n\thttpTools: HttpTool[];\n\t/** Always a list, empty when the agent has none. */\n\tpageActions: PageAction[];\n\t/** Workspace knowledge bases this agent reads, by key. Always present, empty\n\t * when none are attached, so a caller never has to distinguish \"none\" from\n\t * \"an older server that did not send the field\". */\n\tknowledgeBases: string[];\n\t/** Workspace databases this agent may query, by key. Always present, like\n\t * `knowledgeBases`. */\n\tdatabases: string[];\n\tversion: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Where it is live, as the portal shows it. The API works it out by the\n\t * same rule it runs the agent by, so `channels.api === 'on'` is exactly\n\t * \"a turn will be taken\". Read-only: nothing sets it. Sent by `agent.get()`\n\t * and `ws.agents.list()`; absent from what create and update return, so\n\t * call `get()` for it. */\n\treadonly status?: AgentStatus;\n}\n\n/** Who can chat with an agent's website chat. 'restricted' (the default):\n * members of your workspace signed in to AgentNava, and visitors on the\n * allowed websites. 'anyone': anyone with the link, on any website. */\nexport type WebsiteChatAccess = 'restricted' | 'anyone';\n\n/** What `agent.websiteChat.get()` gives back. */\nexport interface WebsiteChat {\n\t/** Who can chat. */\n\treadonly access: WebsiteChatAccess;\n\t/** The hosted chat page, the share link. Share it, or open it in an iframe. */\n\treadonly chatUrl: string;\n\t/** The id the embed script's `data-agent-id` takes. */\n\treadonly embedAgentId: string;\n}\n\n/** Where an agent is live. See `AgentData.status`. */\nexport interface AgentStatus {\n\t/** True when any channel is on. */\n\treadonly live: boolean;\n\t/** Paused by its owner: nothing runs it until it is resumed. */\n\treadonly paused: boolean;\n\t/** Archived: nothing runs it again. */\n\treadonly archived: boolean;\n\treadonly channels: {\n\t\t/** 'on' when the API takes new turns for it. */\n\t\treadonly api: 'on' | 'off';\n\t\t/** 'on' when its website chat page answers visitors. 'unavailable' when it\n\t\t * needs what each user brings (`eachUserBrings`), which a visitor cannot. */\n\t\treadonly websiteChat: 'on' | 'off' | 'unavailable';\n\t};\n\t/** Required accounts and secrets of its own that are not set up yet, on the\n\t * version a new conversation runs. It still runs: the tools that use them\n\t * fail until they are set up. Empty when nothing is missing. */\n\treadonly needs: readonly { kind: 'connection' | 'secret'; name: string }[];\n\t/** The accounts and secrets each user supplies for themselves. */\n\treadonly eachUserBrings: readonly { kind: 'connection' | 'secret'; name: string }[];\n}\n\n/**\n * One of an app's own ready-made tools, as `ws.apps.tools(app)` lists it: what\n * a connection's `tools` chooses from.\n */\nexport interface AppTool {\n\t/** What a connection's `tools` names: `SLACK_SEND_MESSAGE`. */\n\tid: string;\n\t/** The tool service's name for it: \"Send message\". */\n\tname: string;\n\t/** Its description's first sentence. */\n\tsummary: string;\n\t/** It removes something (a message, a file, a record). */\n\tdeletes?: true;\n}\n\n/**\n * One of an agent's connections as it stands right now: the account it names,\n * and whether that account works. What `agent.connections.list()` returns.\n *\n * DECLARED IS NOT CONNECTED, and this is the read that tells them apart. A\n * connection can name an account nobody has finished signing in to, or one that\n * was disconnected since; that is the state a setup checklist has to show, and\n * without this the only way to find it is to start a conversation and watch\n * the agent fail.\n *\n * Reshaped in 0.44: it used to be keyed by `provider`, with `declared`,\n * `required`, `scope` and `suppliedBy`. A connection is now keyed by its\n * `name`, and it says whose account it uses instead of where one might come\n * from.\n */\nexport interface ConnectionStatus {\n\tname: string;\n\tapp: AppId;\n\t/** The agent creator's account the connection names, read fresh. Absent on\n\t * an end user's connection, and on one whose account is gone. */\n\taccount?: AccountData;\n\t/** True when each person talking to the agent signs in with their own. */\n\tendUser?: true;\n\t/** Which of the app's own tools the agent may use; absent for the app's default. */\n\ttools?: string[];\n\t/** Whether the connection works now, as the API reports it. For an agent\n\t * creator's account it follows that account's status. */\n\tstatus: string;\n\t/** Only in the agent's unpublished draft, so no conversation uses it yet. */\n\tinDraft: boolean;\n\t/** Removed in the agent's unpublished draft, and still used until the draft\n\t * is published. */\n\tremovedInDraft: boolean;\n}\n\n/** Where one account's sign-in stands.\n *\n * 'pending' made, and nobody has finished signing in yet\n * 'connected' signed in and working\n * 'needs_sign_in' it worked, and the app now wants the person to sign in again\n * 'error' the app refused it for another reason\n */\nexport type AccountStatus = 'pending' | 'connected' | 'needs_sign_in' | 'error';\n\n/** An agent whose setup names an account, and the connection that names it.\n * Counted from the agent's latest published version and its draft, never\n * from older versions. */\nexport interface UsedBy {\n\t/** The agent's id: the same value as `Agent.id`, so compare this one. */\n\tid: string;\n\t/** AgentNava's internal handle for the same agent (`agt_...`), not `Agent.id`. */\n\tagentId: string;\n\tagentName: string;\n\tconnectionName: string;\n\t/** Named in the agent's unpublished draft. */\n\tinDraft: boolean;\n\t/** Named in the agent's latest published version. */\n\tpublished: boolean;\n}\n\n/**\n * One saved sign-in to one app.\n *\n * TWO OWNERS, and the difference is who signs in:\n *\n * | `owner` | whose | a connection uses it as |\n * |---|---|---|\n * | `'workspace'` | the agent creator's, signed in once, usable by any agent | `Connection.creatorAccount(app, account)` |\n * | `'end-user'` | one of YOUR end users', remembered for that person | `Connection.endUserAccount(app)`, in that person's conversations |\n *\n * Both owners are read and changed through the same routes and the same\n * `Account` handle; `owner` says which this is.\n *\n * Nobody handles a token: the person signs in on the app's own page, and this\n * record says who they signed in as, never how.\n */\nexport interface AccountData {\n\tid: string;\n\t/** The app's id: `App.GMAIL` is `'gmail'`. */\n\tapp: AppId;\n\t/** Who it is signed in as: the email or username the app reports. Null until\n\t * somebody has finished signing in. */\n\tlabel: string | null;\n\t/** Your own name for it, such as `'Support inbox'`. Null when none was given. */\n\tnickname: string | null;\n\tstatus: AccountStatus;\n\t/** True while a reconnect waits for the person to sign in again. The\n\t * account keeps working meanwhile, so `status` can still say\n\t * `'connected'`; `waitUntilConnected()` waits for this to clear. */\n\treconnecting: boolean;\n\towner: 'workspace' | 'end-user';\n\t/** The end user it belongs to, when `owner` is `'end-user'`. An id from YOUR\n\t * database, never a workspace member's. */\n\tendUserId?: string;\n\tconnectedAt: string | null;\n\tlastCheckedAt: string | null;\n\t/** The agents whose setup names this account. Empty for an end user's\n\t * account, which a setup never names by id. */\n\tusedBy: UsedBy[];\n}\n\n/** An end user's account a conversation still needs, with the link that\n * person signs in at. From `conversation.accountsNeeded()`. */\nexport interface AccountNeeded {\n\t/** The connection's name on the agent. */\n\tname: string;\n\tapp: AppId;\n\t/** Send the person here. They sign in once, and every later conversation\n\t * of theirs has it. */\n\turl: string;\n}\n\n/** Something a conversation is still missing before it can work. */\nexport interface Requirement {\n\tkind: 'secret' | 'connection';\n\tname: string;\n\trequired: boolean;\n}\n\nexport interface AgentConversationData {\n\tid: string;\n\tagentId: string;\n\t/** The number of the agent version this conversation runs, as `agent.version`\n\t * numbers them. Fixed at start, except that a schedule or webhook naming the\n\t * conversation moves it to the latest version at each firing. */\n\tversion: number;\n\tstartedAt: string;\n\ttitle?: string;\n\t/** True when nothing REQUIRED is outstanding. An optional gap leaves this\n\t * true, because the conversation genuinely does work without it. */\n\tready: boolean;\n\trequires: Requirement[];\n}\n\nexport interface ProjectConversationData {\n\tid: string;\n\tprojectId: string;\n\tstartedAt: string;\n\ttitle?: string;\n\tready: boolean;\n\trequires: Requirement[];\n}\n\n/** An AGENT on a project, not a person.\n *\n * Called `ProjectAgent` and not `Member`, which is what it was. `Member` is\n * the word this product uses for a HUMAN on the account, so a public type of\n * that name holding an `agentId` was the same trap as `userId` meaning two\n * populations: `import { Member }` handed you the agent one, and the human one\n * had to carry a prefix to get out of its way.\n *\n * The people are `WorkspaceMember`, from `ws.members()`. Nothing here is a\n * person. */\nexport interface ProjectAgent {\n\tagentId: string;\n\tname: string;\n\taddedAt: string;\n}\n\nexport interface ProjectData {\n\tid: string;\n\tname: string;\n\tgoal: string | null;\n\tmanagerInstructions: string | null;\n\tgrade: Grade;\n\tstatus: 'active' | 'archived';\n\tagents: ProjectAgent[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface Step {\n\tid: string;\n\tlabel: string;\n\tkind: 'read' | 'write' | 'edit' | 'search' | 'shell' | 'web' | 'data' | 'task' | 'plan' | 'other';\n\tstatus: 'active' | 'done' | 'error';\n}\n\nexport type TurnEvent =\n\t/** First, before anything else: the id the API gave this turn. */\n\t| { type: 'start'; turnId: string }\n\t/** Carries the WHOLE step list every time, not a change to it. Replace what\n\t * you are showing rather than merging; that is what makes reconnecting\n\t * safe. Sent after each tool event that changes the list, with the steps\n\t * and words the portal shows. */\n\t| { type: 'progress'; steps: Step[] }\n\t/** `name` is the tool's identifier, for code. `label` is what a person sees,\n\t * the portal's words (\"Searching the web: <query>\"). */\n\t| { type: 'tool'; name: string; state: 'start' | 'end'; label?: string; ok?: boolean }\n\t/** A fragment, not a line. Append; do not assemble. */\n\t| { type: 'text'; text: string }\n\t/** A file the agent wrote in the conversation's drive. Pass `path` to\n\t * conversation.readFile(). Sent once per file per turn. */\n\t| { type: 'file'; path: string }\n\t/** A widget the agent is drawing inside its reply, sent whole each time it\n\t * grows: replace the one with the same `surfaceId`. Only on a conversation\n\t * started with `widgets: true`. */\n\t| { type: 'widget'; widget: Widget }\n\t/** `widgets` is the reply's final widget list, present when it has any:\n\t * what to keep, whatever arrived live. */\n\t/** One of the agent's guardrails fired. `rule` is the one, as you wrote it,\n\t * or 'Stay on topic'.\n\t * - `message`: the person's message broke it and was declined. The agent\n\t * never read it; the words that follow are its polite refusal.\n\t * - `reply`: the agent's reply broke it and was taken back (a `reset` came\n\t * first); the words that follow are its answer within the rule.\n\t * - `tool`: an action the agent tried (`tool`) broke one of your rules and\n\t * did not happen; the agent explains in the words that follow. Which rule\n\t * is not reported for this stage. */\n\t| { type: 'guardrail'; stage: 'message'; rule: string; action: 'declined' }\n\t| { type: 'guardrail'; stage: 'reply'; rule: string; action: 'replaced' }\n\t| { type: 'guardrail'; stage: 'tool'; tool: string; action: 'blocked' }\n\t/** Replace the words you have shown for this reply with `text`, often empty:\n\t * earlier words were withdrawn (a guardrail) or a step was retried. Clear the\n\t * reply's widgets too; any that still belong are sent again. */\n\t| { type: 'reset'; text: string }\n\t/** Sent at the start of a turn, once per name: a secret the agent declared\n\t * for each conversation, and one of its tools uses, has no usable value\n\t * here. `expired`: the value you pushed has run out. `missing`: none was\n\t * given, or the stored secret attached under that name was deleted or no\n\t * longer belongs to this person. The turn still runs; the tool says it\n\t * cannot sign in. Push a fresh value (`ask(text, { secrets })`) and ask\n\t * again. */\n\t| { type: 'credential_needed'; name: string; reason: 'missing' | 'expired' }\n\t| { type: 'done'; reply: string; widgets?: Widget[] }\n\t| { type: 'error'; message: string; retryable: boolean };\n\n/**\n * One part of a widget, in Google's open A2UI v0.9 format with AgentNava's own\n * set of parts: an id, which kind of\n * part it is (`Column`, `Row`, `Card`, `Text`, `Stat`, `KeyValue`, `Table`,\n * `Chart`, `Image`, `List`, `Note`, `Badge`, `Link`, `Button`, `Suggestions`,\n * `Divider`), and that kind's props. A container lists its children by id.\n */\nexport interface WidgetPart {\n\tid: string;\n\tcomponent: string;\n\t[prop: string]: unknown;\n}\n\n/**\n * A card, table or chart the agent drew inside a reply. Draw it with `WidgetView`\n * from `@cerebro-labs/agentnava-sdk/react`, or your own components starting\n * from the part with id `root`.\n * `at` is where it sits in the reply's text, as a character count, so it goes\n * between the right sentences.\n */\nexport interface Widget {\n\tsurfaceId: string;\n\tat: number;\n\tcomponents: WidgetPart[];\n\t/** Every part arrived. False only while it streams, or on a reply cut short. */\n\tclosed: boolean;\n}\n\nexport interface Message {\n\trole: 'user' | 'assistant';\n\tcontent: string;\n\tat: string;\n\t/** The widgets in an assistant reply, when it has any. */\n\twidgets?: Widget[];\n}\n\n/** An image goes to the model as an image. Anything else is written into the\n * conversation's drive before the turn starts, so the agent can parse it,\n * compute over it, and still have it next turn. */\nexport interface Attachment {\n\tkind: 'image' | 'file';\n\tname?: string;\n\tmimeType: string;\n\t/** base64, without a data: prefix. */\n\tdata: string;\n}\n\n/** A knowledge base: a named folder of files at WORKSPACE scope that an agent\n * configuration attaches by key. */\nexport interface KnowledgeBaseData {\n\t/** Workspace-unique. This is what an agent configuration stores, and it is\n\t * not editable, because renaming it would move every attachment silently. */\n\tkey: string;\n\tname: string;\n\tdescription?: string;\n\t/** Counted when read, so it never disagrees with the files it counts. */\n\tfileCount: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/** One file in a knowledge base. PATH, not a flat name: a base is a folder, and\n * the session mount reproduces the shape verbatim. */\n/**\n * Whether an agent can read a file in a knowledge base.\n *\n * Text and markdown are readable as they stand. A PDF, a scan or a spreadsheet\n * has to be turned into text first, which happens when the file is uploaded\n * rather than when a question is asked, so an agent never waits on it.\n *\n * 'readable' an agent can read this now\n * 'processing' being prepared, check back shortly\n * 'unreadable' cannot be read, and `reason` says why\n */\nexport type KnowledgeFileStatus = 'readable' | 'processing' | 'unreadable';\n\nexport interface KnowledgeFileEntry {\n\tpath: string;\n\tmimeType: string;\n\tsize: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Whether an agent can read this file. */\n\tstatus: KnowledgeFileStatus;\n\t/** Why it cannot be read, as a sentence you could show someone.\n\t *\n\t * The same text reaches the agent in place of the file, so a developer\n\t * reading this and a model reading the base get one explanation rather than\n\t * two that can drift apart. Absent unless `status` is 'unreadable'. */\n\treason?: string;\n}\n\nexport interface FileEntry {\n\tpath: string;\n\tkind: 'file' | 'directory';\n\tmimeType: string;\n\tsize: number;\n\tmodifiedAt: string;\n}\n\n/** Fields accepted when creating or updating an agent. Everything is optional on\n * an update: what you do not send is inherited from the current version, which\n * is the whole reason updating is safe. */\nexport interface AgentFields {\n\tid?: string;\n\tname?: string;\n\tinstructions?: string;\n\tgreeting?: string;\n\t/** What the platform enforces on every incoming message. See `Guardrails`. */\n\tguardrails?: Guardrails;\n\t/**\n\t * How the agent's website chat looks, on the share link and through the\n\t * embed script. Merged by setting: `{ accent: '#B4532A' }` changes the colour\n\t * and keeps the rest; `null` clears one setting, and `appearance: null` goes\n\t * back to the default look. See `WebsiteChatAppearance`.\n\t */\n\tappearance?: { [K in keyof WebsiteChatAppearance]?: WebsiteChatAppearance[K] | null } | null;\n\tgrade?: Grade;\n\tfilesystem?: Filesystem;\n\t/**\n\t * Knowledge bases this agent reads, by workspace-unique key.\n\t *\n\t * Mounted READ-ONLY at `/knowledge/<key>/` when a session starts, so the\n\t * agent finds things with `ls`, `grep` and `cat` rather than a retrieval API.\n\t *\n\t * Which bases an agent reads is part of its CONFIGURATION, so changing this\n\t * publishes a version you can diff and roll back. The CONTENTS of a base are\n\t * not versioned: correcting a file changes what every attached agent sees on\n\t * its next turn, which is the same by-reference promise `agent.knowledge`\n\t * already makes.\n\t *\n\t * A key that names no base is refused when the configuration is saved, and\n\t * deleting a base is refused while any agent attaches it, so an attachment\n\t * that was valid stays valid.\n\t */\n\tknowledgeBases?: string[];\n\t/**\n\t * Workspace databases this agent may query, by key.\n\t *\n\t * Register the database first with `ws.databases.create()`, which logs in\n\t * and gives it the key; then name the key here. Naming it is the grant: a\n\t * database answers only the agents whose configuration names it, and the\n\t * agent's prompt lists them so it knows what to query.\n\t *\n\t * Part of the CONFIGURATION, so changing it publishes a version. A key that\n\t * names no database is refused when the configuration is saved, and\n\t * removing a database is refused while any agent names it.\n\t */\n\tdatabases?: string[];\n\ttools?: string[];\n\t/**\n\t * \"Answer with widgets\": on unless `false`. When on, the agent draws cards,\n\t * tables and charts inside its answers, on a conversation started with\n\t * `widgets: true`. Set `false` for an agent that should answer in text only.\n\t */\n\twidgets?: boolean;\n\tworkflows?: Workflow[];\n\t/**\n\t * The apps this agent uses, each a NAMED connection that says whose account\n\t * it uses: the agent creator's account, or each end user's own. See\n\t * `Connection` and `AgentConnection`.\n\t *\n\t * ```ts\n\t * connections: [\n\t * Connection.creatorAccount(App.GMAIL, work, { name: 'work-gmail' }),\n\t * Connection.creatorAccount(App.GMAIL, personal, { name: 'personal-gmail' }),\n\t * Connection.endUserAccount(App.GOOGLE_CALENDAR),\n\t * ]\n\t * ```\n\t *\n\t * The builders make plain objects, `{ app, account: '<id>' }` and\n\t * `{ app, endUser: true }`, and those objects are accepted as they are.\n\t * `App.GMAIL` is the string `'gmail'`, so a plain app id works too.\n\t *\n\t * Part of the CONFIGURATION, like `databases`, so changing it publishes a\n\t * version. An unknown account id, an account of a different app, a repeated\n\t * name or a name of the wrong shape is refused when the configuration is\n\t * saved, naming the problem.\n\t */\n\tconnections?: Connection[];\n\tsecrets?: SecretRequirement[];\n\tparameters?: Parameter[];\n\ttriggers?: Trigger[];\n\tmcpServers?: McpServer[];\n\thttpTools?: HttpTool[];\n\t/** Things the agent may ask the website page to do (see PageAction). */\n\tpageActions?: PageAction[];\n}\n\nexport interface ProjectFields {\n\tname?: string;\n\tgoal?: string;\n\tmanagerInstructions?: string;\n\tgrade?: Grade;\n\tagents?: string[];\n}\n\n/** Secret VALUES supplied to an agent (`agent.attach`) or to one conversation\n * (`conversation.attach`): the secrets its agent declared.\n *\n * Accounts are no longer supplied this way (0.44). An agent's setup names the\n * account each connection uses, so there is nothing left to attach. */\nexport interface Bindings {\n\tsecrets?: Record<string, string>;\n}\n\n/** One markdown file read off disk: a workflow or a subagent.\n *\n * `when` is OPTIONAL here and required at publish. A file on disk has no `when`\n * until someone writes one, and refusing to read it would be the wrong place to\n * say so; the API says it at publish, with a message naming the file. */\nexport interface SpecFile {\n\tname: string;\n\tcontent: string;\n\twhen?: string;\n}\n\n/** What a loaded agent directory produces: the fields `ws.agents.create()` takes,\n * plus the id the caller chose and the few legacy names the loader still reads\n * off an existing directory. */\nexport interface SpecInput extends Omit<AgentFields, 'workflows'> {\n\tkey: string;\n\tworkflows?: SpecFile[];\n\tsubagents?: SpecFile[];\n\tsandbox?: Filesystem;\n\trole?: string;\n\t/** Retired in favour of `tools: ['web_search']`, still read off an existing\n\t * agent directory so one written before the rename still loads. */\n\twebSearch?: boolean;\n}\n\n/** A PERSON with access to this workspace: your colleague, on a seat.\n *\n * NOT one of your end users, and the difference is the sharpest naming trap in\n * this SDK. A workspace member signs in here, we issued their id, and we\n * authenticate it. A `EndUser` is the person YOUR application serves, never\n * signs in here, and carries an id from YOUR database that we store verbatim\n * and never check.\n *\n * `userId` below is therefore a PLATFORM id and is not interchangeable with\n * `agent.start({ endUserId })`. Both fields were once spelled `userId`, which\n * made passing one where the other belonged a call that could not fail: a\n * end-user id is never validated against anything, so it silently labelled a\n * conversation with a colleague's internal id. The two names now differ.\n *\n * Named WorkspaceMember rather than Member because a public `Member` type used\n * to mean an AGENT attached to a project. That one is now `ProjectAgent`, so\n * the prefix here is no longer load-bearing; it stays because it says which of\n * the two populations this is at every call site, and that is worth four\n * characters.\n *\n * Read-only, like everything else on the account surface: the SDK can see who\n * is on the account and what they may do, and cannot add, remove or re-role\n * anyone. Those are decisions a person makes while signed in, not something a\n * key should be able to do on their behalf. */\nexport interface WorkspaceMember {\n\t/** A PLATFORM user id (`usr_...`), issued by us. Never pass this to\n\t * `agent.start({ endUserId })` or `ws.endUser()`. */\n\tuserId: string;\n\temail: string;\n\tname: string | null;\n\t/** 'owner' is the account's creator; 'admin' can manage it; 'member' cannot. */\n\trole: 'owner' | 'admin' | 'member';\n\t/** Unix seconds. */\n\tjoinedAt: number;\n}\n\n/** What is left to spend.\n *\n * `credits` is the balance in credits, where one credit is one US dollar. The\n * turn counts are the same balance expressed in the unit people actually\n * reason with, because \"12.5 credits\" answers nothing on its own. */\nexport interface Credits {\n\tcredits: number;\n\tstandardTurnsRemaining: number;\n\tpremiumTurnsRemaining: number;\n}\n\n/** The seat plan this workspace is on.\n *\n * Seats are a SEPARATE purchase from credits: a plan says how many people may\n * share the account, credits pay for the work their agents do. Being on the\n * free plan does not make turns free. */\nexport interface SeatPlan {\n\tkey: string;\n\tlabel: string;\n\t/** People allowed. `null` means negotiated, which is NOT unlimited and\n\t * should never be shown to anyone as a number. */\n\tseats: number | null;\n\t/** Monthly price in US cents. `null` means there is no published price and\n\t * the answer is a conversation, which is the opposite fact from 0 (free). */\n\tusdCentsPerMonth: number | null;\n}\n\n/** A stored secret, WITHOUT its value.\n *\n * The value is never returned by any read. It is written once, encrypted at\n * rest, and substituted into an HTTP tool's url, headers or body server-side at\n * call time, so it is never part of anything the model can see or repeat. To\n * change one, write it again; to be sure of one, replace it. */\nexport interface SecretMeta {\n\tid: string;\n\tname: string;\n\tdescription?: string | null;\n\t/** The agent this secret is scoped to, or null when the whole workspace\n\t * reads it. An agent-scoped secret of the same name wins. */\n\tagentId?: string | null;\n\t/** The end user this secret belongs to, or null when it is the workspace's.\n\t * One of YOUR user ids, stored verbatim: we never resolve or authenticate\n\t * it. A secret with one can only be attached to a conversation launched for\n\t * that same person. */\n\tendUserId?: string | null;\n\t/** The only hosts a tool may send this key to. Empty until the first tool\n\t * saved with it pins its own host; add one on purpose with\n\t * `secret.setAllowedHosts([...])`. */\n\tallowedHosts?: string[];\n\t/** Who created it and who last changed its value or hosts: a member's id,\n\t * `api_key:<id>`, or `system`. A tool save that pins its hosts is not a\n\t * change to it. Null on a secret from before these were kept. */\n\tcreatedBy?: string | null;\n\tupdatedBy?: string | null;\n\t/** The same, in words: a member's first name or \"API key <name>\"; null\n\t * for our own system or someone no longer in the workspace. */\n\tcreatedByName?: string | null;\n\tupdatedByName?: string | null;\n\tcreatedAt?: string;\n\tupdatedAt?: string;\n\tlastUsedAt?: string | null;\n}\n\n/** A SQL engine AgentNava can query. */\nexport type DatabaseEngine = 'postgres' | 'mysql' | 'sqlserver';\n\n/** How the connection to a database is encrypted. `verify` (the default)\n * encrypts and always checks the server's certificate: against public and\n * cloud CAs and the host name, or, for a database with its own home-made CA,\n * against the CA AgentNava trusted the first time it connected. `disable` is\n * for a server with no SSL at all. */\nexport type DatabaseTls = 'verify' | 'disable';\n\n/**\n * How to log in to a database: a connection string, OR the same login as\n * separate fields. Never both; a request with both is refused.\n *\n * Read-only unless `writable: true`, which no SQL the agent sends can override.\n */\nexport type DatabaseLogin =\n\t| {\n\t\t\t/** `postgres://`, `postgresql://` or `mysql://`, with the user (and the\n\t\t\t * password, when there is one) in it. An `sslmode` in the string sets `tls`. */\n\t\t\turl: string;\n\t\t\tengine?: DatabaseEngine;\n\t\t\t/** Overrides the string's `sslmode`. */\n\t\t\ttls?: DatabaseTls;\n\t\t\twritable?: boolean;\n\t }\n\t| {\n\t\t\tengine: DatabaseEngine;\n\t\t\thost: string;\n\t\t\tport: number;\n\t\t\tdatabase: string;\n\t\t\tusername: string;\n\t\t\t/** Leave it out for a database that takes a user name alone. */\n\t\t\tpassword?: string;\n\t\t\ttls?: DatabaseTls;\n\t\t\twritable?: boolean;\n\t };\n\n/** What `ws.databases.create()` takes: the key agents will name it by, an\n * optional label, and a login. */\nexport type DatabaseFields = DatabaseLogin & {\n\t/** Lowercase letters, digits and dashes, like `shop` or `sales-db`. What an\n\t * agent configuration stores, so it is not editable afterwards. */\n\tkey: string;\n\t/** A label for people. Defaults to the key. */\n\tname?: string;\n};\n\n/** A registered database as AgentNava reports it: where it is, never how to\n * log in. Neither the password nor the connection string is ever returned. */\nexport interface DatabaseData {\n\tkey: string;\n\t/** The underlying connection's id. */\n\tid: string;\n\tname: string;\n\tengine: DatabaseEngine | null;\n\thost: string | null;\n\tport: number | null;\n\tdatabase: string | null;\n\ttls: DatabaseTls | null;\n\twritable: boolean;\n\tstatus: string;\n\tcreatedAt: string;\n\t/** The agents whose configuration names this database. */\n\tusedBy: DatabaseUsedBy[];\n}\n\n/** An agent whose configuration names a database: in its latest published\n * version, in its draft, or in both. */\nexport interface DatabaseUsedBy {\n\t/** The agent's id: the same value as `Agent.id`, so compare this one. */\n\tid: string;\n\t/** AgentNava's internal handle for the same agent (`agt_...`), not `Agent.id`. */\n\tagentId: string;\n\t/** The agent's display name. */\n\tname: string;\n\t/** Named in the agent's latest published version, so its conversations can\n\t * query the database now. */\n\tpublished: boolean;\n\t/** Named in the configuration being edited: the draft when there is one,\n\t * else the published version itself. */\n\tdraft: boolean;\n}\n\n/** One table or view in a database. */\nexport interface DatabaseTable {\n\tschema: string;\n\tname: string;\n\tkind: 'table' | 'view';\n}\n\n/** One column of a table. */\nexport interface DatabaseColumn {\n\tname: string;\n\tdataType: string;\n\tnullable: boolean;\n\tisPrimaryKey: boolean;\n}\n\n/** What `ws.databases.test()` reports. A refused login is an answer, not an\n * exception, because it is the answer the call exists to get. */\nexport type DatabaseTestResult =\n\t| { ok: true; engine: DatabaseEngine; tableCount: number; tables: DatabaseTable[] }\n\t| { ok: false; error: { code: string; message: string } };\n\n/** An agent as its draft holds it, from `agent.draft()`. */\nexport interface AgentDraft {\n\t/** An unpublished draft exists. */\n\texists: boolean;\n\t/** The draft differs from the live version. */\n\thasUnpublishedChanges: boolean;\n\t/** The configuration the draft holds, or the live one when there is no draft. */\n\tconfig: AgentFields;\n}\n\n/**\n * How an agent's website chat looks (the share link, and the chat the embed\n * script opens on a website). Every setting is optional; one left out keeps the\n * default. Part of the agent's configuration, so a change is published with a\n * version like any other field.\n */\nexport interface WebsiteChatAppearance {\n\t/** An image id from `agent.websiteChat.uploadLogo()`, shown in a circle in\n\t * the chat's header. Without one, the name's first letter. */\n\tlogo?: string;\n\t/** The name the chat shows, up to 40 characters. Without one, the agent's name. */\n\ttitle?: string;\n\ttheme?: 'light' | 'dark';\n\t/** One colour, written like `#B4532A`: the avatar, the visitor's messages,\n\t * the send button, chips, prices on cards, and the round button. Where it\n\t * is too light to read as text, words use a darker shade of it. */\n\taccent?: string;\n\t/** `clean` is the default. */\n\tfont?: 'clean' | 'friendly' | 'classic' | 'elegant';\n\t/** Whether the embed script opens the chat when a page loads, on screens\n\t * wider than a phone. New agents start `open`; absent means closed. */\n\topens?: 'open' | 'closed';\n\t/** Up to three short ways in (60 characters each), shown on the chat's\n\t * welcome card before a visitor's first message, such as \"Book a visit\".\n\t * A tap sends its words as the visitor's message. The Agent Builder writes\n\t * them from the agent's job; without them the card shows the greeting. */\n\tstarters?: string[];\n\t/** `false` hides the \"Made with AgentNava\" link under the chat; the\n\t * \"<name> is an AI assistant.\" notice always stays. Shown by default.\n\t * Hiding it needs a paid plan (Team and up): on a free plan the update is\n\t * refused with 403 `plan_required`. A workspace a partner app works in whose\n\t * marketplace forbids \"powered by\" marks (the Wix App Market) may hide it on\n\t * every plan. When a paid plan ends, the link shows again and this choice is\n\t * kept. */\n\tshowMadeWith?: boolean;\n}\n"]}
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.
|
|
1
|
+
export declare const SDK_VERSION = "0.74.0";
|
package/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`
|
|
2
2
|
// after bumping the version in package.json. tests/version.test.ts fails if
|
|
3
3
|
// this drifts.
|
|
4
|
-
export const SDK_VERSION = '0.
|
|
4
|
+
export const SDK_VERSION = '0.74.0';
|
|
5
5
|
//# sourceMappingURL=version.js.map
|
package/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4EAA4E;AAC5E,eAAe;AACf,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`\n// after bumping the version in package.json. tests/version.test.ts fails if\n// this drifts.\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4EAA4E;AAC5E,eAAe;AACf,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`\n// after bumping the version in package.json. tests/version.test.ts fails if\n// this drifts.\nexport const SDK_VERSION = '0.74.0';\n"]}
|
package/workspace.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Account } from './account.ts';
|
|
2
|
+
import { PartnerApp, type PartnerAppOptions } from './partner-app.ts';
|
|
2
3
|
import { Agent } from './agent.ts';
|
|
3
4
|
import type { AppId } from './apps.generated.ts';
|
|
4
5
|
import { type ClientOptions } from './http.ts';
|
|
@@ -7,7 +8,7 @@ import { EndUser } from './end-user.ts';
|
|
|
7
8
|
import { Database } from './database.ts';
|
|
8
9
|
import { KnowledgeBase } from './knowledge-base.ts';
|
|
9
10
|
import { Project } from './project.ts';
|
|
10
|
-
import type { AgentFields, Credits, DatabaseFields, DatabaseLogin, DatabaseTestResult, ProjectFields, SeatPlan, WorkspaceInfo, WorkspaceMember } from './types.ts';
|
|
11
|
+
import type { AppTool, AgentFields, Credits, DatabaseFields, DatabaseLogin, DatabaseTestResult, ProjectFields, SeatPlan, WorkspaceInfo, WorkspaceMember } from './types.ts';
|
|
11
12
|
/**
|
|
12
13
|
* Your workspace: the account an API key names.
|
|
13
14
|
*
|
|
@@ -83,6 +84,11 @@ export declare class Workspace {
|
|
|
83
84
|
*
|
|
84
85
|
* `conversation.attach(secret)` is the route that was missing. */
|
|
85
86
|
endUserId?: string;
|
|
87
|
+
/** The only hosts a tool may send this key to, like
|
|
88
|
+
* `["api.example.com"]`. Left out, the first tool saved with it pins
|
|
89
|
+
* its own host, and a tool sending it anywhere else is refused with
|
|
90
|
+
* SecretHostNotAllowed. */
|
|
91
|
+
allowedHosts?: string[];
|
|
86
92
|
}) => Promise<Secret>;
|
|
87
93
|
/** Every secret this WORKSPACE holds, values excluded. Pass `agentId` to
|
|
88
94
|
* include that agent's own secrets alongside the workspace ones.
|
|
@@ -132,6 +138,21 @@ export declare class Workspace {
|
|
|
132
138
|
app?: AppId;
|
|
133
139
|
}) => Promise<Account[]>;
|
|
134
140
|
};
|
|
141
|
+
/**
|
|
142
|
+
* The apps an agent can connect, and each one's own ready-made tools: what a
|
|
143
|
+
* connection's `tools` chooses from.
|
|
144
|
+
*
|
|
145
|
+
* ```ts
|
|
146
|
+
* const tools = await ws.apps.tools(App.SLACK);
|
|
147
|
+
* const send = tools.find((t) => t.name === 'Send message');
|
|
148
|
+
* await agent.connections.change('slack', { tools: [send!.id] });
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
readonly apps: {
|
|
152
|
+
/** One app's current tools, the common ones first. A tool marked `deletes`
|
|
153
|
+
* removes something; leave those out unless the agent needs them. */
|
|
154
|
+
tools: (app: AppId) => Promise<AppTool[]>;
|
|
155
|
+
};
|
|
135
156
|
/**
|
|
136
157
|
* Knowledge bases: named folders of files your agents read.
|
|
137
158
|
*
|
|
@@ -188,6 +209,17 @@ export declare class Workspace {
|
|
|
188
209
|
* `db.delete()`. */
|
|
189
210
|
get: (key: string) => Promise<Database>;
|
|
190
211
|
};
|
|
212
|
+
/**
|
|
213
|
+
* Whether this workspace's agents may call outside services. `'off'` refuses
|
|
214
|
+
* every HTTP tool and leaves out web search and opening web pages, on every
|
|
215
|
+
* agent, from their next call or turn. MCP servers and connections are not
|
|
216
|
+
* covered yet. Anyone can read it; only an owner or admin, signed in, can
|
|
217
|
+
* change it (an API key gets 403).
|
|
218
|
+
*/
|
|
219
|
+
readonly outsideCalls: {
|
|
220
|
+
get: () => Promise<"on" | "off">;
|
|
221
|
+
set: (value: "on" | "off") => Promise<"on" | "off">;
|
|
222
|
+
};
|
|
191
223
|
readonly projects: {
|
|
192
224
|
create: (fields: ProjectFields) => Promise<Project>;
|
|
193
225
|
list: () => Promise<Project[]>;
|
|
@@ -305,4 +337,6 @@ export declare class Workspace {
|
|
|
305
337
|
*/
|
|
306
338
|
export declare const AgentNava: {
|
|
307
339
|
getWorkspace(options?: string | ClientOptions): Workspace;
|
|
340
|
+
/** For a partner app's server: Sign in with AgentNava, then a workspace key (partner-app.ts). */
|
|
341
|
+
partnerApp(options: PartnerAppOptions): PartnerApp;
|
|
308
342
|
};
|
package/workspace.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// The entry point. `AgentNava.getWorkspace()` is a workspace, because an API key already
|
|
2
2
|
// names one: there is nothing to select and nothing to pass.
|
|
3
3
|
import { Account, accountIn } from "./account.js";
|
|
4
|
+
import { PartnerApp } from "./partner-app.js";
|
|
4
5
|
import { Agent } from "./agent.js";
|
|
5
6
|
import { Http } from "./http.js";
|
|
6
7
|
import { Secret } from "./secret.js";
|
|
@@ -92,6 +93,7 @@ export class Workspace {
|
|
|
92
93
|
...(input.description !== undefined && { description: input.description }),
|
|
93
94
|
...(input.agentId !== undefined && { agentId: input.agentId }),
|
|
94
95
|
...(input.endUserId !== undefined && { endUserId: input.endUserId }),
|
|
96
|
+
...(input.allowedHosts !== undefined && { allowedHosts: input.allowedHosts }),
|
|
95
97
|
});
|
|
96
98
|
const meta = res.secret ?? res;
|
|
97
99
|
return new Secret(this.#http, meta.id, meta);
|
|
@@ -155,6 +157,24 @@ export class Workspace {
|
|
|
155
157
|
return (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));
|
|
156
158
|
},
|
|
157
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* The apps an agent can connect, and each one's own ready-made tools: what a
|
|
162
|
+
* connection's `tools` chooses from.
|
|
163
|
+
*
|
|
164
|
+
* ```ts
|
|
165
|
+
* const tools = await ws.apps.tools(App.SLACK);
|
|
166
|
+
* const send = tools.find((t) => t.name === 'Send message');
|
|
167
|
+
* await agent.connections.change('slack', { tools: [send!.id] });
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
apps = {
|
|
171
|
+
/** One app's current tools, the common ones first. A tool marked `deletes`
|
|
172
|
+
* removes something; leave those out unless the agent needs them. */
|
|
173
|
+
tools: async (app) => {
|
|
174
|
+
const res = await this.#http.get(`/v1/connections/apps/${encodeURIComponent(app)}/tools`);
|
|
175
|
+
return res.tools ?? [];
|
|
176
|
+
},
|
|
177
|
+
};
|
|
158
178
|
/**
|
|
159
179
|
* Knowledge bases: named folders of files your agents read.
|
|
160
180
|
*
|
|
@@ -225,6 +245,17 @@ export class Workspace {
|
|
|
225
245
|
return new Database(this.#http, res.database.key, res.database);
|
|
226
246
|
},
|
|
227
247
|
};
|
|
248
|
+
/**
|
|
249
|
+
* Whether this workspace's agents may call outside services. `'off'` refuses
|
|
250
|
+
* every HTTP tool and leaves out web search and opening web pages, on every
|
|
251
|
+
* agent, from their next call or turn. MCP servers and connections are not
|
|
252
|
+
* covered yet. Anyone can read it; only an owner or admin, signed in, can
|
|
253
|
+
* change it (an API key gets 403).
|
|
254
|
+
*/
|
|
255
|
+
outsideCalls = {
|
|
256
|
+
get: async () => (await this.#http.get('/v1/workspace/outside-calls')).outsideCalls,
|
|
257
|
+
set: async (value) => (await this.#http.put('/v1/workspace/outside-calls', { outsideCalls: value })).outsideCalls,
|
|
258
|
+
};
|
|
228
259
|
projects = {
|
|
229
260
|
create: async (fields) => {
|
|
230
261
|
const data = toProjectData(await this.#http.post('/v1/projects', fields));
|
|
@@ -403,5 +434,9 @@ export const AgentNava = {
|
|
|
403
434
|
getWorkspace(options = {}) {
|
|
404
435
|
return new Workspace(typeof options === 'string' ? { apiKey: options } : options);
|
|
405
436
|
},
|
|
437
|
+
/** For a partner app's server: Sign in with AgentNava, then a workspace key (partner-app.ts). */
|
|
438
|
+
partnerApp(options) {
|
|
439
|
+
return new PartnerApp(options);
|
|
440
|
+
},
|
|
406
441
|
};
|
|
407
442
|
//# sourceMappingURL=workspace.js.map
|
package/workspace.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["// The entry point. `AgentNava.getWorkspace()` is a workspace, because an API key already\n// names one: there is nothing to select and nothing to pass.\n\nimport { Account, accountIn } from './account.ts';\nimport { Agent } from './agent.ts';\nimport type { AppId } from './apps.generated.ts';\nimport { Http, type ClientOptions } from './http.ts';\nimport { Secret } from './secret.ts';\nimport { EndUser } from './end-user.ts';\nimport { Database } from './database.ts';\nimport { KnowledgeBase } from './knowledge-base.ts';\nimport { Project, toProjectData } from './project.ts';\nimport type {\n\tAccountData,\n\tAgentData,\n\tAgentFields,\n\tCredits,\n\tDatabaseData,\n\tDatabaseFields,\n\tDatabaseLogin,\n\tDatabaseTestResult,\n\tKnowledgeBaseData,\n\tProjectData,\n\tProjectFields,\n\tSeatPlan,\n\tSecretMeta,\n\tWorkspaceInfo,\n\tWorkspaceMember,\n} from './types.ts';\n\n/**\n * Your workspace: the account an API key names.\n *\n * ```ts\n * const ws = AgentNava.getWorkspace(); // reads AGENTNAVA_API_KEY\n * const agent = await ws.agents.create({ … });\n * const conversation = await agent.start({ endUserId: 'u_ananya' });\n * console.log(await conversation.ask('Hello'));\n * ```\n *\n * Constructing it makes no request. So do `ws.agent(id)`\n * and `ws.project(id)`: they hand you something you can call methods on, and the\n * first request happens when you call one. Fetching an object just to send it a\n * message would be a round trip for nothing.\n *\n * A returned object is not plain JSON. Store the `id`, not the object, and use\n * `ws.agent(id)` to come back in.\n */\nexport class Workspace {\n\treadonly #http: Http;\n\n\tconstructor(options: ClientOptions = {}) {\n\t\tthis.#http = new Http(options);\n\t}\n\n\t/** The workspace itself: name, credits. */\n\tasync get(): Promise<WorkspaceInfo> {\n\t\treturn this.#http.get<WorkspaceInfo>('/v1/workspace');\n\t}\n\n\treadonly agents = {\n\t\t/**\n\t\t * Create an agent.\n\t\t *\n\t\t * Supplying an `id` is optional; without one the server mints it. An id\n\t\t * that already exists is a 409 rather than a quiet new version of the\n\t\t * existing agent, so a typo cannot silently rewrite something else. Use\n\t\t * `agent.update()` to publish a version.\n\t\t */\n\t\tcreate: async (fields: AgentFields): Promise<Agent> => {\n\t\t\tconst data = await this.#http.post<AgentData>('/v1/agents', fields);\n\t\t\treturn new Agent(this.#http, data.id, data);\n\t\t},\n\t\tlist: async (): Promise<Agent[]> => {\n\t\t\tconst res = await this.#http.get<{ agents: AgentData[] }>('/v1/agents');\n\t\t\treturn (res.agents ?? []).map((a) => new Agent(this.#http, a.id, a));\n\t\t},\n\t};\n\n\t/**\n\t * Secrets: values your agents USE and never see.\n\t *\n\t * The one way to give an agent an API key. A secret is written once, stored\n\t * encrypted, and substituted into an HTTP tool's url, headers or body on the\n\t * server at the moment the call goes out, so the key is never in a prompt,\n\t * never in a transcript, and never in anything the model could repeat back.\n\t * Reference it from a tool as `{{secrets.NAME}}`.\n\t *\n\t * Scope is the `agentId` argument. Left out, every agent in the workspace can\n\t * use it; supplied, only that agent can, and it takes precedence over a\n\t * workspace secret of the same name. Prefer the narrow one for anything that\n\t * moves money.\n\t *\n\t * NOTHING READS A VALUE BACK, including you. `list` returns names and\n\t * metadata. That is deliberate rather than an omission: a value you can read\n\t * is a value that can end up in a log.\n\t */\n\treadonly secrets = {\n\t\t/** Store a secret. A name that already exists at the same scope is a 409,\n\t\t * rather than a silent overwrite of a key something else is using. */\n\t\tcreate: async (input: {\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tdescription?: string;\n\t\t\tagentId?: string;\n\t\t\t/** One of YOUR end users, stored verbatim. Prefer\n\t\t\t * `ws.endUser(id).secrets.create(...)`, which fills this in for you.\n\t\t\t *\n\t\t\t * THIS PARAMETER WAS REMOVED AND IS BACK, and the difference is that\n\t\t\t * it now does something. It used to be accepted, written to the\n\t\t\t * column, and read by nothing: a credential reached a turn only by\n\t\t\t * being ATTACHED, and a secret could not be, because binding one took\n\t\t\t * its VALUE and not an id. A parameter that accepts a write, reports\n\t\t\t * success and changes nothing an agent can use is a decoy, so it was\n\t\t\t * deleted rather than left to teach somebody that per-person secrets\n\t\t\t * worked.\n\t\t\t *\n\t\t\t * `conversation.attach(secret)` is the route that was missing. */\n\t\t\tendUserId?: string;\n\t\t}): Promise<Secret> => {\n\t\t\t// FIELDS PICKED, not the input object forwarded.\n\t\t\t//\n\t\t\t// Removing `endUserId` from the type above did not stop it being SENT.\n\t\t\t// This forwarded `input` wholesale, so a JavaScript caller still put\n\t\t\t// the field on the wire and TypeScript was the only thing that had\n\t\t\t// changed. Caught by running the PUBLISHED 0.19.0 in a throwaway\n\t\t\t// project rather than by reading the source, which is the only way it\n\t\t\t// could have been caught: the types agreed with themselves.\n\t\t\t//\n\t\t\t// Picking is what makes a removal real, and it also means an unknown\n\t\t\t// field can never reach the API by accident.\n\t\t\tconst res = await this.#http.post<{ secret?: SecretMeta } & SecretMeta>('/v1/secrets', {\n\t\t\t\tname: input.name,\n\t\t\t\tvalue: input.value,\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\t...(input.agentId !== undefined && { agentId: input.agentId }),\n\t\t\t\t...(input.endUserId !== undefined && { endUserId: input.endUserId }),\n\t\t\t});\n\t\t\tconst meta = res.secret ?? res;\n\t\t\treturn new Secret(this.#http, meta.id, meta);\n\t\t},\n\t\t/** Every secret this WORKSPACE holds, values excluded. Pass `agentId` to\n\t\t * include that agent's own secrets alongside the workspace ones.\n\t\t *\n\t\t * One of your end users' secrets is NOT in here, deliberately: ask for\n\t\t * those with `ws.endUser(id).secrets.list()`. A listing that mixed them\n\t\t * would be a listing you could not act on, since deleting from it would\n\t\t * reach into somebody's personal credentials. */\n\t\tlist: async (agentId?: string): Promise<Secret[]> => {\n\t\t\tconst res = await this.#http.get<{ secrets: SecretMeta[] }>(\n\t\t\t\t'/v1/secrets',\n\t\t\t\tagentId ? { agentId } : undefined,\n\t\t\t);\n\t\t\treturn (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));\n\t\t},\n\t\t// `update` and `delete` are GONE from here. They live on the Secret you\n\t\t// are holding: `secret.update(value)`, `secret.delete()`. Two ways to do\n\t\t// one thing is how a surface becomes hard to learn, and the object is\n\t\t// the one that reads at a call site.\n\t};\n\n\t/**\n\t * Agent creators' accounts: apps signed in to ONCE, in the workspace, for\n\t * any agent here to use.\n\t *\n\t * An ACCOUNT is one saved sign-in to one app (Gmail, signed in as\n\t * support@example.com). An agent reaches one only through a CONNECTION in its\n\t * setup that names it: `agent.connections.add({ app, account })`. Connecting\n\t * an account grants no agent anything on its own.\n\t *\n\t * The person signs in on the app's own page, so YOU NEVER HANDLE A TOKEN.\n\t * `connect` hands you a url to send them to.\n\t *\n\t * Your end users' own accounts are not here: they belong to each person, and\n\t * live under `ws.endUser(id).accounts`. An agent uses those through a\n\t * connection built with `Connection.endUserAccount(app)`.\n\t */\n\treadonly accounts = {\n\t\t/**\n\t\t * Begin connecting an account. Returns it, still `pending`, and the url\n\t\t * to send the person to; they sign in there, and\n\t\t * `account.waitUntilConnected()` tells you when they are done.\n\t\t *\n\t\t * `nickname` is your own name for it, such as `'Support inbox'`, shown\n\t\t * beside the email it is signed in as. Connecting grants nothing by\n\t\t * itself: only an agent whose setup names the account uses it.\n\t\t */\n\t\tconnect: async (input: { app: AppId; nickname?: string }): Promise<{ account: Account; url: string }> => {\n\t\t\t// FIELDS PICKED, never the input object forwarded: an undeclared field\n\t\t\t// must never reach the API because a JavaScript caller passed it.\n\t\t\tconst res = await this.#http.post<{ account?: AccountData; url: string }>('/v1/accounts/connect', {\n\t\t\t\tapp: input.app,\n\t\t\t\t...(input.nickname !== undefined && { nickname: input.nickname }),\n\t\t\t});\n\t\t\tconst account = accountIn(res, '/v1/accounts/connect');\n\t\t\treturn { account: new Account(this.#http, account.id, account), url: res.url };\n\t\t},\n\n\t\t/** Every agent creator's account in this workspace, each with the agents\n\t\t * that use it (`usedBy`). `app` narrows to one app's. */\n\t\tlist: async (input: { app?: AppId } = {}): Promise<Account[]> => {\n\t\t\tconst res = await this.#http.get<{ accounts: AccountData[] }>(\n\t\t\t\t'/v1/accounts',\n\t\t\t\tinput.app ? { app: input.app } : undefined,\n\t\t\t);\n\t\t\treturn (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));\n\t\t},\n\t};\n\n\t/**\n\t * Knowledge bases: named folders of files your agents read.\n\t *\n\t * Called `knowledgeBases`, not `knowledge`, on purpose. `agent.knowledge`\n\t * already means one agent's FILES, and a `ws.knowledge.list()` returning\n\t * bases rather than files would be the same word meaning two different things\n\t * one level apart. The longer name is worth it.\n\t */\n\treadonly knowledgeBases = {\n\t\t/**\n\t\t * Create a base. The KEY is what agent configurations store, so pick\n\t\t * something readable: `product-docs`, not `kb1`.\n\t\t *\n\t\t * A key already in use is an error rather than a silent overwrite, because\n\t\t * the base it would replace may be one several agents already read from.\n\t\t */\n\t\tcreate: async (fields: {\n\t\t\tkey: string;\n\t\t\tname?: string;\n\t\t\tdescription?: string;\n\t\t}): Promise<KnowledgeBase> => {\n\t\t\tconst res = await this.#http.post<{ base: KnowledgeBaseData }>(\n\t\t\t\t'/v1/knowledge/bases',\n\t\t\t\tfields,\n\t\t\t);\n\t\t\treturn new KnowledgeBase(this.#http, res.base.key, res.base);\n\t\t},\n\n\t\t/** Every base in this workspace. No pagination: bases are few, and a\n\t\t * workspace with hundreds of them has a naming problem rather than a\n\t\t * paging one. */\n\t\tlist: async (): Promise<KnowledgeBase[]> => {\n\t\t\tconst res = await this.#http.get<{ bases: KnowledgeBaseData[] }>('/v1/knowledge/bases');\n\t\t\treturn (res.bases ?? []).map((b) => new KnowledgeBase(this.#http, b.key, b));\n\t\t},\n\n\t\t/** One base, by key. Returns a HANDLE you act through: `kb.files.put(...)`,\n\t\t * `kb.attachments()`, `kb.delete()`. */\n\t\tget: async (key: string): Promise<KnowledgeBase> => {\n\t\t\tconst res = await this.#http.get<{ base: KnowledgeBaseData }>(\n\t\t\t\t`/v1/knowledge/bases/${encodeURIComponent(key)}`,\n\t\t\t);\n\t\t\treturn new KnowledgeBase(this.#http, res.base.key, res.base);\n\t\t},\n\t};\n\n\t/**\n\t * Databases your agents can query, each registered once under a key.\n\t *\n\t * Register first, then name the key in an agent's `databases`. Registering\n\t * logs in before saving, so a wrong login fails here instead of in a\n\t * conversation, and nothing is saved when it does. A database answers only\n\t * the agents whose configuration names its key.\n\t */\n\treadonly databases = {\n\t\t/**\n\t\t * Register a database under a key. Pass a connection string as `url`, or\n\t\t * the same login as `engine`, `host`, `port`, `database`, `username` and\n\t\t * `password`. Read-only unless `writable: true`.\n\t\t *\n\t\t * A key already in use is refused rather than overwritten, because agents\n\t\t * may already be querying the database it names.\n\t\t */\n\t\tcreate: async (fields: DatabaseFields): Promise<Database> => {\n\t\t\tconst res = await this.#http.post<{ database: DatabaseData }>('/v1/databases', fields);\n\t\t\treturn new Database(this.#http, res.database.key, res.database);\n\t\t},\n\n\t\t/** Check a login and see its tables, saving nothing. A refused login comes\n\t\t * back as `{ ok: false, error }`, not as an exception. */\n\t\ttest: async (login: DatabaseLogin): Promise<DatabaseTestResult> =>\n\t\t\tthis.#http.post<DatabaseTestResult>('/v1/databases/test', login),\n\n\t\t/** Every database registered in this workspace, oldest first. */\n\t\tlist: async (): Promise<Database[]> => {\n\t\t\tconst res = await this.#http.get<{ databases: DatabaseData[] }>('/v1/databases');\n\t\t\treturn (res.databases ?? []).map((d) => new Database(this.#http, d.key, d));\n\t\t},\n\n\t\t/** One database, by key. Returns a HANDLE: `db.tables()`, `db.describe()`,\n\t\t * `db.delete()`. */\n\t\tget: async (key: string): Promise<Database> => {\n\t\t\tconst res = await this.#http.get<{ database: DatabaseData }>(`/v1/databases/${encodeURIComponent(key)}`);\n\t\t\treturn new Database(this.#http, res.database.key, res.database);\n\t\t},\n\t};\n\n\treadonly projects = {\n\t\tcreate: async (fields: ProjectFields): Promise<Project> => {\n\t\t\tconst data = toProjectData(await this.#http.post('/v1/projects', fields));\n\t\t\treturn new Project(this.#http, data.id, data);\n\t\t},\n\t\tlist: async (): Promise<Project[]> => {\n\t\t\tconst res = await this.#http.get<{ projects: unknown[] }>('/v1/projects');\n\t\t\treturn (res.projects ?? [])\n\t\t\t\t.map((p) => toProjectData(p as never))\n\t\t\t\t.map((p) => new Project(this.#http, p.id, p));\n\t\t},\n\t};\n\n\t// ---- The account, read-only ------------------------------------------\n\t//\n\t// Everything below reads. There is no create-a-key, no invite, no change of\n\t// plan and no payment method, deliberately and not for want of an endpoint.\n\t// A key is a long-lived credential that ends up in CI, in a container image\n\t// and in somebody's shell history; the blast radius of one that leaks should\n\t// be \"they could read our balance\", not \"they added themselves to the\n\t// account\".\n\t//\n\t// Each of these is scoped to the key's OWN workspace by the server, from the\n\t// key's row rather than from anything the caller sends, so there is no\n\t// workspace argument to pass and no way to point them elsewhere.\n\n\t/**\n\t * Who is on this workspace, and what each of them may do.\n\t *\n\t * ```ts\n\t * for (const m of await ws.members()) {\n\t * console.log(m.email, m.role);\n\t * }\n\t * ```\n\t */\n\tasync members(): Promise<WorkspaceMember[]> {\n\t\tconst res = await this.#http.get<{ members: WorkspaceMember[] }>('/v1/teams/members');\n\t\treturn res.members ?? [];\n\t}\n\n\t/**\n\t * What credit is left, and roughly how many turns that buys.\n\t *\n\t * The turn counts are the useful half: a balance in credits is not something\n\t * anybody can act on without knowing what a turn costs.\n\t *\n\t * ```ts\n\t * const { credits, standardTurnsRemaining } = await ws.credits();\n\t * if (standardTurnsRemaining < 100) await topUpSomehow();\n\t * ```\n\t */\n\tasync credits(): Promise<Credits> {\n\t\tconst res = await this.#http.get<Partial<Credits>>('/v1/credits');\n\t\treturn {\n\t\t\tcredits: res.credits ?? 0,\n\t\t\tstandardTurnsRemaining: res.standardTurnsRemaining ?? 0,\n\t\t\tpremiumTurnsRemaining: res.premiumTurnsRemaining ?? 0,\n\t\t};\n\t}\n\n\t/**\n\t * Which seat plan this workspace is on.\n\t *\n\t * Seats and credits are separate purchases: this says how many people may\n\t * share the account, not how much work they may do. Returns null when the\n\t * server cannot say, rather than guessing at the free plan, because \"we do\n\t * not know\" and \"you are on the cheapest one\" are different answers.\n\t */\n\tasync plan(): Promise<SeatPlan | null> {\n\t\tconst res = await this.#http.get<{\n\t\t\tplans?: SeatPlan[];\n\t\t\tcurrentPlanKey?: string | null;\n\t\t}>('/v1/seat-plans');\n\t\tif (!res.currentPlanKey) return null;\n\t\treturn (res.plans ?? []).find((p) => p.key === res.currentPlanKey) ?? null;\n\t}\n\n\t/** Address an agent you already have the id of. No request. */\n\tagent(agentId: string): Agent {\n\t\treturn new Agent(this.#http, agentId);\n\t}\n\n\t// `ws.conversation(id)` IS GONE, deliberately.\n\t//\n\t// A conversation belongs to an agent, or to a project, and is now addressed\n\t// from whichever one owns it: `ws.agent(a).conversation(id)`. Addressing it\n\t// from the workspace made the parent look optional, which is how this SDK\n\t// came to describe conversations as parentless in its own reference.\n\t//\n\t// The objection to moving it was that a caller would have to store two ids.\n\t// In practice the agent id is a constant in the caller's own code, because\n\t// they configured the agent; it is not a per-row value.\n\n\t/** Address a project you already have the id of. No request. */\n\tproject(projectId: string): Project {\n\t\treturn new Project(this.#http, projectId);\n\t}\n\n\t/**\n\t * One of YOUR end users. No request.\n\t *\n\t * The object everything about a person hangs off: their accounts, their\n\t * secrets, their conversations across every agent. You say who once, here,\n\t * instead of threading an `endUserId` through each call and forgetting it in\n\t * one of them.\n\t *\n\t * ```ts\n\t * const ananya = ws.endUser(row.userId);\n\t * const { url } = await ananya.accounts.connect({ app: App.GMAIL });\n\t * await ananya.conversations();\n\t * ```\n\t *\n\t * A SCOPE, NOT A RECORD. Every other addresser here points at a row we\n\t * store and can list back: `ws.agent(id)`, `ws.project(id)`,\n\t * `ws.account(id)`, `ws.secret(id)`, each with its own\n\t * `ws.<plural>.create/list` (or `connect/list`). This one points at nothing.\n\t * We do not create your end users, we cannot list them, and there is no\n\t * `ws.endUsers` collection anywhere in this SDK. We only write the id you\n\t * give us onto rows we already own.\n\t *\n\t * So this does not fetch a person. It hands you the same workspace,\n\t * narrowed to one of your people. If a `ws.endUsers` ever appears here,\n\t * something has started claiming to own them.\n\t *\n\t * It hangs off the workspace because a an end-user id is MEANINGLESS WITHOUT\n\t * ONE: uniqueness is (workspace_id, end_user_id, provider), so two of our\n\t * own customers can each have a person called `user_1` without colliding.\n\t *\n\t * NOT `ws.user()`, and not a workspace member. `ws.members()` lists the\n\t * colleagues who share this account, with ids we issued and authenticate.\n\t * This takes an id from YOUR database that we store verbatim and never\n\t * check. Passing one where the other belongs used to be a call that could\n\t * not fail, because there is nothing for an end-user id to fail against.\n\t */\n\tendUser(endUserId: string): EndUser {\n\t\treturn new EndUser(this.#http, endUserId);\n\t}\n\n\t/** Address an account you already have the id of. No request.\n\t *\n\t * The sibling of `ws.agent(id)`. ANY account in this workspace: the agent\n\t * creator's, or one of your end users' (`data.owner` says which, after a\n\t * read). An account never belongs to one agent: many agents can name it,\n\t * which is why reconnecting it once fixes all of them. `account.get()`\n\t * reads it, and a missing one throws. */\n\taccount(accountId: string): Account {\n\t\treturn new Account(this.#http, accountId);\n\t}\n\n\t/** Address a secret you already have the id of. No request. */\n\tsecret(secretId: string): Secret {\n\t\treturn new Secret(this.#http, secretId);\n\t}\n\n\t/** Address a knowledge base you already know the key of. No request.\n\t *\n\t * The sibling of `agent()` and `project()`, and it was the\n\t * one missing: reaching a base meant `knowledgeBases.get(key)`, which costs a\n\t * round trip to learn something the caller already knew. Use `get()` when you\n\t * want the base's RECORD; use this when you only want to put a file in it. */\n\tknowledgeBase(key: string): KnowledgeBase {\n\t\treturn new KnowledgeBase(this.#http, key);\n\t}\n\n\t/** Address a database you already know the key of. No request. */\n\tdatabase(key: string): Database {\n\t\treturn new Database(this.#http, key);\n\t}\n}\n\n/**\n * The way in.\n *\n * ```ts\n * import { AgentNava } from '@cerebro-labs/agentnava-sdk';\n *\n * const ws = AgentNava.getWorkspace(); // reads AGENTNAVA_API_KEY\n * const ws = AgentNava.getWorkspace('ank_...'); // or pass the key\n * ```\n *\n * IT MAKES NO REQUEST. `get` here means \"hand me the workspace this key names\",\n * not \"go and fetch it\"; the first round trip happens on the first method you\n * call. `ws.get()` is the one that actually reads the record.\n *\n * An API key belongs to exactly one workspace, so there is nothing to select\n * and no workspace argument anywhere in this SDK. This does not CREATE a\n * workspace either: the key already names one, and creating them is not\n * something an API key may do (see \"the account is read-only\").\n */\nexport const AgentNava = {\n\tgetWorkspace(options: string | ClientOptions = {}): Workspace {\n\t\treturn new Workspace(typeof options === 'string' ? { apiKey: options } : options);\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["// The entry point. `AgentNava.getWorkspace()` is a workspace, because an API key already\n// names one: there is nothing to select and nothing to pass.\n\nimport { Account, accountIn } from './account.ts';\nimport { PartnerApp, type PartnerAppOptions } from './partner-app.ts';\nimport { Agent } from './agent.ts';\nimport type { AppId } from './apps.generated.ts';\nimport { Http, type ClientOptions } from './http.ts';\nimport { Secret } from './secret.ts';\nimport { EndUser } from './end-user.ts';\nimport { Database } from './database.ts';\nimport { KnowledgeBase } from './knowledge-base.ts';\nimport { Project, toProjectData } from './project.ts';\nimport type {\n\tAccountData,\n\tAppTool,\n\tAgentData,\n\tAgentFields,\n\tCredits,\n\tDatabaseData,\n\tDatabaseFields,\n\tDatabaseLogin,\n\tDatabaseTestResult,\n\tKnowledgeBaseData,\n\tProjectData,\n\tProjectFields,\n\tSeatPlan,\n\tSecretMeta,\n\tWorkspaceInfo,\n\tWorkspaceMember,\n} from './types.ts';\n\n/**\n * Your workspace: the account an API key names.\n *\n * ```ts\n * const ws = AgentNava.getWorkspace(); // reads AGENTNAVA_API_KEY\n * const agent = await ws.agents.create({ … });\n * const conversation = await agent.start({ endUserId: 'u_ananya' });\n * console.log(await conversation.ask('Hello'));\n * ```\n *\n * Constructing it makes no request. So do `ws.agent(id)`\n * and `ws.project(id)`: they hand you something you can call methods on, and the\n * first request happens when you call one. Fetching an object just to send it a\n * message would be a round trip for nothing.\n *\n * A returned object is not plain JSON. Store the `id`, not the object, and use\n * `ws.agent(id)` to come back in.\n */\nexport class Workspace {\n\treadonly #http: Http;\n\n\tconstructor(options: ClientOptions = {}) {\n\t\tthis.#http = new Http(options);\n\t}\n\n\t/** The workspace itself: name, credits. */\n\tasync get(): Promise<WorkspaceInfo> {\n\t\treturn this.#http.get<WorkspaceInfo>('/v1/workspace');\n\t}\n\n\treadonly agents = {\n\t\t/**\n\t\t * Create an agent.\n\t\t *\n\t\t * Supplying an `id` is optional; without one the server mints it. An id\n\t\t * that already exists is a 409 rather than a quiet new version of the\n\t\t * existing agent, so a typo cannot silently rewrite something else. Use\n\t\t * `agent.update()` to publish a version.\n\t\t */\n\t\tcreate: async (fields: AgentFields): Promise<Agent> => {\n\t\t\tconst data = await this.#http.post<AgentData>('/v1/agents', fields);\n\t\t\treturn new Agent(this.#http, data.id, data);\n\t\t},\n\t\tlist: async (): Promise<Agent[]> => {\n\t\t\tconst res = await this.#http.get<{ agents: AgentData[] }>('/v1/agents');\n\t\t\treturn (res.agents ?? []).map((a) => new Agent(this.#http, a.id, a));\n\t\t},\n\t};\n\n\t/**\n\t * Secrets: values your agents USE and never see.\n\t *\n\t * The one way to give an agent an API key. A secret is written once, stored\n\t * encrypted, and substituted into an HTTP tool's url, headers or body on the\n\t * server at the moment the call goes out, so the key is never in a prompt,\n\t * never in a transcript, and never in anything the model could repeat back.\n\t * Reference it from a tool as `{{secrets.NAME}}`.\n\t *\n\t * Scope is the `agentId` argument. Left out, every agent in the workspace can\n\t * use it; supplied, only that agent can, and it takes precedence over a\n\t * workspace secret of the same name. Prefer the narrow one for anything that\n\t * moves money.\n\t *\n\t * NOTHING READS A VALUE BACK, including you. `list` returns names and\n\t * metadata. That is deliberate rather than an omission: a value you can read\n\t * is a value that can end up in a log.\n\t */\n\treadonly secrets = {\n\t\t/** Store a secret. A name that already exists at the same scope is a 409,\n\t\t * rather than a silent overwrite of a key something else is using. */\n\t\tcreate: async (input: {\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tdescription?: string;\n\t\t\tagentId?: string;\n\t\t\t/** One of YOUR end users, stored verbatim. Prefer\n\t\t\t * `ws.endUser(id).secrets.create(...)`, which fills this in for you.\n\t\t\t *\n\t\t\t * THIS PARAMETER WAS REMOVED AND IS BACK, and the difference is that\n\t\t\t * it now does something. It used to be accepted, written to the\n\t\t\t * column, and read by nothing: a credential reached a turn only by\n\t\t\t * being ATTACHED, and a secret could not be, because binding one took\n\t\t\t * its VALUE and not an id. A parameter that accepts a write, reports\n\t\t\t * success and changes nothing an agent can use is a decoy, so it was\n\t\t\t * deleted rather than left to teach somebody that per-person secrets\n\t\t\t * worked.\n\t\t\t *\n\t\t\t * `conversation.attach(secret)` is the route that was missing. */\n\t\t\tendUserId?: string;\n\t\t\t/** The only hosts a tool may send this key to, like\n\t\t\t * `[\"api.example.com\"]`. Left out, the first tool saved with it pins\n\t\t\t * its own host, and a tool sending it anywhere else is refused with\n\t\t\t * SecretHostNotAllowed. */\n\t\t\tallowedHosts?: string[];\n\t\t}): Promise<Secret> => {\n\t\t\t// FIELDS PICKED, not the input object forwarded.\n\t\t\t//\n\t\t\t// Removing `endUserId` from the type above did not stop it being SENT.\n\t\t\t// This forwarded `input` wholesale, so a JavaScript caller still put\n\t\t\t// the field on the wire and TypeScript was the only thing that had\n\t\t\t// changed. Caught by running the PUBLISHED 0.19.0 in a throwaway\n\t\t\t// project rather than by reading the source, which is the only way it\n\t\t\t// could have been caught: the types agreed with themselves.\n\t\t\t//\n\t\t\t// Picking is what makes a removal real, and it also means an unknown\n\t\t\t// field can never reach the API by accident.\n\t\t\tconst res = await this.#http.post<{ secret?: SecretMeta } & SecretMeta>('/v1/secrets', {\n\t\t\t\tname: input.name,\n\t\t\t\tvalue: input.value,\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\t...(input.agentId !== undefined && { agentId: input.agentId }),\n\t\t\t\t...(input.endUserId !== undefined && { endUserId: input.endUserId }),\n\t\t\t\t...(input.allowedHosts !== undefined && { allowedHosts: input.allowedHosts }),\n\t\t\t});\n\t\t\tconst meta = res.secret ?? res;\n\t\t\treturn new Secret(this.#http, meta.id, meta);\n\t\t},\n\t\t/** Every secret this WORKSPACE holds, values excluded. Pass `agentId` to\n\t\t * include that agent's own secrets alongside the workspace ones.\n\t\t *\n\t\t * One of your end users' secrets is NOT in here, deliberately: ask for\n\t\t * those with `ws.endUser(id).secrets.list()`. A listing that mixed them\n\t\t * would be a listing you could not act on, since deleting from it would\n\t\t * reach into somebody's personal credentials. */\n\t\tlist: async (agentId?: string): Promise<Secret[]> => {\n\t\t\tconst res = await this.#http.get<{ secrets: SecretMeta[] }>(\n\t\t\t\t'/v1/secrets',\n\t\t\t\tagentId ? { agentId } : undefined,\n\t\t\t);\n\t\t\treturn (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));\n\t\t},\n\t\t// `update` and `delete` are GONE from here. They live on the Secret you\n\t\t// are holding: `secret.update(value)`, `secret.delete()`. Two ways to do\n\t\t// one thing is how a surface becomes hard to learn, and the object is\n\t\t// the one that reads at a call site.\n\t};\n\n\t/**\n\t * Agent creators' accounts: apps signed in to ONCE, in the workspace, for\n\t * any agent here to use.\n\t *\n\t * An ACCOUNT is one saved sign-in to one app (Gmail, signed in as\n\t * support@example.com). An agent reaches one only through a CONNECTION in its\n\t * setup that names it: `agent.connections.add({ app, account })`. Connecting\n\t * an account grants no agent anything on its own.\n\t *\n\t * The person signs in on the app's own page, so YOU NEVER HANDLE A TOKEN.\n\t * `connect` hands you a url to send them to.\n\t *\n\t * Your end users' own accounts are not here: they belong to each person, and\n\t * live under `ws.endUser(id).accounts`. An agent uses those through a\n\t * connection built with `Connection.endUserAccount(app)`.\n\t */\n\treadonly accounts = {\n\t\t/**\n\t\t * Begin connecting an account. Returns it, still `pending`, and the url\n\t\t * to send the person to; they sign in there, and\n\t\t * `account.waitUntilConnected()` tells you when they are done.\n\t\t *\n\t\t * `nickname` is your own name for it, such as `'Support inbox'`, shown\n\t\t * beside the email it is signed in as. Connecting grants nothing by\n\t\t * itself: only an agent whose setup names the account uses it.\n\t\t */\n\t\tconnect: async (input: { app: AppId; nickname?: string }): Promise<{ account: Account; url: string }> => {\n\t\t\t// FIELDS PICKED, never the input object forwarded: an undeclared field\n\t\t\t// must never reach the API because a JavaScript caller passed it.\n\t\t\tconst res = await this.#http.post<{ account?: AccountData; url: string }>('/v1/accounts/connect', {\n\t\t\t\tapp: input.app,\n\t\t\t\t...(input.nickname !== undefined && { nickname: input.nickname }),\n\t\t\t});\n\t\t\tconst account = accountIn(res, '/v1/accounts/connect');\n\t\t\treturn { account: new Account(this.#http, account.id, account), url: res.url };\n\t\t},\n\n\t\t/** Every agent creator's account in this workspace, each with the agents\n\t\t * that use it (`usedBy`). `app` narrows to one app's. */\n\t\tlist: async (input: { app?: AppId } = {}): Promise<Account[]> => {\n\t\t\tconst res = await this.#http.get<{ accounts: AccountData[] }>(\n\t\t\t\t'/v1/accounts',\n\t\t\t\tinput.app ? { app: input.app } : undefined,\n\t\t\t);\n\t\t\treturn (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));\n\t\t},\n\t};\n\n\t/**\n\t * The apps an agent can connect, and each one's own ready-made tools: what a\n\t * connection's `tools` chooses from.\n\t *\n\t * ```ts\n\t * const tools = await ws.apps.tools(App.SLACK);\n\t * const send = tools.find((t) => t.name === 'Send message');\n\t * await agent.connections.change('slack', { tools: [send!.id] });\n\t * ```\n\t */\n\treadonly apps = {\n\t\t/** One app's current tools, the common ones first. A tool marked `deletes`\n\t\t * removes something; leave those out unless the agent needs them. */\n\t\ttools: async (app: AppId): Promise<AppTool[]> => {\n\t\t\tconst res = await this.#http.get<{ tools?: AppTool[] }>(`/v1/connections/apps/${encodeURIComponent(app)}/tools`);\n\t\t\treturn res.tools ?? [];\n\t\t},\n\t};\n\n\t/**\n\t * Knowledge bases: named folders of files your agents read.\n\t *\n\t * Called `knowledgeBases`, not `knowledge`, on purpose. `agent.knowledge`\n\t * already means one agent's FILES, and a `ws.knowledge.list()` returning\n\t * bases rather than files would be the same word meaning two different things\n\t * one level apart. The longer name is worth it.\n\t */\n\treadonly knowledgeBases = {\n\t\t/**\n\t\t * Create a base. The KEY is what agent configurations store, so pick\n\t\t * something readable: `product-docs`, not `kb1`.\n\t\t *\n\t\t * A key already in use is an error rather than a silent overwrite, because\n\t\t * the base it would replace may be one several agents already read from.\n\t\t */\n\t\tcreate: async (fields: {\n\t\t\tkey: string;\n\t\t\tname?: string;\n\t\t\tdescription?: string;\n\t\t}): Promise<KnowledgeBase> => {\n\t\t\tconst res = await this.#http.post<{ base: KnowledgeBaseData }>(\n\t\t\t\t'/v1/knowledge/bases',\n\t\t\t\tfields,\n\t\t\t);\n\t\t\treturn new KnowledgeBase(this.#http, res.base.key, res.base);\n\t\t},\n\n\t\t/** Every base in this workspace. No pagination: bases are few, and a\n\t\t * workspace with hundreds of them has a naming problem rather than a\n\t\t * paging one. */\n\t\tlist: async (): Promise<KnowledgeBase[]> => {\n\t\t\tconst res = await this.#http.get<{ bases: KnowledgeBaseData[] }>('/v1/knowledge/bases');\n\t\t\treturn (res.bases ?? []).map((b) => new KnowledgeBase(this.#http, b.key, b));\n\t\t},\n\n\t\t/** One base, by key. Returns a HANDLE you act through: `kb.files.put(...)`,\n\t\t * `kb.attachments()`, `kb.delete()`. */\n\t\tget: async (key: string): Promise<KnowledgeBase> => {\n\t\t\tconst res = await this.#http.get<{ base: KnowledgeBaseData }>(\n\t\t\t\t`/v1/knowledge/bases/${encodeURIComponent(key)}`,\n\t\t\t);\n\t\t\treturn new KnowledgeBase(this.#http, res.base.key, res.base);\n\t\t},\n\t};\n\n\t/**\n\t * Databases your agents can query, each registered once under a key.\n\t *\n\t * Register first, then name the key in an agent's `databases`. Registering\n\t * logs in before saving, so a wrong login fails here instead of in a\n\t * conversation, and nothing is saved when it does. A database answers only\n\t * the agents whose configuration names its key.\n\t */\n\treadonly databases = {\n\t\t/**\n\t\t * Register a database under a key. Pass a connection string as `url`, or\n\t\t * the same login as `engine`, `host`, `port`, `database`, `username` and\n\t\t * `password`. Read-only unless `writable: true`.\n\t\t *\n\t\t * A key already in use is refused rather than overwritten, because agents\n\t\t * may already be querying the database it names.\n\t\t */\n\t\tcreate: async (fields: DatabaseFields): Promise<Database> => {\n\t\t\tconst res = await this.#http.post<{ database: DatabaseData }>('/v1/databases', fields);\n\t\t\treturn new Database(this.#http, res.database.key, res.database);\n\t\t},\n\n\t\t/** Check a login and see its tables, saving nothing. A refused login comes\n\t\t * back as `{ ok: false, error }`, not as an exception. */\n\t\ttest: async (login: DatabaseLogin): Promise<DatabaseTestResult> =>\n\t\t\tthis.#http.post<DatabaseTestResult>('/v1/databases/test', login),\n\n\t\t/** Every database registered in this workspace, oldest first. */\n\t\tlist: async (): Promise<Database[]> => {\n\t\t\tconst res = await this.#http.get<{ databases: DatabaseData[] }>('/v1/databases');\n\t\t\treturn (res.databases ?? []).map((d) => new Database(this.#http, d.key, d));\n\t\t},\n\n\t\t/** One database, by key. Returns a HANDLE: `db.tables()`, `db.describe()`,\n\t\t * `db.delete()`. */\n\t\tget: async (key: string): Promise<Database> => {\n\t\t\tconst res = await this.#http.get<{ database: DatabaseData }>(`/v1/databases/${encodeURIComponent(key)}`);\n\t\t\treturn new Database(this.#http, res.database.key, res.database);\n\t\t},\n\t};\n\n\t/**\n\t * Whether this workspace's agents may call outside services. `'off'` refuses\n\t * every HTTP tool and leaves out web search and opening web pages, on every\n\t * agent, from their next call or turn. MCP servers and connections are not\n\t * covered yet. Anyone can read it; only an owner or admin, signed in, can\n\t * change it (an API key gets 403).\n\t */\n\treadonly outsideCalls = {\n\t\tget: async (): Promise<'on' | 'off'> =>\n\t\t\t(await this.#http.get<{ outsideCalls: 'on' | 'off' }>('/v1/workspace/outside-calls')).outsideCalls,\n\t\tset: async (value: 'on' | 'off'): Promise<'on' | 'off'> =>\n\t\t\t(await this.#http.put<{ outsideCalls: 'on' | 'off' }>('/v1/workspace/outside-calls', { outsideCalls: value })).outsideCalls,\n\t};\n\n\treadonly projects = {\n\t\tcreate: async (fields: ProjectFields): Promise<Project> => {\n\t\t\tconst data = toProjectData(await this.#http.post('/v1/projects', fields));\n\t\t\treturn new Project(this.#http, data.id, data);\n\t\t},\n\t\tlist: async (): Promise<Project[]> => {\n\t\t\tconst res = await this.#http.get<{ projects: unknown[] }>('/v1/projects');\n\t\t\treturn (res.projects ?? [])\n\t\t\t\t.map((p) => toProjectData(p as never))\n\t\t\t\t.map((p) => new Project(this.#http, p.id, p));\n\t\t},\n\t};\n\n\t// ---- The account, read-only ------------------------------------------\n\t//\n\t// Everything below reads. There is no create-a-key, no invite, no change of\n\t// plan and no payment method, deliberately and not for want of an endpoint.\n\t// A key is a long-lived credential that ends up in CI, in a container image\n\t// and in somebody's shell history; the blast radius of one that leaks should\n\t// be \"they could read our balance\", not \"they added themselves to the\n\t// account\".\n\t//\n\t// Each of these is scoped to the key's OWN workspace by the server, from the\n\t// key's row rather than from anything the caller sends, so there is no\n\t// workspace argument to pass and no way to point them elsewhere.\n\n\t/**\n\t * Who is on this workspace, and what each of them may do.\n\t *\n\t * ```ts\n\t * for (const m of await ws.members()) {\n\t * console.log(m.email, m.role);\n\t * }\n\t * ```\n\t */\n\tasync members(): Promise<WorkspaceMember[]> {\n\t\tconst res = await this.#http.get<{ members: WorkspaceMember[] }>('/v1/teams/members');\n\t\treturn res.members ?? [];\n\t}\n\n\t/**\n\t * What credit is left, and roughly how many turns that buys.\n\t *\n\t * The turn counts are the useful half: a balance in credits is not something\n\t * anybody can act on without knowing what a turn costs.\n\t *\n\t * ```ts\n\t * const { credits, standardTurnsRemaining } = await ws.credits();\n\t * if (standardTurnsRemaining < 100) await topUpSomehow();\n\t * ```\n\t */\n\tasync credits(): Promise<Credits> {\n\t\tconst res = await this.#http.get<Partial<Credits>>('/v1/credits');\n\t\treturn {\n\t\t\tcredits: res.credits ?? 0,\n\t\t\tstandardTurnsRemaining: res.standardTurnsRemaining ?? 0,\n\t\t\tpremiumTurnsRemaining: res.premiumTurnsRemaining ?? 0,\n\t\t};\n\t}\n\n\t/**\n\t * Which seat plan this workspace is on.\n\t *\n\t * Seats and credits are separate purchases: this says how many people may\n\t * share the account, not how much work they may do. Returns null when the\n\t * server cannot say, rather than guessing at the free plan, because \"we do\n\t * not know\" and \"you are on the cheapest one\" are different answers.\n\t */\n\tasync plan(): Promise<SeatPlan | null> {\n\t\tconst res = await this.#http.get<{\n\t\t\tplans?: SeatPlan[];\n\t\t\tcurrentPlanKey?: string | null;\n\t\t}>('/v1/seat-plans');\n\t\tif (!res.currentPlanKey) return null;\n\t\treturn (res.plans ?? []).find((p) => p.key === res.currentPlanKey) ?? null;\n\t}\n\n\t/** Address an agent you already have the id of. No request. */\n\tagent(agentId: string): Agent {\n\t\treturn new Agent(this.#http, agentId);\n\t}\n\n\t// `ws.conversation(id)` IS GONE, deliberately.\n\t//\n\t// A conversation belongs to an agent, or to a project, and is now addressed\n\t// from whichever one owns it: `ws.agent(a).conversation(id)`. Addressing it\n\t// from the workspace made the parent look optional, which is how this SDK\n\t// came to describe conversations as parentless in its own reference.\n\t//\n\t// The objection to moving it was that a caller would have to store two ids.\n\t// In practice the agent id is a constant in the caller's own code, because\n\t// they configured the agent; it is not a per-row value.\n\n\t/** Address a project you already have the id of. No request. */\n\tproject(projectId: string): Project {\n\t\treturn new Project(this.#http, projectId);\n\t}\n\n\t/**\n\t * One of YOUR end users. No request.\n\t *\n\t * The object everything about a person hangs off: their accounts, their\n\t * secrets, their conversations across every agent. You say who once, here,\n\t * instead of threading an `endUserId` through each call and forgetting it in\n\t * one of them.\n\t *\n\t * ```ts\n\t * const ananya = ws.endUser(row.userId);\n\t * const { url } = await ananya.accounts.connect({ app: App.GMAIL });\n\t * await ananya.conversations();\n\t * ```\n\t *\n\t * A SCOPE, NOT A RECORD. Every other addresser here points at a row we\n\t * store and can list back: `ws.agent(id)`, `ws.project(id)`,\n\t * `ws.account(id)`, `ws.secret(id)`, each with its own\n\t * `ws.<plural>.create/list` (or `connect/list`). This one points at nothing.\n\t * We do not create your end users, we cannot list them, and there is no\n\t * `ws.endUsers` collection anywhere in this SDK. We only write the id you\n\t * give us onto rows we already own.\n\t *\n\t * So this does not fetch a person. It hands you the same workspace,\n\t * narrowed to one of your people. If a `ws.endUsers` ever appears here,\n\t * something has started claiming to own them.\n\t *\n\t * It hangs off the workspace because a an end-user id is MEANINGLESS WITHOUT\n\t * ONE: uniqueness is (workspace_id, end_user_id, provider), so two of our\n\t * own customers can each have a person called `user_1` without colliding.\n\t *\n\t * NOT `ws.user()`, and not a workspace member. `ws.members()` lists the\n\t * colleagues who share this account, with ids we issued and authenticate.\n\t * This takes an id from YOUR database that we store verbatim and never\n\t * check. Passing one where the other belongs used to be a call that could\n\t * not fail, because there is nothing for an end-user id to fail against.\n\t */\n\tendUser(endUserId: string): EndUser {\n\t\treturn new EndUser(this.#http, endUserId);\n\t}\n\n\t/** Address an account you already have the id of. No request.\n\t *\n\t * The sibling of `ws.agent(id)`. ANY account in this workspace: the agent\n\t * creator's, or one of your end users' (`data.owner` says which, after a\n\t * read). An account never belongs to one agent: many agents can name it,\n\t * which is why reconnecting it once fixes all of them. `account.get()`\n\t * reads it, and a missing one throws. */\n\taccount(accountId: string): Account {\n\t\treturn new Account(this.#http, accountId);\n\t}\n\n\t/** Address a secret you already have the id of. No request. */\n\tsecret(secretId: string): Secret {\n\t\treturn new Secret(this.#http, secretId);\n\t}\n\n\t/** Address a knowledge base you already know the key of. No request.\n\t *\n\t * The sibling of `agent()` and `project()`, and it was the\n\t * one missing: reaching a base meant `knowledgeBases.get(key)`, which costs a\n\t * round trip to learn something the caller already knew. Use `get()` when you\n\t * want the base's RECORD; use this when you only want to put a file in it. */\n\tknowledgeBase(key: string): KnowledgeBase {\n\t\treturn new KnowledgeBase(this.#http, key);\n\t}\n\n\t/** Address a database you already know the key of. No request. */\n\tdatabase(key: string): Database {\n\t\treturn new Database(this.#http, key);\n\t}\n}\n\n/**\n * The way in.\n *\n * ```ts\n * import { AgentNava } from '@cerebro-labs/agentnava-sdk';\n *\n * const ws = AgentNava.getWorkspace(); // reads AGENTNAVA_API_KEY\n * const ws = AgentNava.getWorkspace('ank_...'); // or pass the key\n * ```\n *\n * IT MAKES NO REQUEST. `get` here means \"hand me the workspace this key names\",\n * not \"go and fetch it\"; the first round trip happens on the first method you\n * call. `ws.get()` is the one that actually reads the record.\n *\n * An API key belongs to exactly one workspace, so there is nothing to select\n * and no workspace argument anywhere in this SDK. This does not CREATE a\n * workspace either: the key already names one, and creating them is not\n * something an API key may do (see \"the account is read-only\").\n */\nexport const AgentNava = {\n\tgetWorkspace(options: string | ClientOptions = {}): Workspace {\n\t\treturn new Workspace(typeof options === 'string' ? { apiKey: options } : options);\n\t},\n\t/** For a partner app's server: Sign in with AgentNava, then a workspace key (partner-app.ts). */\n\tpartnerApp(options: PartnerAppOptions): PartnerApp {\n\t\treturn new PartnerApp(options);\n\t},\n};\n"]}
|