@alfe.ai/agent-api-client 0.1.3 → 0.2.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/dist/index.cjs +334 -13
- package/dist/index.d.cts +313 -310
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +313 -310
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +334 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @alfe.ai/agent-api-client — Agent self-service API client.\n *\n * Used by agents calling /agent/ endpoints. The agent authenticates\n * with its API key — the backend resolves agentId + tenantId from the token.\n * No agent ID needed in paths or config.\n */\n\nexport type {\n IntegrationInstall,\n IntegrationConfigResult,\n RegistryEntry,\n IntegrationConfigSchemaField,\n SecretScope,\n EncryptedEnvelopeV1,\n SecretMetadata,\n SecretAggregate,\n Field,\n FieldFormat,\n FieldSensitivity,\n FieldView,\n FieldEnvelope,\n SecretCategory,\n ChangelogEntry,\n ChangelogAction,\n ChangelogActor,\n ScopeInfo,\n GeneratedDataKey,\n} from \"@alfe/types\";\n\nimport type {\n IntegrationInstall,\n IntegrationConfigResult,\n RegistryEntry,\n SecretScope,\n EncryptedEnvelopeV1,\n SecretMetadata,\n SecretAggregate,\n FieldFormat,\n FieldSensitivity,\n FieldEnvelope,\n SecretCategory,\n ChangelogEntry,\n ScopeInfo,\n GeneratedDataKey,\n} from \"@alfe/types\";\n\nexport interface AgentApiClientConfig {\n apiKey: string;\n apiUrl: string;\n}\n\n// ─── Sync types ──────────────────────────────────────────\n\nexport interface SyncAgentInfo {\n agentId: string;\n tenantId: string;\n displayName: string;\n s3Prefix: string;\n status: \"stale\" | \"syncing\" | \"synced\";\n fileCount?: number;\n totalSize?: number;\n lastSync?: string;\n}\n\nexport interface SyncManifestEntry {\n hash: string;\n size: number;\n modified: string;\n etag?: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncManifest {\n version: 1;\n agentId: string;\n lastSync: string;\n files: Record<string, SyncManifestEntry>;\n}\n\nexport interface SyncPresignedUrl {\n path: string;\n url: string;\n expiresAt: string;\n}\n\nexport interface SyncConfirmedUpload {\n filePath: string;\n hash: string;\n size: number;\n storageClass: \"STANDARD\" | \"GLACIER_IR\";\n syncedAt: string;\n}\n\nexport interface SyncReconstructFile {\n path: string;\n size: number;\n url: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncReconstructBundle {\n agentId: string;\n mode: \"full\" | \"active\" | \"memory\";\n fileCount: number;\n totalSize: number;\n files: SyncReconstructFile[];\n expiresAt: string;\n}\n\nexport interface SyncAgentStats {\n agentId: string;\n standardBytes: number;\n glacierBytes: number;\n fileCount: number;\n lastSyncAt: string | null;\n}\n\nexport interface SyncFileEntry {\n filePath: string;\n size: number;\n modified: string;\n contentHash: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncSessionEntry {\n sessionId: string;\n size: number;\n lastModified: string;\n storageClass?: string;\n isArchived: boolean;\n}\n\nexport interface SyncSessionContent {\n sessionId: string;\n content: string;\n compressed: boolean;\n}\n\nexport interface SharedFileEntry {\n filePath: string;\n fileName: string;\n size: number;\n contentType?: string;\n}\n\n/**\n * Encode each path segment but keep the `/` separators — `encodeURIComponent`\n * would escape the slashes too, breaking greedy proxy routes.\n */\nfunction encodeFilePath(filePath: string): string {\n return filePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nexport class AgentApiClient {\n private readonly apiKey: string;\n private readonly apiUrl: string;\n\n constructor(config: AgentApiClientConfig) {\n this.apiKey = config.apiKey;\n this.apiUrl = config.apiUrl;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const headers = new Headers(options?.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"Content-Type\", \"application/json\");\n\n const res = await fetch(url, { ...options, headers });\n\n if (!res.ok) {\n await res.text(); // drain body\n throw new Error(`Agent API request failed (${String(res.status)})`);\n }\n\n const body = (await res.json()) as { data: T };\n return body.data;\n }\n\n // ─── Sync ────────────────────────────────────────────────\n //\n // Workspace backup. The agent only ever calls /agent/sync/* — file\n // bytes go to/from S3 via presigned URLs (S3 fetch is the one\n // legitimate raw-fetch in a plugin). Dashboard editing uses the\n // user-API at /sync/agents/{agentId}/* and is not exposed here.\n\n async syncRegister(args?: { displayName?: string }): Promise<{ agent: SyncAgentInfo }> {\n return this.request(\"/agent/sync/register\", {\n method: \"POST\",\n body: JSON.stringify(args ?? {}),\n });\n }\n\n async syncGetManifest(): Promise<SyncManifest> {\n return this.request(\"/agent/sync/manifest\");\n }\n\n async syncPresign(args: {\n files: { path: string; operation: \"put\" | \"get\"; contentType?: string }[];\n }): Promise<{ urls: SyncPresignedUrl[] }> {\n return this.request(\"/agent/sync/presign\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncConfirmUpload(args: {\n filePath: string;\n hash: string;\n size: number;\n storageClass?: \"STANDARD\" | \"GLACIER_IR\";\n }): Promise<SyncConfirmedUpload> {\n return this.request(\"/agent/sync/confirm\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncReconstruct(args: {\n mode: \"full\" | \"active\" | \"memory\";\n }): Promise<SyncReconstructBundle> {\n return this.request(\"/agent/sync/reconstruct\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncGetStats(): Promise<SyncAgentStats> {\n return this.request(\"/agent/sync/stats\");\n }\n\n async syncListFiles(args?: { prefix?: string }): Promise<{ files: SyncFileEntry[] }> {\n const qs = new URLSearchParams();\n if (args?.prefix) qs.set(\"prefix\", args.prefix);\n const query = qs.toString();\n return this.request(`/agent/sync/files${query ? `?${query}` : \"\"}`);\n }\n\n async syncListSessions(): Promise<{ sessions: SyncSessionEntry[] }> {\n return this.request(\"/agent/sync/sessions\");\n }\n\n async syncGetSession(sessionId: string): Promise<SyncSessionContent> {\n return this.request(`/agent/sync/sessions/${encodeURIComponent(sessionId)}`);\n }\n\n async syncDeleteFile(filePath: string): Promise<{ removed: boolean }> {\n return this.request(`/agent/sync/files/${encodeFilePath(filePath)}`, {\n method: \"DELETE\",\n });\n }\n\n // ─── Shared (org/team/project) files ─────────────────────\n //\n // Used by the sync plugin's shared-sync engine to mirror org-scoped\n // files into the agent's `shared/` directory. Routes live in services/org.\n\n async sharedListFiles(args: {\n scope: \"org\" | \"team\" | \"project\";\n scopeId: string;\n }): Promise<{ files: SharedFileEntry[]; nextCursor: string | null }> {\n return this.request(\n `/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}`,\n );\n }\n\n async sharedDownloadUrl(args: {\n scope: \"org\" | \"team\" | \"project\";\n scopeId: string;\n filePath: string;\n }): Promise<{ downloadUrl: string; expiresIn: number }> {\n return this.request(\n `/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/download/${encodeFilePath(args.filePath)}`,\n );\n }\n\n async listIntegrations(): Promise<IntegrationInstall[]> {\n return this.request<IntegrationInstall[]>(\"/agent/integrations\");\n }\n\n async getIntegrationConfig(integrationId: string): Promise<IntegrationConfigResult> {\n return this.request<IntegrationConfigResult>(\n `/agent/integrations/${encodeURIComponent(integrationId)}/config`,\n );\n }\n\n async updateIntegrationConfig(\n integrationId: string,\n config: Record<string, unknown>,\n ): Promise<void> {\n await this.request<unknown>(\n `/agent/integrations/${encodeURIComponent(integrationId)}`,\n {\n method: \"PATCH\",\n body: JSON.stringify({ config }),\n },\n );\n }\n\n async installIntegration(\n integrationId: string,\n options?: { version?: string; config?: Record<string, unknown> },\n ): Promise<IntegrationInstall> {\n return this.request<IntegrationInstall>(\"/agent/integrations\", {\n method: \"POST\",\n body: JSON.stringify({\n integrationId,\n version: options?.version,\n config: options?.config,\n }),\n });\n }\n\n async removeIntegration(integrationId: string): Promise<IntegrationInstall> {\n return this.request<IntegrationInstall>(\n `/agent/integrations/${encodeURIComponent(integrationId)}`,\n { method: \"DELETE\" },\n );\n }\n\n async getOAuthUrl(\n provider: string,\n scopes?: string[],\n ): Promise<{ url: string; provider: string; expiresIn: number }> {\n const params = new URLSearchParams({ provider });\n if (scopes?.length) params.set(\"scopes\", scopes.join(\",\"));\n return this.request(`/agent/integrations/oauth/url?${params.toString()}`);\n }\n\n async getOAuthStatus(\n provider: string,\n ): Promise<{ provider: string; connected: boolean; config?: Record<string, string> }> {\n return this.request(\n `/agent/integrations/oauth/status?provider=${encodeURIComponent(provider)}`,\n );\n }\n\n async getRegistry(): Promise<{ integrations: RegistryEntry[] }> {\n return this.request<{ integrations: RegistryEntry[] }>(\"/integrations/registry\");\n }\n\n async getGoogleCredentials(): Promise<{\n accounts?: {\n email: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n enabledServices?: string[];\n isDefault: boolean;\n displayName?: string;\n }[];\n email: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n projectId: string;\n enabledServices?: string[];\n }> {\n return this.request(\"/agent/google/credentials\");\n }\n\n async disconnectGoogleAccount(email: string): Promise<{\n accounts: { email: string; displayName?: string; isDefault: boolean }[];\n }> {\n return this.request(`/agent/google/accounts/${encodeURIComponent(email)}`, {\n method: \"DELETE\",\n });\n }\n\n async setDefaultGoogleAccount(email: string): Promise<{\n accounts: { email: string; displayName?: string; isDefault: boolean }[];\n }> {\n return this.request(`/agent/google/accounts/${encodeURIComponent(email)}/default`, {\n method: \"PUT\",\n });\n }\n\n async getGoogleChatCredentials(): Promise<{\n email: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n displayName?: string;\n }> {\n return this.request(\"/agent/google-chat/credentials\");\n }\n\n async getGithubCredentials(): Promise<{\n login: string;\n accessToken: string;\n }> {\n return this.request(\"/agent/github/credentials\");\n }\n\n async getXeroCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n xeroTenantId: string;\n }> {\n return this.request(\"/agent/xero/credentials\");\n }\n\n async refreshXeroToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/xero/token\", { method: \"POST\" });\n }\n\n async getNotionCredentials(): Promise<{\n accessToken: string;\n workspaceId: string;\n workspaceName: string;\n }> {\n return this.request(\"/agent/notion/credentials\");\n }\n\n async getAtlassianCredentials(): Promise<{\n accessToken: string;\n refreshToken: string;\n accessTokenExpiresAt: string;\n cloudId: string;\n siteName: string;\n siteUrl: string;\n email: string;\n enabledProducts: string[];\n clientId: string;\n clientSecret: string;\n }> {\n return this.request(\"/agent/atlassian/credentials\");\n }\n\n async refreshAtlassianToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/atlassian/token\", { method: \"POST\" });\n }\n\n async getMYOBCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n myobBusinessId: string;\n clientId: string;\n }> {\n return this.request(\"/agent/myob/credentials\");\n }\n\n async refreshMYOBToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/myob/token\", { method: \"POST\" });\n }\n\n async getTeamsCredentials(): Promise<{\n agentId: string;\n tenantId: string;\n azureAppId: string;\n azureBotId: string;\n azureClientSecret: string;\n botDisplayName?: string;\n teamsTenantId?: string;\n serviceUrl?: string;\n }> {\n return this.request(\"/agent/microsoft/credentials\");\n }\n\n async sendTeamsMessage(data: {\n conversationId: string;\n text?: string;\n adaptiveCard?: Record<string, unknown>;\n }): Promise<{ ok: boolean; activityId: string }> {\n return this.request(\"/agent/microsoft/send\", {\n method: \"POST\",\n body: JSON.stringify(data),\n });\n }\n\n async listTeamsChannels(): Promise<{\n channels: { id: string; name: string; description?: string }[];\n }> {\n return this.request(\"/agent/microsoft/channels\");\n }\n\n async presignAttachments(files: { filename: string; mimeType: string; size: number }[]): Promise<{\n attachments: { id: string; uploadUrl: string; downloadUrl: string; s3Key: string; expiresAt: string }[];\n }> {\n return this.request(\"/agent/chat/attachments/presign\", {\n method: \"POST\",\n body: JSON.stringify({ files }),\n });\n }\n\n async recordActivity(data: {\n userId?: string;\n channel: string;\n role: \"user\" | \"assistant\";\n }): Promise<{ recorded: boolean }> {\n return this.request<{ recorded: boolean }>(\"/agent/activity\", {\n method: \"POST\",\n body: JSON.stringify(data),\n });\n }\n\n // ─── Secrets ──────────────────────────────────────────────────\n //\n // Envelope CRUD + KMS proxy for per-scope encrypted secret storage.\n // Agents never hold a KMS master key — these proxy endpoints mint one-shot\n // AES-256 data keys bound (via KMS encryption context) to\n // `{ tenantId, scope, scopeId, secretId }`. The agent performs AES-256-GCM\n // locally; the backend only ever sees opaque envelopes.\n //\n // Routes resolve to the agent API gateway (mapping key `agent`), where\n // services/secrets registers its routes with pathPrefix `/secrets`. With\n // `apiUrl` set to the host root (e.g. `https://api.alfe.ai`), the full URL\n // is `https://api.alfe.ai/agent/secrets/...`. This is the same mapping as\n // `/agent/integrations/...` etc. — do NOT hit `/secrets/...` on the root\n // host: that's the user-auth dashboard gateway, which rejects agent tokens.\n //\n // `plaintextKey` in responses is base64 — callers MUST decode to a Node\n // `Buffer` immediately and zero it after use. NEVER keep plaintext keys\n // as JS strings (strings are immutable and cannot be wiped).\n\n /**\n * Mint a fresh AES-256 data key for a specific (secret, field) pair. The\n * encryption context is rebuilt server-side from `auth.tenantId` + the body\n * fields including `fieldKey`; the agent cannot forge context for a scope\n * or field it doesn't own. Legacy single-envelope secrets are migrated to\n * `field#value` rows by the data migration, so call with `fieldKey: \"value\"`\n * to reach them.\n */\n async generateSecretDataKey(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<GeneratedDataKey> {\n return this.request<GeneratedDataKey>(\"/agent/secrets/generate-data-key\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Unwrap a wrapped data key so the agent can decrypt the envelope locally.\n * `fieldKey` MUST match the value supplied when the data key was generated\n * (it's bound into KMS encryption context); mismatch fails with\n * `InvalidCiphertextException`.\n */\n async decryptSecretDataKey(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n dataKeyCiphertext: string;\n }): Promise<{ plaintextKey: string }> {\n return this.request<{ plaintextKey: string }>(\"/agent/secrets/decrypt-data-key\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Create a new secret with one or more fields. Encrypted fields must arrive\n * pre-sealed (the agent has already obtained per-field data keys via\n * `generateSecretDataKey({ ..., fieldKey })` and AES-encrypted locally).\n * Plaintext fields ship the value inline.\n */\n async createSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n secretName: string;\n category?: SecretCategory;\n description?: string;\n tags?: string[];\n fields: {\n key: string;\n format?: FieldFormat;\n sensitivity: FieldSensitivity;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n }[];\n reason?: string;\n }): Promise<SecretAggregate> {\n const { scope, scopeId, secretId, ...body } = args;\n return this.request<SecretAggregate>(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}`,\n {\n method: \"PUT\",\n body: JSON.stringify(body),\n },\n );\n }\n\n /** Fetch the secret aggregate plus per-field encrypted envelopes. */\n async getSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n }): Promise<{ aggregate: SecretAggregate; envelopes: FieldEnvelope[] }> {\n return this.request<{ aggregate: SecretAggregate; envelopes: FieldEnvelope[] }>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}`,\n );\n }\n\n /** Fetch one field. Plaintext: value inline. Encrypted: envelope. */\n async getSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<{\n key: string;\n sensitivity: FieldSensitivity;\n format?: FieldFormat;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n rotatedAt?: string;\n createdAt: string;\n updatedAt: string;\n }> {\n return this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/fields/${encodeURIComponent(args.fieldKey)}`,\n );\n }\n\n /** Add OR rotate one field. */\n async setSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n sensitivity: FieldSensitivity;\n format?: FieldFormat;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n reason?: string;\n }): Promise<{ fieldKey: string; rotated: boolean }> {\n const { scope, scopeId, secretId, fieldKey, ...body } = args;\n return this.request(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}/fields/${encodeURIComponent(fieldKey)}`,\n { method: \"PUT\", body: JSON.stringify(body) },\n );\n }\n\n /** Remove one field. */\n async removeSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<void> {\n await this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/fields/${encodeURIComponent(args.fieldKey)}`,\n { method: \"DELETE\" },\n );\n }\n\n /** Update secret-level metadata (name/description/tags/category). */\n async updateSecretMetadata(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n secretName?: string;\n description?: string;\n tags?: string[];\n category?: SecretCategory;\n reason?: string;\n }): Promise<SecretAggregate> {\n const { scope, scopeId, secretId, ...body } = args;\n return this.request<SecretAggregate>(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}`,\n { method: \"PATCH\", body: JSON.stringify(body) },\n );\n }\n\n /** List metadata for secrets in a scope. Optional filters route through the byFacet GSI. */\n async listSecrets(args: {\n scope: SecretScope;\n scopeId: string;\n category?: SecretCategory;\n tag?: string;\n fieldKey?: string;\n }): Promise<SecretMetadata[]> {\n const params = new URLSearchParams();\n if (args.category) params.set(\"category\", args.category);\n if (args.tag) params.set(\"tag\", args.tag);\n if (args.fieldKey) params.set(\"fieldKey\", args.fieldKey);\n const qs = params.toString();\n const resp = await this.request<{ secrets: SecretMetadata[] }>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}${qs ? `?${qs}` : \"\"}`,\n );\n return resp.secrets;\n }\n\n /** Bounded changelog read — metadata-only audit entries. */\n async getSecretHistory(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n limit?: number;\n cursor?: string;\n }): Promise<{ entries: ChangelogEntry[]; nextCursor?: string }> {\n const params = new URLSearchParams();\n if (args.limit) params.set(\"limit\", String(args.limit));\n if (args.cursor) params.set(\"cursor\", args.cursor);\n const qs = params.toString();\n return this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/history${qs ? `?${qs}` : \"\"}`,\n );\n }\n\n /** Delete a secret (and all its field rows + tag rows + changelog rows). */\n async deleteSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n }): Promise<void> {\n await this.request<unknown>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}`,\n { method: \"DELETE\" },\n );\n }\n\n /** Enumerate scopes (org/team/project/agent) this agent can access. */\n async listSecretScopes(): Promise<ScopeInfo[]> {\n const resp = await this.request<{ scopes: ScopeInfo[] }>(\"/agent/secrets/scopes\");\n return resp.scopes;\n }\n\n // ─── Identity ─────────────────────────────────────────────\n //\n // Identity resolution, permission enforcement, and CRM tools.\n // The agent API derives tenantId + agentId from the agent token.\n\n /**\n * Returns the calling agent's own identity context — `{ agentId, tenantId }`\n * decoded server-side from the agent API token. Used by the\n * `@alfe.ai/openclaw-identity` plugin to bootstrap context when the\n * OpenClaw daemon doesn't plumb `ctx.agentId` through to plugin hooks.\n * Plugins should cache this for the daemon's lifetime (single-agent-per-\n * process invariant). One HTTP round-trip per process activate; not for\n * per-call use.\n */\n async whoami(): Promise<{ agentId: string; tenantId: string }> {\n return this.request(\"/agent/identity/whoami\");\n }\n\n async resolveIdentity(args: {\n provider: string;\n platformId: string;\n kind?: \"user\" | \"agent\" | \"service\" | \"bot\" | \"workspace\";\n displayName?: string;\n }): Promise<{\n identityId: string | null;\n status: string;\n created?: boolean;\n reason?: string;\n /**\n * Flattened auriclabs permission strings for the resolved identity\n * (scope-prefixed where applicable). Empty array on miss / org service\n * outage — the runtime gate fails closed in that case.\n */\n permissions: string[];\n }> {\n return this.request(\"/agent/identity/resolve\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async searchIdentities(args?: {\n q?: string;\n status?: string;\n limit?: number;\n }): Promise<{ identities: unknown[] }> {\n const qs = new URLSearchParams();\n if (args?.q) qs.set(\"q\", args.q);\n if (args?.status) qs.set(\"status\", args.status);\n if (args?.limit) qs.set(\"limit\", String(args.limit));\n const query = qs.toString();\n return this.request(`/agent/identity/search${query ? `?${query}` : \"\"}`);\n }\n\n async getIdentityContext(identityId: string): Promise<{\n context: unknown;\n }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/context`);\n }\n\n async mergeIdentities(survivorId: string, args: {\n mergedId: string;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; error?: string }> {\n return this.request(`/agent/identity/${encodeURIComponent(survivorId)}/merge`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async unmergeIdentity(identityId: string, args: {\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; error?: string }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/unmerge`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async addIdentityNote(identityId: string, args: {\n content: string;\n category?: string;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ noteId: string | null }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/notes`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async tagIdentity(identityId: string, args: {\n tag: string;\n action: \"add\" | \"remove\";\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/tags`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async getIdentityChangelog(identityId: string, args?: {\n limit?: number;\n }): Promise<{ entries: unknown[] }> {\n const qs = new URLSearchParams();\n if (args?.limit) qs.set(\"limit\", String(args.limit));\n const query = qs.toString();\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/changelog${query ? `?${query}` : \"\"}`);\n }\n\n async rollbackIdentity(identityId: string, args: {\n targetVersion: number;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; entry?: unknown }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/rollback`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async requestIdentityVerification(args: {\n claimedIdentityId: string;\n requestingIdentityId: string;\n requestingProvider: string;\n requestingPlatformId: string;\n preferredChannel?: \"mobile\" | \"email\";\n /**\n * Phase 2: agent-supplied contact endpoint. When provided, the top-level\n * `preferredChannel` is ignored — the contact's channel wins.\n */\n contact?: { channel: \"email\" | \"mobile\"; value: string };\n }): Promise<{\n verificationId: string;\n channel: string;\n deliveredTo: string;\n expiresAt: string;\n availableChannels: { channel: string; deliveredTo: string }[];\n } | { error: string }> {\n return this.request(\"/agent/identity/verify/request\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async confirmIdentityVerification(args: {\n claimedIdentityId: string;\n verificationId: string;\n phrase: string;\n }): Promise<{\n verified: boolean;\n identityId?: string;\n /** Phase 2: how the confirm resolved — Scenario A vs B. */\n action?: \"merged\" | \"contact_verified\";\n error?: string;\n }> {\n return this.request(\"/agent/identity/verify/confirm\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Update display-shape fields on an Identity. Body excludes `email` /\n * `phone` / `title` / `company` / `metadata` per Section D4 — contacts go\n * via the verify flow, title/company live on OrgMembership, metadata is\n * not agent-writable.\n */\n async updateIdentity(\n identityId: string,\n args: {\n name?: string;\n avatarUrl?: string;\n timezone?: string;\n locale?: string;\n },\n ): Promise<{ ok: boolean }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/update`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Phase 2 (Section H): server-side verification of a Google Chat sender via\n * the agent's existing Google OAuth credentials. Returns the resolved\n * identity (created or matched via Scenario-B email enrichment).\n */\n async resolveGoogleChatSender(args: {\n senderUserId: string;\n spaceId?: string;\n }): Promise<{\n identityId: string | null;\n status: string;\n }> {\n return this.request(\"/agent/google/resolve-sender\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n // ─── Memory ──────────────────────────────────────────────\n //\n // Cloud memory (Turbopuffer vectors + DynamoDB knowledge graph).\n // The agent API derives tenantId + agentId from the agent token.\n\n async memorySearch(query: string, opts?: {\n limit?: number;\n topic?: string;\n subtopic?: string;\n tag?: string;\n includeKnowledge?: boolean;\n }): Promise<{\n facts: { subject: string; predicate: string; object: string; since: string; confidence: number }[];\n memories: { id: string; text: string; topic: string; subtopic: string; tag: string; importance: number; timestamp: number; score: number }[];\n }> {\n return this.request(\"/agent/memory/search\", {\n method: \"POST\",\n body: JSON.stringify({\n query,\n limit: opts?.limit ?? 10,\n topic: opts?.topic,\n subtopic: opts?.subtopic,\n tag: opts?.tag,\n includeKnowledge: opts?.includeKnowledge ?? true,\n }),\n });\n }\n\n async memoryStore(text: string, opts?: {\n topic?: string;\n subtopic?: string;\n tag?: string;\n importance?: number;\n }): Promise<{ memoryId: string }> {\n return this.request(\"/agent/memory/store\", {\n method: \"POST\",\n body: JSON.stringify({\n text,\n topic: opts?.topic ?? \"general\",\n subtopic: opts?.subtopic ?? \"general\",\n tag: opts?.tag ?? \"fact\",\n importance: opts?.importance ?? 0.7,\n }),\n });\n }\n\n async memoryIngest(sessionKey: string, messages: {\n role: string;\n content: string;\n index: number;\n timestamp?: string;\n }[], metadata?: {\n channelId?: string;\n userId?: string;\n userName?: string;\n }): Promise<{ queued: boolean; messageCount: number }> {\n return this.request(\"/agent/memory/ingest\", {\n method: \"POST\",\n body: JSON.stringify({\n sessionKey,\n lastProcessedIndex: messages.length > 0 ? messages[messages.length - 1].index : -1,\n messages,\n metadata,\n }),\n });\n }\n\n async memoryLoadContext(tier?: number, topicHint?: string): Promise<{\n formatted: string;\n [key: string]: unknown;\n }> {\n const params = new URLSearchParams();\n if (tier !== undefined) params.set(\"tier\", String(tier));\n if (topicHint) params.set(\"topicHint\", topicHint);\n const qs = params.toString();\n return this.request(`/agent/memory/context${qs ? `?${qs}` : \"\"}`);\n }\n\n async memoryLookupEntity(subject: string): Promise<{\n subject: string;\n triples: { tripleId: string; predicate: string; object: string; validFrom: string; validTo?: string; confidence: number }[];\n }> {\n return this.request(`/agent/memory/knowledge/entities?subject=${encodeURIComponent(subject)}`);\n }\n\n async memoryNavigate(): Promise<{\n topics: { name: string; tripleCount: number; subtopics: string[] }[];\n cursor: string | null;\n }> {\n return this.request(\"/agent/memory/navigate\");\n }\n\n async memoryDelete(memoryId: string): Promise<{ deleted: boolean }> {\n return this.request(`/agent/memory/${encodeURIComponent(memoryId)}`, {\n method: \"DELETE\",\n });\n }\n\n async memoryStats(): Promise<{\n vectorCount: number;\n tripleCount: number;\n storageEstimateBytes: number;\n lastIngestionAt?: string;\n }> {\n return this.request(\"/agent/memory/stats\");\n }\n\n async memoryLearn(args: {\n text: string;\n source?: string;\n sourceType?: \"file\" | \"url\" | \"inline\";\n metadata?: { sessionId?: string; channelId?: string; userName?: string };\n }): Promise<{\n memoriesStored: number;\n triplesStored: number;\n chunks: number;\n source?: string;\n }> {\n return this.request(\"/agent/memory/learn\", {\n method: \"POST\",\n body: JSON.stringify({\n text: args.text,\n source: args.source,\n sourceType: args.sourceType ?? \"inline\",\n metadata: args.metadata,\n }),\n });\n }\n\n async memoryBootstrapStatus(): Promise<{ synced: boolean; syncedAt?: string }> {\n return this.request(\"/agent/memory/bootstrap-status\");\n }\n\n async memoryBootstrapStatusMark(): Promise<{ synced: true; syncedAt: string }> {\n return this.request(\"/agent/memory/bootstrap-status\", { method: \"POST\" });\n }\n\n // ─── Search ──────────────────────────────────────────────\n\n async searchWeb(params: {\n query: string;\n count?: number;\n offset?: number;\n country?: string;\n freshness?: string;\n }): Promise<unknown> {\n return this.request(\"/agent/search/web\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n async searchImages(params: {\n query: string;\n count?: number;\n }): Promise<unknown> {\n return this.request(\"/agent/search/images\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n async searchNews(params: {\n query: string;\n count?: number;\n freshness?: string;\n }): Promise<unknown> {\n return this.request(\"/agent/search/news\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n // ─── Database ───────────────────────────────────────────\n\n async registerDatabaseCredentials(): Promise<{\n connectionString: string;\n username: string;\n password: string;\n databases: string[];\n }> {\n return this.request(\"/agent/database/register\", { method: \"POST\" });\n }\n\n async reportDatabaseAudit(entry: {\n database: string;\n collection: string;\n operation: string;\n summary?: string;\n }): Promise<void> {\n await this.request(\"/agent/database/audit\", {\n method: \"POST\",\n body: JSON.stringify(entry),\n }).catch(() => {\n // Fire and forget — audit failure doesn't affect operations\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @alfe.ai/agent-api-client — Agent self-service API client.\n *\n * Used by agents calling /agent/ endpoints. The agent authenticates\n * with its API key — the backend resolves agentId + tenantId from the token.\n * No agent ID needed in paths or config.\n */\n\nexport type {\n IntegrationInstall,\n IntegrationConfigResult,\n RegistryEntry,\n IntegrationConfigSchemaField,\n SecretScope,\n EncryptedEnvelopeV1,\n SecretMetadata,\n SecretAggregate,\n Field,\n FieldFormat,\n FieldSensitivity,\n FieldView,\n FieldEnvelope,\n SecretCategory,\n ChangelogEntry,\n ChangelogAction,\n ChangelogActor,\n ScopeInfo,\n GeneratedDataKey,\n} from \"@alfe/types\";\n\nimport type {\n IntegrationInstall,\n IntegrationConfigResult,\n RegistryEntry,\n SecretScope,\n EncryptedEnvelopeV1,\n SecretMetadata,\n SecretAggregate,\n FieldFormat,\n FieldSensitivity,\n FieldEnvelope,\n SecretCategory,\n ChangelogEntry,\n ScopeInfo,\n GeneratedDataKey,\n} from \"@alfe/types\";\n\nexport interface AgentApiClientConfig {\n apiKey: string;\n apiUrl: string;\n}\n\n// ─── Sync types ──────────────────────────────────────────\n\nexport interface SyncAgentInfo {\n agentId: string;\n tenantId: string;\n displayName: string;\n s3Prefix: string;\n status: \"stale\" | \"syncing\" | \"synced\";\n fileCount?: number;\n totalSize?: number;\n lastSync?: string;\n}\n\nexport interface SyncManifestEntry {\n hash: string;\n size: number;\n modified: string;\n etag?: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncManifest {\n version: 1;\n agentId: string;\n lastSync: string;\n files: Record<string, SyncManifestEntry>;\n}\n\nexport interface SyncPresignedUrl {\n path: string;\n url: string;\n expiresAt: string;\n}\n\nexport interface SyncConfirmedUpload {\n filePath: string;\n hash: string;\n size: number;\n storageClass: \"STANDARD\" | \"GLACIER_IR\";\n syncedAt: string;\n}\n\nexport interface SyncReconstructFile {\n path: string;\n size: number;\n url: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncReconstructBundle {\n agentId: string;\n mode: \"full\" | \"active\" | \"memory\";\n fileCount: number;\n totalSize: number;\n files: SyncReconstructFile[];\n expiresAt: string;\n}\n\nexport interface SyncAgentStats {\n agentId: string;\n standardBytes: number;\n glacierBytes: number;\n fileCount: number;\n lastSyncAt: string | null;\n}\n\nexport interface SyncFileEntry {\n filePath: string;\n size: number;\n modified: string;\n contentHash: string;\n storageClass?: string;\n compressed?: boolean;\n}\n\nexport interface SyncSessionEntry {\n sessionId: string;\n size: number;\n lastModified: string;\n storageClass?: string;\n isArchived: boolean;\n}\n\nexport interface SyncSessionContent {\n sessionId: string;\n content: string;\n compressed: boolean;\n}\n\nexport interface SharedFileEntry {\n filePath: string;\n fileName: string;\n size: number;\n contentType?: string;\n}\n\n/**\n * Encode each path segment but keep the `/` separators — `encodeURIComponent`\n * would escape the slashes too, breaking greedy proxy routes.\n */\nfunction encodeFilePath(filePath: string): string {\n return filePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nexport class AgentApiClient {\n private readonly apiKey: string;\n private readonly apiUrl: string;\n\n constructor(config: AgentApiClientConfig) {\n this.apiKey = config.apiKey;\n this.apiUrl = config.apiUrl;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const headers = new Headers(options?.headers);\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"Content-Type\", \"application/json\");\n\n const res = await fetch(url, { ...options, headers });\n\n if (!res.ok) {\n await res.text(); // drain body\n throw new Error(`Agent API request failed (${String(res.status)})`);\n }\n\n const body = (await res.json()) as { data: T };\n return body.data;\n }\n\n // ─── Sync ────────────────────────────────────────────────\n //\n // Workspace backup. The agent only ever calls /agent/sync/* — file\n // bytes go to/from S3 via presigned URLs (S3 fetch is the one\n // legitimate raw-fetch in a plugin). Dashboard editing uses the\n // user-API at /sync/agents/{agentId}/* and is not exposed here.\n\n async syncRegister(args?: { displayName?: string }): Promise<{ agent: SyncAgentInfo }> {\n return this.request(\"/agent/sync/register\", {\n method: \"POST\",\n body: JSON.stringify(args ?? {}),\n });\n }\n\n async syncGetManifest(): Promise<SyncManifest> {\n return this.request(\"/agent/sync/manifest\");\n }\n\n async syncPresign(args: {\n files: { path: string; operation: \"put\" | \"get\"; contentType?: string }[];\n }): Promise<{ urls: SyncPresignedUrl[] }> {\n return this.request(\"/agent/sync/presign\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncConfirmUpload(args: {\n filePath: string;\n hash: string;\n size: number;\n storageClass?: \"STANDARD\" | \"GLACIER_IR\";\n }): Promise<SyncConfirmedUpload> {\n return this.request(\"/agent/sync/confirm\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncReconstruct(args: {\n mode: \"full\" | \"active\" | \"memory\";\n }): Promise<SyncReconstructBundle> {\n return this.request(\"/agent/sync/reconstruct\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async syncGetStats(): Promise<SyncAgentStats> {\n return this.request(\"/agent/sync/stats\");\n }\n\n async syncListFiles(args?: { prefix?: string }): Promise<{ files: SyncFileEntry[] }> {\n const qs = new URLSearchParams();\n if (args?.prefix) qs.set(\"prefix\", args.prefix);\n const query = qs.toString();\n return this.request(`/agent/sync/files${query ? `?${query}` : \"\"}`);\n }\n\n async syncListSessions(): Promise<{ sessions: SyncSessionEntry[] }> {\n return this.request(\"/agent/sync/sessions\");\n }\n\n async syncGetSession(sessionId: string): Promise<SyncSessionContent> {\n return this.request(`/agent/sync/sessions/${encodeURIComponent(sessionId)}`);\n }\n\n async syncDeleteFile(filePath: string): Promise<{ removed: boolean }> {\n return this.request(`/agent/sync/files/${encodeFilePath(filePath)}`, {\n method: \"DELETE\",\n });\n }\n\n // ─── Shared (org/team/project) files ─────────────────────\n //\n // Used by the sync plugin's shared-sync engine to mirror org-scoped\n // files into the agent's `shared/` directory. Routes live in services/org.\n\n async sharedListFiles(args: {\n scope: \"org\" | \"team\" | \"project\";\n scopeId: string;\n }): Promise<{ files: SharedFileEntry[]; nextCursor: string | null }> {\n return this.request(\n `/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}`,\n );\n }\n\n async sharedDownloadUrl(args: {\n scope: \"org\" | \"team\" | \"project\";\n scopeId: string;\n filePath: string;\n }): Promise<{ downloadUrl: string; expiresIn: number }> {\n return this.request(\n `/agent/org/files/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/download/${encodeFilePath(args.filePath)}`,\n );\n }\n\n async listIntegrations(): Promise<IntegrationInstall[]> {\n return this.request<IntegrationInstall[]>(\"/agent/integrations\");\n }\n\n async getIntegrationConfig(integrationId: string): Promise<IntegrationConfigResult> {\n return this.request<IntegrationConfigResult>(\n `/agent/integrations/${encodeURIComponent(integrationId)}/config`,\n );\n }\n\n async updateIntegrationConfig(\n integrationId: string,\n config: Record<string, unknown>,\n ): Promise<void> {\n await this.request<unknown>(\n `/agent/integrations/${encodeURIComponent(integrationId)}`,\n {\n method: \"PATCH\",\n body: JSON.stringify({ config }),\n },\n );\n }\n\n async installIntegration(\n integrationId: string,\n options?: { version?: string; config?: Record<string, unknown> },\n ): Promise<IntegrationInstall> {\n return this.request<IntegrationInstall>(\"/agent/integrations\", {\n method: \"POST\",\n body: JSON.stringify({\n integrationId,\n version: options?.version,\n config: options?.config,\n }),\n });\n }\n\n async removeIntegration(integrationId: string): Promise<IntegrationInstall> {\n return this.request<IntegrationInstall>(\n `/agent/integrations/${encodeURIComponent(integrationId)}`,\n { method: \"DELETE\" },\n );\n }\n\n async getOAuthUrl(\n provider: string,\n scopes?: string[],\n ): Promise<{ url: string; provider: string; expiresIn: number }> {\n const params = new URLSearchParams({ provider });\n if (scopes?.length) params.set(\"scopes\", scopes.join(\",\"));\n return this.request(`/agent/integrations/oauth/url?${params.toString()}`);\n }\n\n async getOAuthStatus(\n provider: string,\n ): Promise<{ provider: string; connected: boolean; config?: Record<string, string> }> {\n return this.request(\n `/agent/integrations/oauth/status?provider=${encodeURIComponent(provider)}`,\n );\n }\n\n async getRegistry(): Promise<{ integrations: RegistryEntry[] }> {\n return this.request<{ integrations: RegistryEntry[] }>(\"/integrations/registry\");\n }\n\n /**\n * Returns every connected Google account for the agent. Multi-account by\n * design — the openclaw-google plugin requires the LLM to pass `email`\n * explicitly to `google_run_command` so an account is always selected\n * deliberately.\n *\n * 2026-05-14 (connections-redesign PR 1): the legacy flat shape (`email`,\n * `refreshToken`, `accessToken`, etc., populated from the default account)\n * is gone. Iterate over `accounts`.\n */\n async getGoogleCredentials(): Promise<{\n accounts: {\n email: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n displayName?: string;\n connectedAt?: string;\n }[];\n }> {\n const raw = await this.request<{\n provider: string;\n accounts: {\n accountIdentifier: string;\n accessToken?: string;\n refreshToken?: string;\n clientId?: string;\n clientSecret?: string;\n workspaceDomain?: string;\n displayName?: string | null;\n connectedAt?: string;\n }[];\n }>(\"/agent/connect/google/accounts\");\n\n return {\n accounts: raw.accounts.map((a) => ({\n email: a.accountIdentifier,\n refreshToken: a.refreshToken ?? \"\",\n clientId: a.clientId ?? \"\",\n clientSecret: a.clientSecret ?? \"\",\n displayName: a.displayName ?? undefined,\n connectedAt: a.connectedAt,\n })),\n };\n }\n\n async disconnectGoogleAccount(email: string): Promise<{\n accounts: { email: string; displayName?: string; connectedAt?: string }[];\n }> {\n const raw = await this.request<{\n accounts: { accountIdentifier: string; displayName?: string | null; connectedAt?: string }[];\n }>(`/agent/connect/google/accounts/${encodeURIComponent(email)}`, {\n method: \"DELETE\",\n });\n return {\n accounts: raw.accounts.map((a) => ({\n email: a.accountIdentifier,\n displayName: a.displayName ?? undefined,\n connectedAt: a.connectedAt,\n })),\n };\n }\n\n async getGoogleChatCredentials(): Promise<{\n email: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n displayName?: string;\n }> {\n return this.request(\"/agent/google-chat/credentials\");\n }\n\n /**\n * @deprecated Returns a single primary credential blob (legacy \"pick-the-\n * default-connection\" shape). Use `getGithubAccounts()` for the multi-\n * account shape required by Pattern A — explicit selector args on every\n * tool. Retained because the `@alfe.ai/openclaw-github` proxy is the\n * only consumer that knows about Pattern A; legacy env-interpolation\n * callers will keep hitting `/credentials` until they move to the proxy.\n */\n async getGithubCredentials(): Promise<{\n login: string;\n accessToken: string;\n }> {\n // GitHub lives on services/connect's universal credential endpoint\n // since the cutover. Connect's `buildCredentialsResponse` returns\n // `{ accessToken, scopes, login }`; we project to the historical\n // shape so callers don't need to know which path served it.\n const raw = await this.request<{\n accessToken: string;\n login: string;\n scopes?: string;\n }>(\"/agent/connect/github/credentials\");\n return { login: raw.login, accessToken: raw.accessToken };\n }\n\n /**\n * Pattern A: multi-account credential fetch for GitHub.\n *\n * Returns every agent-scoped GitHub connection. The caller is expected\n * to require a `login` selector on every credential-touching tool and\n * look up the matching account at dispatch time.\n *\n * GitHub OAuth tokens have no expiry (`tokenLifecycle: \"no_expiry\"`),\n * so there is intentionally no `refreshGithubAccountToken` method — if\n * a token is revoked the user must re-run the OAuth flow.\n *\n * Returned `accounts[i].login` is the GitHub username — the stable\n * cross-session identifier the LLM should pass.\n */\n async getGithubAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n login: string;\n scopes: string;\n }[];\n }> {\n const raw = await this.request<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken?: string;\n login?: string;\n scopes?: string;\n }[];\n }>(\"/agent/connect/github/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken ?? \"\",\n login: a.login ?? a.accountIdentifier,\n scopes: a.scopes ?? \"\",\n })),\n };\n }\n\n /**\n * @deprecated Returns a single primary credential blob (legacy \"pick-the-\n * default-connection\" shape). Use `getXeroAccounts()` for the multi-\n * account shape required by Pattern A — explicit selector args on every\n * tool. This method will be removed once all consumers migrate.\n */\n async getXeroCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n xeroTenantId: string;\n }> {\n // Xero lives on services/connect since the cutover.\n const raw = await this.request<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n xeroTenantId?: string;\n }>(\"/agent/connect/xero/credentials\");\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n xeroTenantId: raw.xeroTenantId ?? \"\",\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for Xero. Returns every\n * agent-scoped Xero connection. The caller is expected to require a\n * selector arg (e.g. `xeroTenantId`) on every credential-touching tool\n * and look up the matching account by that selector at dispatch time.\n *\n * Returned `accounts[i].accountIdentifier` is the Xero tenantId — the\n * stable cross-session identifier the LLM should pass.\n */\n async getXeroAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n xeroTenantId: string;\n }[];\n }> {\n const raw = await this.request<{\n provider: string;\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt?: string;\n xeroTenantId?: string;\n }[];\n }>(\"/agent/connect/xero/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken,\n accessTokenExpiresAt: a.accessTokenExpiresAt ?? \"\",\n xeroTenantId: a.xeroTenantId ?? a.accountIdentifier,\n })),\n };\n }\n\n async refreshXeroToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/connect/xero/refresh\", { method: \"POST\" });\n }\n\n /**\n * Pattern A: refresh a specific Xero connection by its `accountIdentifier`\n * (the Xero `tenantId`). The legacy `refreshXeroToken()` only refreshes\n * the *primary* connection, which is wrong for multi-tenant Xero where\n * each tenant has its own non-interchangeable access token.\n */\n async refreshXeroAccountToken(xeroTenantId: string): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n expiresAt: string;\n }> {\n const path = `/agent/connect/xero/accounts/${encodeURIComponent(xeroTenantId)}/refresh`;\n const raw = await this.request<{\n accountIdentifier: string;\n accessToken: string;\n accessTokenExpiresAt?: string;\n expiresAt?: string;\n }>(path, { method: \"POST\" });\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n expiresAt: raw.expiresAt ?? \"\",\n };\n }\n\n /**\n * @deprecated Returns a single primary credential blob (legacy \"pick-the-\n * default-connection\" shape). Use `getNotionAccounts()` for the multi-\n * account shape required by Pattern A.\n */\n async getNotionCredentials(): Promise<{\n accessToken: string;\n workspaceId: string;\n workspaceName: string;\n }> {\n // Notion lives on services/connect since the cutover.\n const raw = await this.request<{\n accessToken: string;\n workspaceId?: string;\n workspaceName?: string;\n botId?: string;\n }>(\"/agent/connect/notion/credentials\");\n return {\n accessToken: raw.accessToken,\n workspaceId: raw.workspaceId ?? \"\",\n workspaceName: raw.workspaceName ?? \"\",\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for Notion. Returns every\n * agent-scoped Notion connection. The caller is expected to require a\n * selector arg (e.g. `workspaceId`) on every credential-touching tool.\n *\n * Returned `accounts[i].accountIdentifier` is the Notion workspaceId.\n */\n async getNotionAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n workspaceId: string;\n workspaceName: string;\n }[];\n }> {\n const raw = await this.request<{\n provider: string;\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n workspaceId?: string;\n workspaceName?: string;\n botId?: string;\n }[];\n }>(\"/agent/connect/notion/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken,\n workspaceId: a.workspaceId ?? a.accountIdentifier,\n workspaceName: a.workspaceName ?? a.displayName ?? \"\",\n })),\n };\n }\n\n /**\n * @deprecated Returns a single primary Atlassian Connection's credentials\n * (one OAuth user, one cloudId) — the legacy \"pick-the-default-connection\"\n * shape. Atlassian is multi-site by nature (each OAuth user may have\n * access to multiple Cloud sites), so Pattern A plugins MUST use\n * `getAtlassianAccounts()` to discover the full set and dispatch via\n * the `cloudId` selector arg.\n */\n async getAtlassianCredentials(): Promise<{\n accessToken: string;\n refreshToken: string;\n accessTokenExpiresAt: string;\n cloudId: string;\n siteName: string;\n siteUrl: string;\n email: string;\n enabledProducts: string[];\n clientId: string;\n clientSecret: string;\n }> {\n // Atlassian lives on services/connect since the cutover.\n const raw = await this.request<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n clientId: string;\n clientSecret: string;\n cloudId?: string;\n siteName?: string;\n siteUrl?: string;\n }>(\"/agent/connect/atlassian/credentials\");\n return {\n accessToken: raw.accessToken,\n refreshToken: \"\", // refresh now happens via /agent/connect/atlassian/refresh\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n cloudId: raw.cloudId ?? \"\",\n siteName: raw.siteName ?? \"\",\n siteUrl: raw.siteUrl ?? \"\",\n email: \"\",\n enabledProducts: [],\n clientId: raw.clientId,\n clientSecret: raw.clientSecret,\n };\n }\n\n async refreshAtlassianToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/connect/atlassian/refresh\", { method: \"POST\" });\n }\n\n /**\n * Pattern A: multi-account / multi-site credential fetch for Atlassian.\n *\n * Returns every agent-scoped Atlassian Connection. Each Connection is\n * one OAuth user with a single access token and N accessible Cloud\n * sites (`availableSites`). The caller is expected to:\n *\n * 1. Flatten (connection × cloudId) into one MCP child per site.\n * 2. Require a `cloudId` selector on every credential-touching tool.\n * 3. Use the access token bound to the Connection that owns the\n * requested `cloudId` (Atlassian shares one access token across\n * all sites accessible to the OAuth user).\n *\n * Per-account token refresh uses `refreshAtlassianAccountToken(email)`\n * — refreshing one Connection rotates its single access token, which\n * then applies to every cloudId for that Connection.\n *\n * Returned `accounts[i].accountIdentifier` is the OAuth user's email\n * — the stable cross-session identifier for refresh purposes. The LLM\n * never sees this directly: it picks a site via the `cloudId` arg\n * instead.\n */\n async getAtlassianAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n clientId: string;\n clientSecret: string;\n cloudId: string;\n siteName: string;\n siteUrl: string;\n availableSites: {\n id: string;\n url: string;\n name: string;\n scopes?: string[];\n avatarUrl?: string;\n }[];\n }[];\n }> {\n const raw = await this.request<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken?: string;\n accessTokenExpiresAt?: string;\n clientId?: string;\n clientSecret?: string;\n cloudId?: string;\n siteName?: string;\n siteUrl?: string;\n availableSites?: {\n id: string;\n url: string;\n name: string;\n scopes?: string[];\n avatarUrl?: string;\n }[];\n }[];\n }>(\"/agent/connect/atlassian/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken ?? \"\",\n accessTokenExpiresAt: a.accessTokenExpiresAt ?? \"\",\n clientId: a.clientId ?? \"\",\n clientSecret: a.clientSecret ?? \"\",\n cloudId: a.cloudId ?? \"\",\n siteName: a.siteName ?? \"\",\n siteUrl: a.siteUrl ?? \"\",\n availableSites: a.availableSites ?? [],\n })),\n };\n }\n\n /**\n * Pattern A: refresh a specific Atlassian Connection by `accountIdentifier`\n * (the OAuth user's email).\n *\n * Atlassian rotates refresh tokens (`rotatesRefreshToken: true`); the\n * server-side per-account refresh endpoint handles rotation and\n * persistence. Refreshing one Connection updates its single access\n * token, which applies to every accessible Cloud site (cloudId) for\n * that OAuth user.\n *\n * Returns the new access token + expiry. The proxy is responsible for\n * fanning the new token out to every child server it spawned for\n * cloudIds owned by this Connection.\n */\n async refreshAtlassianAccountToken(accountIdentifier: string): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n expiresAt: string;\n }> {\n const path = `/agent/connect/atlassian/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;\n const raw = await this.request<{\n accountIdentifier: string;\n accessToken: string;\n accessTokenExpiresAt?: string;\n expiresAt?: string;\n }>(path, { method: \"POST\" });\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n expiresAt: raw.expiresAt ?? \"\",\n };\n }\n\n /**\n * @deprecated Returns a single primary credential blob (legacy \"pick-the-\n * default-connection\" shape). Use `getMYOBAccounts()` for the multi-\n * account shape required by Pattern A.\n */\n async getMYOBCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n myobBusinessId: string;\n clientId: string;\n }> {\n // MYOB lives on services/connect since the cutover.\n const raw = await this.request<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n clientId: string;\n myobBusinessId: string;\n myobBusinessName?: string;\n }>(\"/agent/connect/myob/credentials\");\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n myobBusinessId: raw.myobBusinessId,\n clientId: raw.clientId,\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for MYOB. Returns every\n * agent-scoped MYOB connection. The caller is expected to require a\n * selector arg (e.g. `myobBusinessId` / `accountIdentifier`) on every\n * credential-touching tool.\n *\n * Returned `accounts[i].accountIdentifier` is the MYOB businessId.\n */\n async getMYOBAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n myobBusinessId: string;\n clientId: string;\n }[];\n }> {\n const raw = await this.request<{\n provider: string;\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt?: string;\n clientId: string;\n myobBusinessId?: string;\n myobBusinessName?: string;\n }[];\n }>(\"/agent/connect/myob/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken,\n accessTokenExpiresAt: a.accessTokenExpiresAt ?? \"\",\n myobBusinessId: a.myobBusinessId ?? a.accountIdentifier,\n clientId: a.clientId,\n })),\n };\n }\n\n async refreshMYOBToken(): Promise<{\n accessToken: string;\n expiresAt: string;\n }> {\n return this.request(\"/agent/connect/myob/refresh\", { method: \"POST\" });\n }\n\n /**\n * Microsoft 365 (delegated OAuth) credential fetch — single-account shape.\n *\n * @deprecated Use `getMicrosoftAccounts()` and dispatch via the `email`\n * selector once per-account plugins land. Retained because the existing\n * `integrations/connect/microsoft/hooks/post_activate.mjs` writes\n * `mgc` credentials for the single (default) Microsoft account.\n *\n * Returns the agent's effective Microsoft delegated-OAuth credentials.\n * Distinct from `getTeamsCredentials()` (Azure bot credentials for the\n * Teams adapter, which is admin-consent flow on services/microsoft, not\n * delegated OAuth on services/connect).\n */\n async getMicrosoftCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n email?: string;\n microsoftTenantId?: string;\n workspaceDomain?: string;\n }> {\n const raw = await this.request<{\n accessToken?: string;\n accessTokenExpiresAt?: string;\n refreshToken?: string;\n clientId?: string;\n clientSecret?: string;\n accountIdentifier?: string;\n email?: string;\n microsoftTenantId?: string;\n workspaceDomain?: string;\n }>(\"/agent/connect/microsoft/credentials\");\n return {\n accessToken: raw.accessToken ?? \"\",\n accessTokenExpiresAt: raw.accessTokenExpiresAt,\n refreshToken: raw.refreshToken ?? \"\",\n clientId: raw.clientId ?? \"\",\n clientSecret: raw.clientSecret ?? \"\",\n email: raw.email ?? raw.accountIdentifier,\n microsoftTenantId: raw.microsoftTenantId,\n workspaceDomain: raw.workspaceDomain,\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for Microsoft 365.\n *\n * Returns every agent-scoped Microsoft connection. The caller is expected\n * to require an `email` selector on every credential-touching tool and\n * look up the matching account at dispatch time.\n *\n * Returned `accounts[i].accountIdentifier` is the user's primary email\n * (or the tid claim as fallback) — the stable cross-session identifier\n * the LLM should pass.\n *\n * Per-account token refresh is exposed via `refreshMicrosoftAccountToken`,\n * NOT `refreshXeroAccountToken` — Microsoft refresh tokens are not\n * interchangeable across (tenant, user) pairs.\n */\n async getMicrosoftAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n refreshToken: string;\n clientId: string;\n clientSecret: string;\n email: string;\n microsoftTenantId: string;\n workspaceDomain: string;\n }[];\n }> {\n const raw = await this.request<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken?: string;\n accessTokenExpiresAt?: string;\n refreshToken?: string;\n clientId?: string;\n clientSecret?: string;\n email?: string;\n microsoftTenantId?: string;\n workspaceDomain?: string;\n }[];\n }>(\"/agent/connect/microsoft/accounts\");\n return {\n accounts: raw.accounts.map((a) => ({\n connectionId: a.connectionId,\n accountIdentifier: a.accountIdentifier,\n displayName: a.displayName,\n connectedAt: a.connectedAt,\n accessToken: a.accessToken ?? \"\",\n accessTokenExpiresAt: a.accessTokenExpiresAt ?? \"\",\n refreshToken: a.refreshToken ?? \"\",\n clientId: a.clientId ?? \"\",\n clientSecret: a.clientSecret ?? \"\",\n email: a.email ?? a.accountIdentifier,\n microsoftTenantId: a.microsoftTenantId ?? \"\",\n workspaceDomain: a.workspaceDomain ?? \"\",\n })),\n };\n }\n\n /**\n * Pattern A: refresh a specific Microsoft 365 connection by its\n * `accountIdentifier`. For Microsoft, `accountIdentifier` is the user's\n * email when the Graph profile fetch succeeded at connect time, and the\n * Azure tenant id (`tid` claim) as fallback. Callers should pass the\n * value returned by `getMicrosoftAccounts()` rather than synthesising\n * an email locally.\n *\n * Microsoft refresh tokens are bound to a specific (tenant, user) pair —\n * they are NOT interchangeable across accounts, so per-account refresh\n * is mandatory. The generic /accounts/{accountIdentifier}/refresh\n * endpoint walks the agent's full visible scope chain to find a matching\n * connection (works for inherited team/project Microsoft connections).\n */\n async refreshMicrosoftAccountToken(accountIdentifier: string): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n expiresAt: string;\n }> {\n const path = `/agent/connect/microsoft/accounts/${encodeURIComponent(accountIdentifier)}/refresh`;\n const raw = await this.request<{\n accountIdentifier: string;\n accessToken: string;\n accessTokenExpiresAt?: string;\n expiresAt?: string;\n }>(path, { method: \"POST\" });\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n expiresAt: raw.expiresAt ?? \"\",\n };\n }\n\n async getTeamsCredentials(): Promise<{\n agentId: string;\n tenantId: string;\n azureAppId: string;\n azureBotId: string;\n azureClientSecret: string;\n botDisplayName?: string;\n teamsTenantId?: string;\n serviceUrl?: string;\n }> {\n return this.request(\"/agent/microsoft/credentials\");\n }\n\n async sendTeamsMessage(data: {\n conversationId: string;\n text?: string;\n adaptiveCard?: Record<string, unknown>;\n }): Promise<{ ok: boolean; activityId: string }> {\n return this.request(\"/agent/microsoft/send\", {\n method: \"POST\",\n body: JSON.stringify(data),\n });\n }\n\n async listTeamsChannels(): Promise<{\n channels: { id: string; name: string; description?: string }[];\n }> {\n return this.request(\"/agent/microsoft/channels\");\n }\n\n async presignAttachments(files: { filename: string; mimeType: string; size: number }[]): Promise<{\n attachments: { id: string; uploadUrl: string; downloadUrl: string; s3Key: string; expiresAt: string }[];\n }> {\n return this.request(\"/agent/chat/attachments/presign\", {\n method: \"POST\",\n body: JSON.stringify({ files }),\n });\n }\n\n async recordActivity(data: {\n userId?: string;\n channel: string;\n role: \"user\" | \"assistant\";\n }): Promise<{ recorded: boolean }> {\n return this.request<{ recorded: boolean }>(\"/agent/activity\", {\n method: \"POST\",\n body: JSON.stringify(data),\n });\n }\n\n // ─── Secrets ──────────────────────────────────────────────────\n //\n // Envelope CRUD + KMS proxy for per-scope encrypted secret storage.\n // Agents never hold a KMS master key — these proxy endpoints mint one-shot\n // AES-256 data keys bound (via KMS encryption context) to\n // `{ tenantId, scope, scopeId, secretId }`. The agent performs AES-256-GCM\n // locally; the backend only ever sees opaque envelopes.\n //\n // Routes resolve to the agent API gateway (mapping key `agent`), where\n // services/secrets registers its routes with pathPrefix `/secrets`. With\n // `apiUrl` set to the host root (e.g. `https://api.alfe.ai`), the full URL\n // is `https://api.alfe.ai/agent/secrets/...`. This is the same mapping as\n // `/agent/integrations/...` etc. — do NOT hit `/secrets/...` on the root\n // host: that's the user-auth dashboard gateway, which rejects agent tokens.\n //\n // `plaintextKey` in responses is base64 — callers MUST decode to a Node\n // `Buffer` immediately and zero it after use. NEVER keep plaintext keys\n // as JS strings (strings are immutable and cannot be wiped).\n\n /**\n * Mint a fresh AES-256 data key for a specific (secret, field) pair. The\n * encryption context is rebuilt server-side from `auth.tenantId` + the body\n * fields including `fieldKey`; the agent cannot forge context for a scope\n * or field it doesn't own. Legacy single-envelope secrets are migrated to\n * `field#value` rows by the data migration, so call with `fieldKey: \"value\"`\n * to reach them.\n */\n async generateSecretDataKey(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<GeneratedDataKey> {\n return this.request<GeneratedDataKey>(\"/agent/secrets/generate-data-key\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Unwrap a wrapped data key so the agent can decrypt the envelope locally.\n * `fieldKey` MUST match the value supplied when the data key was generated\n * (it's bound into KMS encryption context); mismatch fails with\n * `InvalidCiphertextException`.\n */\n async decryptSecretDataKey(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n dataKeyCiphertext: string;\n }): Promise<{ plaintextKey: string }> {\n return this.request<{ plaintextKey: string }>(\"/agent/secrets/decrypt-data-key\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Create a new secret with one or more fields. Encrypted fields must arrive\n * pre-sealed (the agent has already obtained per-field data keys via\n * `generateSecretDataKey({ ..., fieldKey })` and AES-encrypted locally).\n * Plaintext fields ship the value inline.\n */\n async createSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n secretName: string;\n category?: SecretCategory;\n description?: string;\n tags?: string[];\n fields: {\n key: string;\n format?: FieldFormat;\n sensitivity: FieldSensitivity;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n }[];\n reason?: string;\n }): Promise<SecretAggregate> {\n const { scope, scopeId, secretId, ...body } = args;\n return this.request<SecretAggregate>(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}`,\n {\n method: \"PUT\",\n body: JSON.stringify(body),\n },\n );\n }\n\n /** Fetch the secret aggregate plus per-field encrypted envelopes. */\n async getSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n }): Promise<{ aggregate: SecretAggregate; envelopes: FieldEnvelope[] }> {\n return this.request<{ aggregate: SecretAggregate; envelopes: FieldEnvelope[] }>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}`,\n );\n }\n\n /** Fetch one field. Plaintext: value inline. Encrypted: envelope. */\n async getSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<{\n key: string;\n sensitivity: FieldSensitivity;\n format?: FieldFormat;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n rotatedAt?: string;\n createdAt: string;\n updatedAt: string;\n }> {\n return this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/fields/${encodeURIComponent(args.fieldKey)}`,\n );\n }\n\n /** Add OR rotate one field. */\n async setSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n sensitivity: FieldSensitivity;\n format?: FieldFormat;\n value?: string;\n envelope?: EncryptedEnvelopeV1;\n reason?: string;\n }): Promise<{ fieldKey: string; rotated: boolean }> {\n const { scope, scopeId, secretId, fieldKey, ...body } = args;\n return this.request(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}/fields/${encodeURIComponent(fieldKey)}`,\n { method: \"PUT\", body: JSON.stringify(body) },\n );\n }\n\n /** Remove one field. */\n async removeSecretField(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n fieldKey: string;\n }): Promise<void> {\n await this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/fields/${encodeURIComponent(args.fieldKey)}`,\n { method: \"DELETE\" },\n );\n }\n\n /** Update secret-level metadata (name/description/tags/category). */\n async updateSecretMetadata(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n secretName?: string;\n description?: string;\n tags?: string[];\n category?: SecretCategory;\n reason?: string;\n }): Promise<SecretAggregate> {\n const { scope, scopeId, secretId, ...body } = args;\n return this.request<SecretAggregate>(\n `/agent/secrets/${encodeURIComponent(scope)}/${encodeURIComponent(scopeId)}/${encodeURIComponent(secretId)}`,\n { method: \"PATCH\", body: JSON.stringify(body) },\n );\n }\n\n /** List metadata for secrets in a scope. Optional filters route through the byFacet GSI. */\n async listSecrets(args: {\n scope: SecretScope;\n scopeId: string;\n category?: SecretCategory;\n tag?: string;\n fieldKey?: string;\n }): Promise<SecretMetadata[]> {\n const params = new URLSearchParams();\n if (args.category) params.set(\"category\", args.category);\n if (args.tag) params.set(\"tag\", args.tag);\n if (args.fieldKey) params.set(\"fieldKey\", args.fieldKey);\n const qs = params.toString();\n const resp = await this.request<{ secrets: SecretMetadata[] }>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}${qs ? `?${qs}` : \"\"}`,\n );\n return resp.secrets;\n }\n\n /** Bounded changelog read — metadata-only audit entries. */\n async getSecretHistory(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n limit?: number;\n cursor?: string;\n }): Promise<{ entries: ChangelogEntry[]; nextCursor?: string }> {\n const params = new URLSearchParams();\n if (args.limit) params.set(\"limit\", String(args.limit));\n if (args.cursor) params.set(\"cursor\", args.cursor);\n const qs = params.toString();\n return this.request(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}/history${qs ? `?${qs}` : \"\"}`,\n );\n }\n\n /** Delete a secret (and all its field rows + tag rows + changelog rows). */\n async deleteSecret(args: {\n scope: SecretScope;\n scopeId: string;\n secretId: string;\n }): Promise<void> {\n await this.request<unknown>(\n `/agent/secrets/${encodeURIComponent(args.scope)}/${encodeURIComponent(args.scopeId)}/${encodeURIComponent(args.secretId)}`,\n { method: \"DELETE\" },\n );\n }\n\n /** Enumerate scopes (org/team/project/agent) this agent can access. */\n async listSecretScopes(): Promise<ScopeInfo[]> {\n const resp = await this.request<{ scopes: ScopeInfo[] }>(\"/agent/secrets/scopes\");\n return resp.scopes;\n }\n\n // ─── Identity ─────────────────────────────────────────────\n //\n // Identity resolution, permission enforcement, and CRM tools.\n // The agent API derives tenantId + agentId from the agent token.\n\n /**\n * Returns the calling agent's own identity context — `{ agentId, tenantId }`\n * decoded server-side from the agent API token. Used by the\n * `@alfe.ai/openclaw-identity` plugin to bootstrap context when the\n * OpenClaw daemon doesn't plumb `ctx.agentId` through to plugin hooks.\n * Plugins should cache this for the daemon's lifetime (single-agent-per-\n * process invariant). One HTTP round-trip per process activate; not for\n * per-call use.\n */\n async whoami(): Promise<{ agentId: string; tenantId: string }> {\n return this.request(\"/agent/identity/whoami\");\n }\n\n async resolveIdentity(args: {\n provider: string;\n platformId: string;\n kind?: \"user\" | \"agent\" | \"service\" | \"bot\" | \"workspace\";\n displayName?: string;\n }): Promise<{\n identityId: string | null;\n status: string;\n created?: boolean;\n reason?: string;\n /**\n * Flattened auriclabs permission strings for the resolved identity\n * (scope-prefixed where applicable). Empty array on miss / org service\n * outage — the runtime gate fails closed in that case.\n */\n permissions: string[];\n }> {\n return this.request(\"/agent/identity/resolve\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async searchIdentities(args?: {\n q?: string;\n status?: string;\n limit?: number;\n }): Promise<{ identities: unknown[] }> {\n const qs = new URLSearchParams();\n if (args?.q) qs.set(\"q\", args.q);\n if (args?.status) qs.set(\"status\", args.status);\n if (args?.limit) qs.set(\"limit\", String(args.limit));\n const query = qs.toString();\n return this.request(`/agent/identity/search${query ? `?${query}` : \"\"}`);\n }\n\n async getIdentityContext(identityId: string): Promise<{\n context: unknown;\n }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/context`);\n }\n\n async mergeIdentities(survivorId: string, args: {\n mergedId: string;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; error?: string }> {\n return this.request(`/agent/identity/${encodeURIComponent(survivorId)}/merge`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async unmergeIdentity(identityId: string, args: {\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; error?: string }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/unmerge`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async addIdentityNote(identityId: string, args: {\n content: string;\n category?: string;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ noteId: string | null }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/notes`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async tagIdentity(identityId: string, args: {\n tag: string;\n action: \"add\" | \"remove\";\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/tags`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async getIdentityChangelog(identityId: string, args?: {\n limit?: number;\n }): Promise<{ entries: unknown[] }> {\n const qs = new URLSearchParams();\n if (args?.limit) qs.set(\"limit\", String(args.limit));\n const query = qs.toString();\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/changelog${query ? `?${query}` : \"\"}`);\n }\n\n async rollbackIdentity(identityId: string, args: {\n targetVersion: number;\n changedBy: { type: string; id: string; name?: string };\n }): Promise<{ ok: boolean; entry?: unknown }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/rollback`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async requestIdentityVerification(args: {\n claimedIdentityId: string;\n requestingIdentityId: string;\n requestingProvider: string;\n requestingPlatformId: string;\n preferredChannel?: \"mobile\" | \"email\";\n /**\n * Phase 2: agent-supplied contact endpoint. When provided, the top-level\n * `preferredChannel` is ignored — the contact's channel wins.\n */\n contact?: { channel: \"email\" | \"mobile\"; value: string };\n }): Promise<{\n verificationId: string;\n channel: string;\n deliveredTo: string;\n expiresAt: string;\n availableChannels: { channel: string; deliveredTo: string }[];\n } | { error: string }> {\n return this.request(\"/agent/identity/verify/request\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async confirmIdentityVerification(args: {\n claimedIdentityId: string;\n verificationId: string;\n phrase: string;\n }): Promise<{\n verified: boolean;\n identityId?: string;\n /** Phase 2: how the confirm resolved — Scenario A vs B. */\n action?: \"merged\" | \"contact_verified\";\n error?: string;\n }> {\n return this.request(\"/agent/identity/verify/confirm\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Update display-shape fields on an Identity. Body excludes `email` /\n * `phone` / `title` / `company` / `metadata` per Section D4 — contacts go\n * via the verify flow, title/company live on OrgMembership, metadata is\n * not agent-writable.\n */\n async updateIdentity(\n identityId: string,\n args: {\n name?: string;\n avatarUrl?: string;\n timezone?: string;\n locale?: string;\n },\n ): Promise<{ ok: boolean }> {\n return this.request(`/agent/identity/${encodeURIComponent(identityId)}/update`, {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Phase 2 (Section H): server-side verification of a Google Chat sender via\n * the agent's existing Google OAuth credentials. Returns the resolved\n * identity (created or matched via Scenario-B email enrichment).\n */\n async resolveGoogleChatSender(args: {\n senderUserId: string;\n spaceId?: string;\n }): Promise<{\n identityId: string | null;\n status: string;\n }> {\n return this.request(\"/agent/google/resolve-sender\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n // ─── Memory ──────────────────────────────────────────────\n //\n // Cloud memory (Turbopuffer vectors + DynamoDB knowledge graph).\n // The agent API derives tenantId + agentId from the agent token.\n\n async memorySearch(query: string, opts?: {\n limit?: number;\n topic?: string;\n subtopic?: string;\n tag?: string;\n includeKnowledge?: boolean;\n }): Promise<{\n facts: { subject: string; predicate: string; object: string; since: string; confidence: number }[];\n memories: { id: string; text: string; topic: string; subtopic: string; tag: string; importance: number; timestamp: number; score: number }[];\n }> {\n return this.request(\"/agent/memory/search\", {\n method: \"POST\",\n body: JSON.stringify({\n query,\n limit: opts?.limit ?? 10,\n topic: opts?.topic,\n subtopic: opts?.subtopic,\n tag: opts?.tag,\n includeKnowledge: opts?.includeKnowledge ?? true,\n }),\n });\n }\n\n async memoryStore(text: string, opts?: {\n topic?: string;\n subtopic?: string;\n tag?: string;\n importance?: number;\n }): Promise<{ memoryId: string }> {\n return this.request(\"/agent/memory/store\", {\n method: \"POST\",\n body: JSON.stringify({\n text,\n topic: opts?.topic ?? \"general\",\n subtopic: opts?.subtopic ?? \"general\",\n tag: opts?.tag ?? \"fact\",\n importance: opts?.importance ?? 0.7,\n }),\n });\n }\n\n async memoryIngest(sessionKey: string, messages: {\n role: string;\n content: string;\n index: number;\n timestamp?: string;\n }[], metadata?: {\n channelId?: string;\n userId?: string;\n userName?: string;\n }): Promise<{ queued: boolean; messageCount: number }> {\n return this.request(\"/agent/memory/ingest\", {\n method: \"POST\",\n body: JSON.stringify({\n sessionKey,\n lastProcessedIndex: messages.length > 0 ? messages[messages.length - 1].index : -1,\n messages,\n metadata,\n }),\n });\n }\n\n async memoryLoadContext(tier?: number, topicHint?: string): Promise<{\n formatted: string;\n [key: string]: unknown;\n }> {\n const params = new URLSearchParams();\n if (tier !== undefined) params.set(\"tier\", String(tier));\n if (topicHint) params.set(\"topicHint\", topicHint);\n const qs = params.toString();\n return this.request(`/agent/memory/context${qs ? `?${qs}` : \"\"}`);\n }\n\n async memoryLookupEntity(subject: string): Promise<{\n subject: string;\n triples: { tripleId: string; predicate: string; object: string; validFrom: string; validTo?: string; confidence: number }[];\n }> {\n return this.request(`/agent/memory/knowledge/entities?subject=${encodeURIComponent(subject)}`);\n }\n\n async memoryNavigate(): Promise<{\n topics: { name: string; tripleCount: number; subtopics: string[] }[];\n cursor: string | null;\n }> {\n return this.request(\"/agent/memory/navigate\");\n }\n\n async memoryDelete(memoryId: string): Promise<{ deleted: boolean }> {\n return this.request(`/agent/memory/${encodeURIComponent(memoryId)}`, {\n method: \"DELETE\",\n });\n }\n\n async memoryStats(): Promise<{\n vectorCount: number;\n tripleCount: number;\n storageEstimateBytes: number;\n lastIngestionAt?: string;\n }> {\n return this.request(\"/agent/memory/stats\");\n }\n\n async memoryLearn(args: {\n text: string;\n source?: string;\n sourceType?: \"file\" | \"url\" | \"inline\";\n metadata?: { sessionId?: string; channelId?: string; userName?: string };\n }): Promise<{\n memoriesStored: number;\n triplesStored: number;\n chunks: number;\n source?: string;\n }> {\n return this.request(\"/agent/memory/learn\", {\n method: \"POST\",\n body: JSON.stringify({\n text: args.text,\n source: args.source,\n sourceType: args.sourceType ?? \"inline\",\n metadata: args.metadata,\n }),\n });\n }\n\n async memoryBootstrapStatus(): Promise<{ synced: boolean; syncedAt?: string }> {\n return this.request(\"/agent/memory/bootstrap-status\");\n }\n\n async memoryBootstrapStatusMark(): Promise<{ synced: true; syncedAt: string }> {\n return this.request(\"/agent/memory/bootstrap-status\", { method: \"POST\" });\n }\n\n // ─── Search ──────────────────────────────────────────────\n\n async searchWeb(params: {\n query: string;\n count?: number;\n offset?: number;\n country?: string;\n freshness?: string;\n }): Promise<unknown> {\n return this.request(\"/agent/search/web\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n async searchImages(params: {\n query: string;\n count?: number;\n }): Promise<unknown> {\n return this.request(\"/agent/search/images\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n async searchNews(params: {\n query: string;\n count?: number;\n freshness?: string;\n }): Promise<unknown> {\n return this.request(\"/agent/search/news\", {\n method: \"POST\",\n body: JSON.stringify(params),\n });\n }\n\n // ─── Database ───────────────────────────────────────────\n\n async registerDatabaseCredentials(): Promise<{\n connectionString: string;\n username: string;\n password: string;\n databases: string[];\n }> {\n return this.request(\"/agent/database/register\", { method: \"POST\" });\n }\n\n async reportDatabaseAudit(entry: {\n database: string;\n collection: string;\n operation: string;\n summary?: string;\n }): Promise<void> {\n await this.request(\"/agent/database/audit\", {\n method: \"POST\",\n body: JSON.stringify(entry),\n }).catch(() => {\n // Fire and forget — audit failure doesn't affect operations\n });\n }\n}\n"],"mappings":"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"}
|