@alfe.ai/agent-api-client 0.6.1 → 0.7.1

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 CHANGED
@@ -15,6 +15,8 @@ const RETRYABLE_STATUS = new Set([
15
15
  504
16
16
  ]);
17
17
  const RETRY_DELAY_MS = 500;
18
+ const IMAGE_POLL_INTERVAL_MS = 2e3;
19
+ const IMAGE_JOB_TIMEOUT_MS = 18e4;
18
20
  function sleep(ms) {
19
21
  return new Promise((resolve) => {
20
22
  setTimeout(resolve, ms);
@@ -592,36 +594,50 @@ var AgentApiClient = class {
592
594
  }
593
595
  /**
594
596
  * Generate an image from a text prompt and get back a STABLE, public URL
595
- * (served from the agent-assets CDN — it does not expire). The image is
596
- * generated + stored server-side; embed the returned `imageUrl` in a reply as
597
- * markdown to show it to the user.
597
+ * (served from the agent-assets CDN — it does not expire). Embed the returned
598
+ * `imageUrl` in a reply as markdown to show it to the user.
598
599
  *
599
- * Unlike most methods this reads the server's error body so a bad-request
600
- * detail (e.g. an unsupported `size`) reaches the caller instead of an opaque
601
- * "request failed (400)". Not retried generation is expensive and
602
- * non-idempotent.
600
+ * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
601
+ * 30s ceiling, so this enqueues a job (`POST /agent/images/generate`
602
+ * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
603
+ * worker's real failure message (e.g. an unsupported `size`) surfaces via the
604
+ * job's `error` field.
603
605
  */
604
606
  async generateImage(args) {
605
607
  const headers = new Headers();
606
608
  headers.set("Authorization", `Bearer ${this.apiKey}`);
607
609
  headers.set("Content-Type", "application/json");
608
- const res = await fetch(`${this.apiUrl}/agent/images/generate`, {
610
+ const enqueueRes = await fetch(`${this.apiUrl}/agent/images/generate`, {
609
611
  method: "POST",
610
612
  headers,
611
613
  body: JSON.stringify(args),
612
- signal: AbortSignal.timeout(33e3)
614
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
613
615
  });
614
- if (!res.ok) {
615
- const body = await res.text().catch(() => "");
616
- let detail = "";
616
+ if (!enqueueRes.ok) throw new Error(`Image generation failed to start (${String(enqueueRes.status)})`);
617
+ const { data: enqueued } = await enqueueRes.json();
618
+ const jobId = enqueued.jobId;
619
+ const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;
620
+ while (Date.now() < deadline) {
621
+ await sleep(IMAGE_POLL_INTERVAL_MS);
622
+ let job;
617
623
  try {
618
- const parsed = JSON.parse(body);
619
- const msg = typeof parsed.message === "string" ? parsed.message : typeof parsed.error === "string" ? parsed.error : "";
620
- if (msg) detail = `: ${msg}`;
621
- } catch {}
622
- throw new Error(`Image generation failed (${String(res.status)})${detail}`);
624
+ job = await this.request(`/agent/images/${jobId}`);
625
+ } catch {
626
+ continue;
627
+ }
628
+ if (job.status === "completed") {
629
+ if (!job.imageUrl) throw new Error("Image generation completed without a URL");
630
+ return {
631
+ imageUrl: job.imageUrl,
632
+ model: job.model ?? args.model ?? "gpt-image-1"
633
+ };
634
+ }
635
+ if (job.status === "failed") {
636
+ const detail = job.error ? `: ${job.error.split("\n")[0]}` : "";
637
+ throw new Error(`Image generation failed${detail}`);
638
+ }
623
639
  }
624
- return (await res.json()).data;
640
+ throw new Error("Image generation timed out");
625
641
  }
626
642
  async recordActivity(data) {
627
643
  return this.request("/agent/activity", {
@@ -639,12 +655,44 @@ var AgentApiClient = class {
639
655
  /**
640
656
  * Generate the agent's own avatar from a text prompt. The image is generated,
641
657
  * stored, and set on the agent server-side; returns the updated agent.
658
+ *
659
+ * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
660
+ * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
661
+ * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
662
+ * until the avatar is set. Signature unchanged — the plugin is unaffected.
642
663
  */
643
664
  async generateAvatar(args) {
644
- return this.request("/agent/avatar/generate", {
665
+ const headers = new Headers();
666
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
667
+ headers.set("Content-Type", "application/json");
668
+ const enqueueRes = await fetch(`${this.apiUrl}/agent/avatar/generate`, {
645
669
  method: "POST",
646
- body: JSON.stringify(args)
670
+ headers,
671
+ body: JSON.stringify(args),
672
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
647
673
  });
674
+ if (!enqueueRes.ok) throw new Error(`Avatar generation failed to start (${String(enqueueRes.status)})`);
675
+ const { data: enqueued } = await enqueueRes.json();
676
+ const jobId = enqueued.jobId;
677
+ const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;
678
+ while (Date.now() < deadline) {
679
+ await sleep(IMAGE_POLL_INTERVAL_MS);
680
+ let job;
681
+ try {
682
+ job = await this.request(`/agent/avatar/${jobId}`);
683
+ } catch {
684
+ continue;
685
+ }
686
+ if (job.status === "completed") {
687
+ if (!job.agent) throw new Error("Avatar generation completed without an agent");
688
+ return job.agent;
689
+ }
690
+ if (job.status === "failed") {
691
+ const detail = job.error ? `: ${job.error.split("\n")[0]}` : "";
692
+ throw new Error(`Avatar generation failed${detail}`);
693
+ }
694
+ }
695
+ throw new Error("Avatar generation timed out");
648
696
  }
649
697
  /**
650
698
  * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to
package/dist/index.d.cts CHANGED
@@ -782,14 +782,14 @@ declare class AgentApiClient {
782
782
  }>;
783
783
  /**
784
784
  * Generate an image from a text prompt and get back a STABLE, public URL
785
- * (served from the agent-assets CDN — it does not expire). The image is
786
- * generated + stored server-side; embed the returned `imageUrl` in a reply as
787
- * markdown to show it to the user.
785
+ * (served from the agent-assets CDN — it does not expire). Embed the returned
786
+ * `imageUrl` in a reply as markdown to show it to the user.
788
787
  *
789
- * Unlike most methods this reads the server's error body so a bad-request
790
- * detail (e.g. an unsupported `size`) reaches the caller instead of an opaque
791
- * "request failed (400)". Not retried generation is expensive and
792
- * non-idempotent.
788
+ * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
789
+ * 30s ceiling, so this enqueues a job (`POST /agent/images/generate`
790
+ * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
791
+ * worker's real failure message (e.g. an unsupported `size`) surfaces via the
792
+ * job's `error` field.
793
793
  */
794
794
  generateImage(args: {
795
795
  prompt: string;
@@ -815,6 +815,11 @@ declare class AgentApiClient {
815
815
  /**
816
816
  * Generate the agent's own avatar from a text prompt. The image is generated,
817
817
  * stored, and set on the agent server-side; returns the updated agent.
818
+ *
819
+ * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
820
+ * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
821
+ * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
822
+ * until the avatar is set. Signature unchanged — the plugin is unaffected.
818
823
  */
819
824
  generateAvatar(args: {
820
825
  prompt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -782,14 +782,14 @@ declare class AgentApiClient {
782
782
  }>;
783
783
  /**
784
784
  * Generate an image from a text prompt and get back a STABLE, public URL
785
- * (served from the agent-assets CDN — it does not expire). The image is
786
- * generated + stored server-side; embed the returned `imageUrl` in a reply as
787
- * markdown to show it to the user.
785
+ * (served from the agent-assets CDN — it does not expire). Embed the returned
786
+ * `imageUrl` in a reply as markdown to show it to the user.
788
787
  *
789
- * Unlike most methods this reads the server's error body so a bad-request
790
- * detail (e.g. an unsupported `size`) reaches the caller instead of an opaque
791
- * "request failed (400)". Not retried generation is expensive and
792
- * non-idempotent.
788
+ * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
789
+ * 30s ceiling, so this enqueues a job (`POST /agent/images/generate`
790
+ * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
791
+ * worker's real failure message (e.g. an unsupported `size`) surfaces via the
792
+ * job's `error` field.
793
793
  */
794
794
  generateImage(args: {
795
795
  prompt: string;
@@ -815,6 +815,11 @@ declare class AgentApiClient {
815
815
  /**
816
816
  * Generate the agent's own avatar from a text prompt. The image is generated,
817
817
  * stored, and set on the agent server-side; returns the updated agent.
818
+ *
819
+ * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
820
+ * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
821
+ * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
822
+ * until the avatar is set. Signature unchanged — the plugin is unaffected.
818
823
  */
819
824
  generateAvatar(args: {
820
825
  prompt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -14,6 +14,8 @@ const RETRYABLE_STATUS = new Set([
14
14
  504
15
15
  ]);
16
16
  const RETRY_DELAY_MS = 500;
17
+ const IMAGE_POLL_INTERVAL_MS = 2e3;
18
+ const IMAGE_JOB_TIMEOUT_MS = 18e4;
17
19
  function sleep(ms) {
18
20
  return new Promise((resolve) => {
19
21
  setTimeout(resolve, ms);
@@ -591,36 +593,50 @@ var AgentApiClient = class {
591
593
  }
592
594
  /**
593
595
  * Generate an image from a text prompt and get back a STABLE, public URL
594
- * (served from the agent-assets CDN — it does not expire). The image is
595
- * generated + stored server-side; embed the returned `imageUrl` in a reply as
596
- * markdown to show it to the user.
596
+ * (served from the agent-assets CDN — it does not expire). Embed the returned
597
+ * `imageUrl` in a reply as markdown to show it to the user.
597
598
  *
598
- * Unlike most methods this reads the server's error body so a bad-request
599
- * detail (e.g. an unsupported `size`) reaches the caller instead of an opaque
600
- * "request failed (400)". Not retried generation is expensive and
601
- * non-idempotent.
599
+ * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
600
+ * 30s ceiling, so this enqueues a job (`POST /agent/images/generate`
601
+ * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
602
+ * worker's real failure message (e.g. an unsupported `size`) surfaces via the
603
+ * job's `error` field.
602
604
  */
603
605
  async generateImage(args) {
604
606
  const headers = new Headers();
605
607
  headers.set("Authorization", `Bearer ${this.apiKey}`);
606
608
  headers.set("Content-Type", "application/json");
607
- const res = await fetch(`${this.apiUrl}/agent/images/generate`, {
609
+ const enqueueRes = await fetch(`${this.apiUrl}/agent/images/generate`, {
608
610
  method: "POST",
609
611
  headers,
610
612
  body: JSON.stringify(args),
611
- signal: AbortSignal.timeout(33e3)
613
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
612
614
  });
613
- if (!res.ok) {
614
- const body = await res.text().catch(() => "");
615
- let detail = "";
615
+ if (!enqueueRes.ok) throw new Error(`Image generation failed to start (${String(enqueueRes.status)})`);
616
+ const { data: enqueued } = await enqueueRes.json();
617
+ const jobId = enqueued.jobId;
618
+ const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;
619
+ while (Date.now() < deadline) {
620
+ await sleep(IMAGE_POLL_INTERVAL_MS);
621
+ let job;
616
622
  try {
617
- const parsed = JSON.parse(body);
618
- const msg = typeof parsed.message === "string" ? parsed.message : typeof parsed.error === "string" ? parsed.error : "";
619
- if (msg) detail = `: ${msg}`;
620
- } catch {}
621
- throw new Error(`Image generation failed (${String(res.status)})${detail}`);
623
+ job = await this.request(`/agent/images/${jobId}`);
624
+ } catch {
625
+ continue;
626
+ }
627
+ if (job.status === "completed") {
628
+ if (!job.imageUrl) throw new Error("Image generation completed without a URL");
629
+ return {
630
+ imageUrl: job.imageUrl,
631
+ model: job.model ?? args.model ?? "gpt-image-1"
632
+ };
633
+ }
634
+ if (job.status === "failed") {
635
+ const detail = job.error ? `: ${job.error.split("\n")[0]}` : "";
636
+ throw new Error(`Image generation failed${detail}`);
637
+ }
622
638
  }
623
- return (await res.json()).data;
639
+ throw new Error("Image generation timed out");
624
640
  }
625
641
  async recordActivity(data) {
626
642
  return this.request("/agent/activity", {
@@ -638,12 +654,44 @@ var AgentApiClient = class {
638
654
  /**
639
655
  * Generate the agent's own avatar from a text prompt. The image is generated,
640
656
  * stored, and set on the agent server-side; returns the updated agent.
657
+ *
658
+ * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
659
+ * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
660
+ * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
661
+ * until the avatar is set. Signature unchanged — the plugin is unaffected.
641
662
  */
642
663
  async generateAvatar(args) {
643
- return this.request("/agent/avatar/generate", {
664
+ const headers = new Headers();
665
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
666
+ headers.set("Content-Type", "application/json");
667
+ const enqueueRes = await fetch(`${this.apiUrl}/agent/avatar/generate`, {
644
668
  method: "POST",
645
- body: JSON.stringify(args)
669
+ headers,
670
+ body: JSON.stringify(args),
671
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
646
672
  });
673
+ if (!enqueueRes.ok) throw new Error(`Avatar generation failed to start (${String(enqueueRes.status)})`);
674
+ const { data: enqueued } = await enqueueRes.json();
675
+ const jobId = enqueued.jobId;
676
+ const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;
677
+ while (Date.now() < deadline) {
678
+ await sleep(IMAGE_POLL_INTERVAL_MS);
679
+ let job;
680
+ try {
681
+ job = await this.request(`/agent/avatar/${jobId}`);
682
+ } catch {
683
+ continue;
684
+ }
685
+ if (job.status === "completed") {
686
+ if (!job.agent) throw new Error("Avatar generation completed without an agent");
687
+ return job.agent;
688
+ }
689
+ if (job.status === "failed") {
690
+ const detail = job.error ? `: ${job.error.split("\n")[0]}` : "";
691
+ throw new Error(`Avatar generation failed${detail}`);
692
+ }
693
+ }
694
+ throw new Error("Avatar generation timed out");
647
695
  }
648
696
  /**
649
697
  * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to
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// ─── Remote (interactive relay) types ────────────────────\n\nexport interface RemoteSessionInfo {\n sessionId: string;\n agentId: string;\n surface: \"browser\" | \"terminal\";\n status:\n | \"agent_driving\"\n | \"awaiting_human\"\n | \"human_in_control\"\n | \"resuming\"\n | \"completed\"\n | \"expired\"\n | \"failed\";\n url?: string;\n instructions?: string;\n requestedAt?: 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// ─── Knowledge resource types (org/team/project) ──────────\n//\n// Scoped, searchable knowledge ABOUT a thing being worked on. The system\n// of record is `services/org` (docs + profile + the membership gate);\n// `services/knowledge` is a pure RAG projection (vector search). `scopeId`\n// for the `org` scope is the tenantId (covers personal + org tenants\n// identically) — agents discover it via `listScopes()`.\n\nexport type KnowledgeScopeType = \"org\" | \"team\" | \"project\";\n\nexport interface KnowledgeScope {\n scopeType: KnowledgeScopeType;\n scopeId: string;\n name: string;\n}\n\nexport interface KnowledgeSearchHit {\n id: string;\n text: string;\n /** Normalized relevance in (0,1]; higher = closer. */\n score: number;\n scopeType: KnowledgeScopeType;\n scopeId: string;\n /**\n * Provenance of the hit. All live results are `\"doc\"`; `\"fact\"` only ever\n * appears for legacy vectors indexed before the facts primitive was removed\n * (the search index stays tolerant of them). Treat every hit as a doc.\n */\n source: \"doc\" | \"fact\";\n /** The canonical file under shared/<scope>/ (present on doc hits). */\n filePath?: string;\n /** Legacy-only: the id of a pre-removal fact vector. */\n factId?: string;\n}\n\nexport interface KnowledgeSearchResult {\n results: KnowledgeSearchHit[];\n /** True when fan-out breadth was capped (more member scopes than the cap). */\n truncatedScopes: boolean;\n}\n\nexport interface KnowledgeProfileLink {\n label: string;\n url: string;\n}\n\nexport interface KnowledgeProfile {\n scopeType: KnowledgeScopeType;\n scopeId: string;\n about: string | null;\n description: string | null;\n links: KnowledgeProfileLink[];\n updatedAt: string | null;\n updatedBy: string | null;\n}\n\nexport interface KnowledgeDoc {\n filePath: string;\n fileName: string;\n contentType?: string;\n size: number;\n uploadedBy?: string;\n createdAt: string;\n updatedAt: string;\n}\n\n// ─── Knowledge change requests ───────────────────────────\n//\n// A change request is a proposed, inert mutation to one knowledge resource.\n// It is the agent's contribution path to a scope it is NOT a member of: the\n// proposal stays inert until a reviewer with scope authority approves it. An\n// agent that IS a member should just write directly (resource_write_*).\n\nexport type ChangeRequestResourceType = \"doc\" | \"profile\";\nexport type ChangeRequestOperation = \"create\" | \"update\" | \"delete\";\nexport type ChangeRequestStatus =\n | \"open\"\n | \"approved\"\n | \"rejected\"\n | \"withdrawn\"\n | \"superseded\";\nexport type ChangeRequestActorKind = \"human\" | \"agent\";\n\n/** Public projection of a change request (mirrors `PublicChangeRequest` in services/org). */\nexport interface KnowledgeChangeRequest {\n changeRequestId: string;\n scopeType: KnowledgeScopeType;\n scopeId: string;\n resourceType: ChangeRequestResourceType;\n operation: ChangeRequestOperation;\n targetPath: string | null;\n baseVersionId: string | null;\n proposedContentType: string | null;\n status: ChangeRequestStatus;\n proposerId: string;\n proposerKind: ChangeRequestActorKind;\n rationale: string;\n reviewerId: string | null;\n reviewerKind: ChangeRequestActorKind | null;\n reviewedAt: string | null;\n reviewNote: string | null;\n appliedRef: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Per-type proposal payload for `proposeScopeChange`. */\nexport interface ProposeScopeChangeInput {\n resourceType: ChangeRequestResourceType;\n operation: ChangeRequestOperation;\n /** Why the change is proposed — shown to the reviewer. */\n rationale: string;\n /** doc: the path the proposal applies to (e.g. designs/data-center.md). */\n targetPath?: string;\n /** doc create/update: the staged body to upload (markdown or other text). */\n content?: string;\n /** doc create/update: content type of the staged body (default text/markdown). */\n contentType?: string;\n /** profile: the proposed value ({ about, description, links }). */\n proposedValue?: unknown;\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\n// Per-request budget. Covers cold-start chains (authorizer + handler\n// + downstream OAuth provider) with headroom; the worst legitimate\n// path observed is ~7s (cold Lambda + Atlassian token exchange).\nconst REQUEST_TIMEOUT_MS = 20_000;\n// Statuses worth one retry — API GW synthesizes 500 on authorizer\n// timeout, 502/503/504 cover upstream cold-start and LB transients.\nconst RETRYABLE_STATUS = new Set([500, 502, 503, 504]);\nconst RETRY_DELAY_MS = 500;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction isRetryableNetworkError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // AbortSignal.timeout() rejects with TimeoutError (DOMException).\n if (err.name === \"TimeoutError\" || err.name === \"AbortError\") return true;\n // undici wraps socket-level failures (stale keep-alive connections,\n // ECONNRESET on reused pool entries) in a TypeError \"fetch failed\"\n // with the cause attached.\n if (err.name === \"TypeError\") return true;\n return false;\n}\n\n// ─── Self identity types ─────────────────────────────────\n//\n// The agent customizing its OWN identity (name, avatar, voice). agentId +\n// tenantId are resolved from the token, so no id appears in the request.\n\n/** Voice settings — core agent config. Mirrors `VoiceConfig` in `@alfe/types`. */\nexport interface AgentVoiceConfig {\n /** ElevenLabs voice ID; platform default when unset. */\n voiceId?: string;\n ttsModel?: string;\n enabled?: boolean;\n}\n\n/**\n * The agent's own public identity, as returned by `updateSelf`, `generateAvatar`,\n * `presignAvatar`'s finalize (`finalizeAvatar`). This is the public agent\n * projection; only the identity-relevant fields are typed here — the response\n * carries the full public agent record.\n */\nexport interface AgentSelf {\n agentId: string;\n tenantId: string;\n name: string;\n avatarUrl?: string;\n voiceConfig?: AgentVoiceConfig;\n status: string;\n}\n\n/** Result of `presignAvatar` — the agent PUTs bytes to `uploadUrl`, then finalizes with `s3Key`. */\nexport interface AgentAvatarPresign {\n /** Presigned PUT URL to upload the image bytes to. */\n uploadUrl: string;\n /** Object key — echoed back to `finalizeAvatar`. */\n s3Key: string;\n /** Stable public URL the avatar will be served from once finalized. */\n publicUrl: string;\n /** ISO expiry of the presigned PUT URL. */\n expiresAt: string;\n}\n\n/** A voice in the platform catalogue (ElevenLabs), from `listVoices`. */\nexport interface AgentVoice {\n id: string;\n name: string;\n previewUrl: string;\n description: string;\n labels: Record<string, string>;\n category: string;\n}\n\n// ─── Voice one-shot TTS / STT ────────────────────────────\n//\n// These hit the voice service's agent-authed one-shot endpoints\n// (`/voice/tts`, `/voice/stt`), which are Lambda routes co-located on the\n// shared api gateway under the `voice` mapping key. Both are binary flows —\n// TTS returns raw PCM audio bytes, STT accepts raw PCM audio bytes — so they\n// bypass the JSON `{ data: T }` transport used by every other method here and\n// go through `rawFetch` instead. Metering to the tenant credit pool happens\n// server-side; the caller just gets audio (TTS) or a transcript (STT).\n\n/** The ElevenLabs models with a pricing row — the TTS endpoint rejects any other value. */\nexport type VoiceTtsModel = \"eleven_turbo_v2_5\" | \"eleven_multilingual_v2\";\n\nexport interface VoiceTtsArgs {\n /** Text to synthesize (1–5000 chars — the endpoint enforces this). */\n text: string;\n /** ElevenLabs voice id; platform default when unset. */\n voiceId?: string;\n /** TTS model; `eleven_turbo_v2_5` (lower latency) when unset. */\n model?: VoiceTtsModel;\n}\n\n/** Raw synthesized audio plus its PCM framing (from the response headers). */\nexport interface VoiceTtsResult {\n /** Raw little-endian PCM samples — no container. Wrap in WAV to make a playable file. */\n audio: Buffer;\n /** Samples per second (e.g. 24000). */\n sampleRate: number;\n /** Channel count (mono = 1). */\n channels: number;\n /** Bits per sample (e.g. 16). */\n bitDepth: number;\n}\n\nexport interface VoiceSttArgs {\n /** Raw linear16 (16-bit little-endian) mono PCM samples — no WAV/container header. */\n audio: Uint8Array;\n /** Sample rate of `audio` in Hz (8000–48000). */\n sampleRate: number;\n}\n\nexport interface VoiceSttResult {\n text: string;\n /** Deepgram confidence in (0,1]. */\n confidence: number;\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 // One retry on transient failures. Long-running daemon processes\n // (MCP proxies, the gateway) call this client after multi-hour\n // idle gaps; the first attempt then rides a cold path end-to-end —\n // including the API Gateway Lambda authorizer, which API GW\n // hard-caps at 10s and surfaces as a synthetic 500 WITHOUT ever\n // invoking the route handler. Observed on QA Tester (dev,\n // 2026-06-11): atlassian-mcp-proxy token refreshes failed ~59%\n // of attempts with an 11-12s hang then 500; the same request\n // re-issued seconds later succeeded in ~1.5s. A single retry\n // converts that failure mode into a slow success.\n //\n // Retrying POSTs is safe here: the 500 fires before the handler\n // runs (authorizer timeout), and the one rotating-token endpoint\n // (connect/{provider}/refresh) reads its refresh token from the\n // DB per call, so a duplicate invocation re-rotates cleanly\n // rather than corrupting state.\n let lastError: unknown;\n for (let attempt = 1; attempt <= 2; attempt++) {\n try {\n const res = await fetch(url, {\n ...options,\n headers,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n\n if (!res.ok) {\n await res.text(); // drain body\n const error = new Error(`Agent API request failed (${String(res.status)})`);\n if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {\n lastError = error;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw error;\n }\n\n const body = (await res.json()) as { data: T };\n return body.data;\n } catch (err) {\n if (attempt === 1 && isRetryableNetworkError(err)) {\n lastError = err;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw err;\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\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 * Fetch decrypted credentials for ONE specific connection by its\n * stable connectionId (connection-scoped, vs the provider-scoped\n * `get<Provider>Credentials` helpers). Used by the daemon to resolve\n * a Custom Connection-driven integration's credentials from the\n * exact connection it was installed from — every custom connection\n * shares the `custom` provider id, so provider-scoping is ambiguous.\n *\n * For custom connections `accessToken` is the JSON-encoded secret\n * bundle (the daemon un-bundles it); non-secret fields are on\n * `providerMetadata`. The endpoint enforces that the connection is in\n * the calling agent's effective scope (403 otherwise).\n */\n async getConnectionCredentials(connectionId: string): Promise<{\n provider: string;\n connectionId: string;\n accountIdentifier?: string;\n accessToken?: string;\n providerMetadata?: Record<string, unknown>;\n [key: string]: unknown;\n }> {\n return this.request(\n `/agent/connect/connections/${encodeURIComponent(connectionId)}/credentials`,\n );\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/github-mcp` 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 * @deprecated Returns a single primary credential blob. Use\n * `getSalesforceAccounts()` for the multi-account shape required by\n * Pattern A.\n */\n async getSalesforceCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n instanceUrl: string;\n orgId: string;\n }> {\n const raw = await this.request<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n instanceUrl?: string;\n orgId?: string;\n }>(\"/agent/connect/salesforce/credentials\");\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n instanceUrl: raw.instanceUrl ?? \"\",\n orgId: raw.orgId ?? \"\",\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for Salesforce. Returns every\n * agent-scoped Salesforce connection. One OAuth grant maps to one org, so\n * `accounts[i].accountIdentifier` (and `orgId`) is the Salesforce org id —\n * the selector every credential-touching tool requires.\n */\n async getSalesforceAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n instanceUrl: string;\n orgId: 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 instanceUrl?: string;\n orgId?: string;\n }[];\n }>(\"/agent/connect/salesforce/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 instanceUrl: a.instanceUrl ?? \"\",\n orgId: a.orgId ?? a.accountIdentifier,\n })),\n };\n }\n\n /**\n * Refresh the access token for a specific Salesforce org. Salesforce\n * tokens aren't interchangeable across orgs, so the connection is targeted\n * by `accountIdentifier` (the org id) — mirrors `refreshXeroAccountToken`.\n */\n async refreshSalesforceAccountToken(orgId: string): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n expiresAt: string;\n }> {\n const path = `/agent/connect/salesforce/accounts/${encodeURIComponent(orgId)}/refresh`;\n const raw = await this.request<{\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 * 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 /**\n * Generate an image from a text prompt and get back a STABLE, public URL\n * (served from the agent-assets CDN — it does not expire). The image is\n * generated + stored server-side; embed the returned `imageUrl` in a reply as\n * markdown to show it to the user.\n *\n * Unlike most methods this reads the server's error body so a bad-request\n * detail (e.g. an unsupported `size`) reaches the caller instead of an opaque\n * \"request failed (400)\". Not retried — generation is expensive and\n * non-idempotent.\n */\n async generateImage(args: {\n prompt: string;\n model?: string;\n size?: string;\n quality?: string;\n }): Promise<{ imageUrl: string; model: string }> {\n const headers = new Headers();\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"Content-Type\", \"application/json\");\n // Image generation runs longer than a normal request. The API Gateway\n // integration ceiling is ~30s, so wait just past it: if generation overruns,\n // the gateway returns a readable 504 rather than us aborting first with an\n // opaque client-side TimeoutError. Large sizes / high quality are the most\n // likely to hit this — the tool description steers toward standard sizes.\n const res = await fetch(`${this.apiUrl}/agent/images/generate`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(args),\n signal: AbortSignal.timeout(33_000),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n let detail = \"\";\n try {\n const parsed = JSON.parse(body) as { message?: unknown; error?: unknown };\n const msg =\n typeof parsed.message === \"string\"\n ? parsed.message\n : typeof parsed.error === \"string\"\n ? parsed.error\n : \"\";\n if (msg) detail = `: ${msg}`;\n } catch {\n // non-JSON body — leave detail empty\n }\n throw new Error(`Image generation failed (${String(res.status)})${detail}`);\n }\n const body = (await res.json()) as { data: { imageUrl: string; model: string } };\n return body.data;\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 // ─── Self identity ────────────────────────────────────────────\n //\n // The agent customizes its OWN name / voice / avatar. agentId + tenantId are\n // resolved from the API key — never passed in the path or body. `avatarUrl`\n // is server-set only, via generate/upload, so `updateSelf` intentionally\n // does not accept it.\n\n /** Update the agent's own name and/or voice config. Returns the updated agent. */\n async updateSelf(update: { name?: string; voiceConfig?: AgentVoiceConfig }): Promise<AgentSelf> {\n return this.request<AgentSelf>(\"/agent/self\", {\n method: \"PATCH\",\n body: JSON.stringify(update),\n });\n }\n\n /**\n * Generate the agent's own avatar from a text prompt. The image is generated,\n * stored, and set on the agent server-side; returns the updated agent.\n */\n async generateAvatar(args: { prompt: string }): Promise<AgentSelf> {\n return this.request<AgentSelf>(\"/agent/avatar/generate\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to\n * `uploadUrl`, then call `finalizeAvatar(s3Key)` to set it on the agent.\n */\n async presignAvatar(args: { mimeType: string; size: number }): Promise<AgentAvatarPresign> {\n return this.request<AgentAvatarPresign>(\"/agent/avatar/presign\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Finalize an avatar upload — validates ownership + size, then sets the\n * agent's `avatarUrl` server-side. Returns the updated agent.\n */\n async finalizeAvatar(s3Key: string): Promise<AgentSelf> {\n return this.request<AgentSelf>(\"/agent/avatar\", {\n method: \"POST\",\n body: JSON.stringify({ s3Key }),\n });\n }\n\n /** List the platform voice catalogue (ElevenLabs) so the agent can pick its own voice. */\n async listVoices(): Promise<{ voices: AgentVoice[] }> {\n return this.request<{ voices: AgentVoice[] }>(\"/agent/voices\");\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<{\n synced: boolean;\n syncedAt?: string;\n sessionsBackfillSynced?: boolean;\n sessionsBackfillSyncedAt?: string;\n }> {\n return this.request(\"/agent/memory/bootstrap-status\");\n }\n\n async memoryBootstrapStatusMark(scope?: \"files\" | \"sessions\"): Promise<{ synced: true; syncedAt: string }> {\n return this.request(\"/agent/memory/bootstrap-status\", {\n method: \"POST\",\n ...(scope ? { body: JSON.stringify({ scope }) } : {}),\n });\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 // ─── Knowledge resources (org/team/project) ──────────────\n //\n // Scoped knowledge ABOUT a thing being worked on. Search hits\n // `services/knowledge` (RAG); docs + profile hit `services/org`\n // (system of record + per-agent membership gate). All routes resolve\n // to the agent gateway: search under pathPrefix `/knowledge`, org\n // resources under `/org` — same `/agent/...` mapping as the rest.\n //\n // Every write takes an explicit `scopeId`: an agent sees ALL its member\n // scopes (there is no implicit \"current\" one). For the `org` scope,\n // `scopeId` is the tenantId — discover it from `listScopes()`.\n\n /**\n * Semantic search across the agent's member scopes. Fan-out is gated\n * server-side by `listScopes` set-inclusion (fail-closed). Pass\n * `scopeType` + `scopeId` to narrow to one scope; a non-member scope\n * yields empty results (never a cross-scope leak).\n */\n async knowledgeSearch(\n query: string,\n opts?: { limit?: number; scopeType?: KnowledgeScopeType; scopeId?: string },\n ): Promise<KnowledgeSearchResult> {\n return this.request<KnowledgeSearchResult>(\"/agent/knowledge/search\", {\n method: \"POST\",\n body: JSON.stringify({\n query,\n limit: opts?.limit,\n scopeType: opts?.scopeType,\n scopeId: opts?.scopeId,\n }),\n });\n }\n\n /** Enumerate the scopes (org + teams + projects) this agent belongs to. */\n async listScopes(): Promise<{ scopes: KnowledgeScope[] }> {\n return this.request<{ scopes: KnowledgeScope[] }>(\"/agent/org/scopes\");\n }\n\n /** Read a scope's structured knowledge profile (after membership check). */\n async getScopeProfile(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n ): Promise<KnowledgeProfile> {\n return this.request<KnowledgeProfile>(\n `/agent/org/profile/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}`,\n );\n }\n\n /** List a scope's docs (the org-files corpus; mirrored to shared/<scope>/). */\n async listScopeDocs(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n opts?: { limit?: number; cursor?: string },\n ): Promise<{ files: KnowledgeDoc[]; nextCursor: string | null }> {\n const qs = new URLSearchParams();\n if (opts?.limit !== undefined) qs.set(\"limit\", String(opts.limit));\n if (opts?.cursor) qs.set(\"cursor\", opts.cursor);\n const query = qs.toString();\n return this.request<{ files: KnowledgeDoc[]; nextCursor: string | null }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Read the full text of a scope doc. Resolves a presigned download URL\n * from `services/org`, then fetches the bytes directly from S3 (the one\n * legitimate raw fetch in a plugin — same pattern as sync).\n */\n async readScopeDoc(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n filePath: string,\n ): Promise<{ filePath: string; text: string }> {\n const { downloadUrl } = await this.request<{ downloadUrl: string; expiresIn: number }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}/download/${encodeFilePath(filePath)}`,\n );\n const res = await fetch(downloadUrl, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });\n if (!res.ok) {\n await res.text();\n throw new Error(`Doc download failed (${String(res.status)})`);\n }\n const text = await res.text();\n return { filePath, text };\n }\n\n /**\n * Write (create or overwrite) a scope doc. Two-step presigned upload:\n * `services/org` returns a signed URL plus `requiredHeaders` (author /\n * authorKind / message as `x-amz-meta-*`) that MUST be sent verbatim on\n * the PUT, alongside the same `Content-Type` that was signed. Author and\n * authorKind are server-set from the agent token — never trusted here.\n */\n async writeScopeDoc(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n filePath: string,\n content: string,\n opts?: { contentType?: string; message?: string },\n ): Promise<{ filePath: string }> {\n const contentType = opts?.contentType ?? \"text/markdown\";\n const presign = await this.request<{\n uploadUrl: string;\n filePath: string;\n expiresIn: number;\n requiredHeaders: Record<string, string>;\n }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}/upload/${encodeFilePath(filePath)}`,\n { method: \"POST\", body: JSON.stringify({ contentType, message: opts?.message }) },\n );\n\n const putHeaders = new Headers(presign.requiredHeaders);\n // The presign signed `ContentType` into the URL — the PUT must echo the\n // exact same value or S3 rejects with SignatureDoesNotMatch.\n putHeaders.set(\"Content-Type\", contentType);\n\n const res = await fetch(presign.uploadUrl, {\n method: \"PUT\",\n body: content,\n headers: putHeaders,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text();\n throw new Error(`Doc upload failed (${String(res.status)})`);\n }\n return { filePath: presign.filePath };\n }\n\n // ─── Knowledge change requests ───────────────────────────\n //\n // Propose a change to a scope's knowledge instead of writing it directly.\n // Use this ONLY when the agent is not a member of the target scope (direct\n // resource_write_* is refused there) or otherwise cannot write directly —\n // the proposal is inert until a scope reviewer approves it. Create is gated\n // on a valid agent token only (no membership needed), which is what lets a\n // non-member contribute.\n\n /**\n * Open a change request against a scope's knowledge resource. For a doc\n * create/update, `services/org` returns a presigned staging PUT; this method\n * uploads the proposed `content` to it (echoing the same Content-Type that\n * was signed), mirroring `writeScopeDoc`. The staged body is applied to the\n * canonical doc — attributed to this agent — only when a reviewer approves.\n */\n async proposeScopeChange(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n input: ProposeScopeChangeInput,\n ): Promise<KnowledgeChangeRequest> {\n const isDocBody =\n input.resourceType === \"doc\" && input.operation !== \"delete\";\n const contentType = input.contentType ?? \"text/markdown\";\n\n const result = await this.request<{\n changeRequest: KnowledgeChangeRequest;\n uploadUrl?: string;\n requiredHeaders?: Record<string, string>;\n }>(\n `/agent/org/change-requests/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n resourceType: input.resourceType,\n operation: input.operation,\n rationale: input.rationale,\n targetPath: input.targetPath,\n proposedContentType: isDocBody ? contentType : undefined,\n proposedValue: input.proposedValue,\n }),\n },\n );\n\n // doc create/update: stage the proposed body at the returned presigned PUT.\n if (isDocBody && result.uploadUrl) {\n const putHeaders = new Headers(result.requiredHeaders ?? {});\n // The staging PUT signed `ContentType` into the URL — the PUT must echo\n // the exact same value or S3 rejects with SignatureDoesNotMatch.\n putHeaders.set(\"Content-Type\", contentType);\n const res = await fetch(result.uploadUrl, {\n method: \"PUT\",\n body: input.content ?? \"\",\n headers: putHeaders,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text();\n throw new Error(`Change-request body upload failed (${String(res.status)})`);\n }\n }\n\n return result.changeRequest;\n }\n\n /**\n * List the agent's OWN change requests in a scope (filtered server-side to\n * this agent as proposer). Pass `status` to narrow to open / approved / etc.\n */\n async listScopeChangeRequests(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n opts?: { status?: ChangeRequestStatus; limit?: number; cursor?: string },\n ): Promise<{ changeRequests: KnowledgeChangeRequest[]; nextCursor: string | null }> {\n const qs = new URLSearchParams();\n if (opts?.status) qs.set(\"status\", opts.status);\n if (opts?.limit !== undefined) qs.set(\"limit\", String(opts.limit));\n if (opts?.cursor) qs.set(\"cursor\", opts.cursor);\n const query = qs.toString();\n return this.request<{ changeRequests: KnowledgeChangeRequest[]; nextCursor: string | null }>(\n `/agent/org/change-requests/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}${query ? `?${query}` : \"\"}`,\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 // ─── Remote (interactive relay: browser co-browse takeover) ──────\n //\n // The agent asks a human to complete a step on the live browser it's\n // looking at. `requestBrowserTakeover` creates the session and notifies\n // the user (dashboard tab + chat card + push); the plugin then blocks on\n // the relay's RELEASE_CONTROL for the actual handoff, so no long-lived\n // request is held open here. `completeRemoteSession` marks it done.\n\n async requestBrowserTakeover(args: {\n instructions: string;\n url?: string;\n conversationId?: string;\n }): Promise<{ sessionId: string; status: string }> {\n return this.request(\"/agent/remote/takeover\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async getRemoteSession(sessionId: string): Promise<RemoteSessionInfo> {\n return this.request(`/agent/remote/sessions/${encodeURIComponent(sessionId)}`);\n }\n\n async completeRemoteSession(sessionId: string): Promise<{ ok: boolean }> {\n return this.request(`/agent/remote/sessions/${encodeURIComponent(sessionId)}/complete`, {\n method: \"POST\",\n body: JSON.stringify({}),\n });\n }\n\n // ─── Voice (one-shot TTS / STT) ──────────────────────────────\n //\n // Binary siblings of `request<T>()`. `request()` forces\n // `Content-Type: application/json` and parses a `{ data: T }` envelope,\n // neither of which fits a raw-audio flow, so voice goes through `rawFetch`\n // instead. Auth (Bearer), the request budget, and the single retry on\n // transient 5xx / network errors are kept in sync with `request()`.\n\n /**\n * Issue a request that returns the raw `Response` (no JSON parsing, no\n * forced Content-Type). The caller sets `Content-Type`/`Accept` on `headers`\n * and reads the body itself (`arrayBuffer()` / `json()`).\n *\n * A single retry fires only on the same transient statuses `request()`\n * retries (authorizer-timeout 500 + LB 502/503/504) and transient network\n * errors — before the route handler runs — so re-issuing a POST does not\n * risk a duplicate side effect. Voice TTS/STT are effectively idempotent\n * (re-synthesize / re-transcribe) and meter server-side keyed on the\n * gateway requestId, so a retried transcription doesn't double-bill.\n */\n private async rawFetch(\n path: string,\n init: { method: string; headers: Headers; body?: BodyInit | Uint8Array },\n ): Promise<Response> {\n const url = `${this.apiUrl}${path}`;\n init.headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n\n let lastError: unknown;\n for (let attempt = 1; attempt <= 2; attempt++) {\n try {\n const res = await fetch(url, {\n method: init.method,\n headers: init.headers,\n // undici accepts a Uint8Array/Buffer body at runtime; the DOM\n // `BodyInit` type omits it, so widen through `unknown`.\n body: init.body as BodyInit | undefined,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text(); // drain body\n const error = new Error(`Agent API request failed (${String(res.status)})`);\n if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {\n lastError = error;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw error;\n }\n return res;\n } catch (err) {\n if (attempt === 1 && isRetryableNetworkError(err)) {\n lastError = err;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw err;\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n /**\n * Text-to-speech. Returns raw PCM audio bytes plus their framing — the\n * voice service defaults to 24 kHz / mono / 16-bit. Wrap in a WAV container\n * to produce a playable file. Metered per character against the tenant\n * credit pool server-side; TTS completes regardless of metering outcome.\n */\n async tts(args: VoiceTtsArgs): Promise<VoiceTtsResult> {\n const headers = new Headers();\n headers.set(\"Content-Type\", \"application/json\");\n headers.set(\"Accept\", \"audio/pcm\");\n const res = await this.rawFetch(\"/voice/tts\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(args),\n });\n const audio = Buffer.from(await res.arrayBuffer());\n return {\n audio,\n sampleRate: parseInt(res.headers.get(\"x-sample-rate\") ?? \"24000\", 10),\n channels: parseInt(res.headers.get(\"x-channels\") ?? \"1\", 10),\n bitDepth: parseInt(res.headers.get(\"x-bit-depth\") ?? \"16\", 10),\n };\n }\n\n /**\n * Speech-to-text. Accepts raw linear16 (16-bit LE) mono PCM — NOT a WAV or\n * other container (the endpoint transcribes with a fixed linear16 encoding,\n * so a container header would be transcribed as noise). Strip any WAV header\n * and pass `sampleRate` from it before calling. Metered by transcribed\n * duration against the tenant credit pool server-side.\n */\n async stt(args: VoiceSttArgs): Promise<VoiceSttResult> {\n const headers = new Headers();\n headers.set(\"Content-Type\", \"application/octet-stream\");\n headers.set(\"x-sample-rate\", String(args.sampleRate));\n const res = await this.rawFetch(\"/voice/stt\", {\n method: \"POST\",\n headers,\n body: args.audio,\n });\n const body = (await res.json()) as { data: VoiceSttResult };\n return body.data;\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// ─── Remote (interactive relay) types ────────────────────\n\nexport interface RemoteSessionInfo {\n sessionId: string;\n agentId: string;\n surface: \"browser\" | \"terminal\";\n status:\n | \"agent_driving\"\n | \"awaiting_human\"\n | \"human_in_control\"\n | \"resuming\"\n | \"completed\"\n | \"expired\"\n | \"failed\";\n url?: string;\n instructions?: string;\n requestedAt?: 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// ─── Knowledge resource types (org/team/project) ──────────\n//\n// Scoped, searchable knowledge ABOUT a thing being worked on. The system\n// of record is `services/org` (docs + profile + the membership gate);\n// `services/knowledge` is a pure RAG projection (vector search). `scopeId`\n// for the `org` scope is the tenantId (covers personal + org tenants\n// identically) — agents discover it via `listScopes()`.\n\nexport type KnowledgeScopeType = \"org\" | \"team\" | \"project\";\n\nexport interface KnowledgeScope {\n scopeType: KnowledgeScopeType;\n scopeId: string;\n name: string;\n}\n\nexport interface KnowledgeSearchHit {\n id: string;\n text: string;\n /** Normalized relevance in (0,1]; higher = closer. */\n score: number;\n scopeType: KnowledgeScopeType;\n scopeId: string;\n /**\n * Provenance of the hit. All live results are `\"doc\"`; `\"fact\"` only ever\n * appears for legacy vectors indexed before the facts primitive was removed\n * (the search index stays tolerant of them). Treat every hit as a doc.\n */\n source: \"doc\" | \"fact\";\n /** The canonical file under shared/<scope>/ (present on doc hits). */\n filePath?: string;\n /** Legacy-only: the id of a pre-removal fact vector. */\n factId?: string;\n}\n\nexport interface KnowledgeSearchResult {\n results: KnowledgeSearchHit[];\n /** True when fan-out breadth was capped (more member scopes than the cap). */\n truncatedScopes: boolean;\n}\n\nexport interface KnowledgeProfileLink {\n label: string;\n url: string;\n}\n\nexport interface KnowledgeProfile {\n scopeType: KnowledgeScopeType;\n scopeId: string;\n about: string | null;\n description: string | null;\n links: KnowledgeProfileLink[];\n updatedAt: string | null;\n updatedBy: string | null;\n}\n\nexport interface KnowledgeDoc {\n filePath: string;\n fileName: string;\n contentType?: string;\n size: number;\n uploadedBy?: string;\n createdAt: string;\n updatedAt: string;\n}\n\n// ─── Knowledge change requests ───────────────────────────\n//\n// A change request is a proposed, inert mutation to one knowledge resource.\n// It is the agent's contribution path to a scope it is NOT a member of: the\n// proposal stays inert until a reviewer with scope authority approves it. An\n// agent that IS a member should just write directly (resource_write_*).\n\nexport type ChangeRequestResourceType = \"doc\" | \"profile\";\nexport type ChangeRequestOperation = \"create\" | \"update\" | \"delete\";\nexport type ChangeRequestStatus =\n | \"open\"\n | \"approved\"\n | \"rejected\"\n | \"withdrawn\"\n | \"superseded\";\nexport type ChangeRequestActorKind = \"human\" | \"agent\";\n\n/** Public projection of a change request (mirrors `PublicChangeRequest` in services/org). */\nexport interface KnowledgeChangeRequest {\n changeRequestId: string;\n scopeType: KnowledgeScopeType;\n scopeId: string;\n resourceType: ChangeRequestResourceType;\n operation: ChangeRequestOperation;\n targetPath: string | null;\n baseVersionId: string | null;\n proposedContentType: string | null;\n status: ChangeRequestStatus;\n proposerId: string;\n proposerKind: ChangeRequestActorKind;\n rationale: string;\n reviewerId: string | null;\n reviewerKind: ChangeRequestActorKind | null;\n reviewedAt: string | null;\n reviewNote: string | null;\n appliedRef: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Per-type proposal payload for `proposeScopeChange`. */\nexport interface ProposeScopeChangeInput {\n resourceType: ChangeRequestResourceType;\n operation: ChangeRequestOperation;\n /** Why the change is proposed — shown to the reviewer. */\n rationale: string;\n /** doc: the path the proposal applies to (e.g. designs/data-center.md). */\n targetPath?: string;\n /** doc create/update: the staged body to upload (markdown or other text). */\n content?: string;\n /** doc create/update: content type of the staged body (default text/markdown). */\n contentType?: string;\n /** profile: the proposed value ({ about, description, links }). */\n proposedValue?: unknown;\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\n// Per-request budget. Covers cold-start chains (authorizer + handler\n// + downstream OAuth provider) with headroom; the worst legitimate\n// path observed is ~7s (cold Lambda + Atlassian token exchange).\nconst REQUEST_TIMEOUT_MS = 20_000;\n// Statuses worth one retry — API GW synthesizes 500 on authorizer\n// timeout, 502/503/504 cover upstream cold-start and LB transients.\nconst RETRYABLE_STATUS = new Set([500, 502, 503, 504]);\nconst RETRY_DELAY_MS = 500;\n\n// Async image-generation job polling. Generation runs off-request on a job\n// worker (no API Gateway 30s ceiling), so the client enqueues then polls.\n// The plugin runs in the daemon (not a Lambda), so a multi-minute poll is fine.\nconst IMAGE_POLL_INTERVAL_MS = 2_000;\nconst IMAGE_JOB_TIMEOUT_MS = 180_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction isRetryableNetworkError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // AbortSignal.timeout() rejects with TimeoutError (DOMException).\n if (err.name === \"TimeoutError\" || err.name === \"AbortError\") return true;\n // undici wraps socket-level failures (stale keep-alive connections,\n // ECONNRESET on reused pool entries) in a TypeError \"fetch failed\"\n // with the cause attached.\n if (err.name === \"TypeError\") return true;\n return false;\n}\n\n// ─── Self identity types ─────────────────────────────────\n//\n// The agent customizing its OWN identity (name, avatar, voice). agentId +\n// tenantId are resolved from the token, so no id appears in the request.\n\n/** Voice settings — core agent config. Mirrors `VoiceConfig` in `@alfe/types`. */\nexport interface AgentVoiceConfig {\n /** ElevenLabs voice ID; platform default when unset. */\n voiceId?: string;\n ttsModel?: string;\n enabled?: boolean;\n}\n\n/**\n * The agent's own public identity, as returned by `updateSelf`, `generateAvatar`,\n * `presignAvatar`'s finalize (`finalizeAvatar`). This is the public agent\n * projection; only the identity-relevant fields are typed here — the response\n * carries the full public agent record.\n */\nexport interface AgentSelf {\n agentId: string;\n tenantId: string;\n name: string;\n avatarUrl?: string;\n voiceConfig?: AgentVoiceConfig;\n status: string;\n}\n\n/** Result of `presignAvatar` — the agent PUTs bytes to `uploadUrl`, then finalizes with `s3Key`. */\nexport interface AgentAvatarPresign {\n /** Presigned PUT URL to upload the image bytes to. */\n uploadUrl: string;\n /** Object key — echoed back to `finalizeAvatar`. */\n s3Key: string;\n /** Stable public URL the avatar will be served from once finalized. */\n publicUrl: string;\n /** ISO expiry of the presigned PUT URL. */\n expiresAt: string;\n}\n\n/** A voice in the platform catalogue (ElevenLabs), from `listVoices`. */\nexport interface AgentVoice {\n id: string;\n name: string;\n previewUrl: string;\n description: string;\n labels: Record<string, string>;\n category: string;\n}\n\n// ─── Voice one-shot TTS / STT ────────────────────────────\n//\n// These hit the voice service's agent-authed one-shot endpoints\n// (`/voice/tts`, `/voice/stt`), which are Lambda routes co-located on the\n// shared api gateway under the `voice` mapping key. Both are binary flows —\n// TTS returns raw PCM audio bytes, STT accepts raw PCM audio bytes — so they\n// bypass the JSON `{ data: T }` transport used by every other method here and\n// go through `rawFetch` instead. Metering to the tenant credit pool happens\n// server-side; the caller just gets audio (TTS) or a transcript (STT).\n\n/** The ElevenLabs models with a pricing row — the TTS endpoint rejects any other value. */\nexport type VoiceTtsModel = \"eleven_turbo_v2_5\" | \"eleven_multilingual_v2\";\n\nexport interface VoiceTtsArgs {\n /** Text to synthesize (1–5000 chars — the endpoint enforces this). */\n text: string;\n /** ElevenLabs voice id; platform default when unset. */\n voiceId?: string;\n /** TTS model; `eleven_turbo_v2_5` (lower latency) when unset. */\n model?: VoiceTtsModel;\n}\n\n/** Raw synthesized audio plus its PCM framing (from the response headers). */\nexport interface VoiceTtsResult {\n /** Raw little-endian PCM samples — no container. Wrap in WAV to make a playable file. */\n audio: Buffer;\n /** Samples per second (e.g. 24000). */\n sampleRate: number;\n /** Channel count (mono = 1). */\n channels: number;\n /** Bits per sample (e.g. 16). */\n bitDepth: number;\n}\n\nexport interface VoiceSttArgs {\n /** Raw linear16 (16-bit little-endian) mono PCM samples — no WAV/container header. */\n audio: Uint8Array;\n /** Sample rate of `audio` in Hz (8000–48000). */\n sampleRate: number;\n}\n\nexport interface VoiceSttResult {\n text: string;\n /** Deepgram confidence in (0,1]. */\n confidence: number;\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 // One retry on transient failures. Long-running daemon processes\n // (MCP proxies, the gateway) call this client after multi-hour\n // idle gaps; the first attempt then rides a cold path end-to-end —\n // including the API Gateway Lambda authorizer, which API GW\n // hard-caps at 10s and surfaces as a synthetic 500 WITHOUT ever\n // invoking the route handler. Observed on QA Tester (dev,\n // 2026-06-11): atlassian-mcp-proxy token refreshes failed ~59%\n // of attempts with an 11-12s hang then 500; the same request\n // re-issued seconds later succeeded in ~1.5s. A single retry\n // converts that failure mode into a slow success.\n //\n // Retrying POSTs is safe here: the 500 fires before the handler\n // runs (authorizer timeout), and the one rotating-token endpoint\n // (connect/{provider}/refresh) reads its refresh token from the\n // DB per call, so a duplicate invocation re-rotates cleanly\n // rather than corrupting state.\n let lastError: unknown;\n for (let attempt = 1; attempt <= 2; attempt++) {\n try {\n const res = await fetch(url, {\n ...options,\n headers,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n\n if (!res.ok) {\n await res.text(); // drain body\n const error = new Error(`Agent API request failed (${String(res.status)})`);\n if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {\n lastError = error;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw error;\n }\n\n const body = (await res.json()) as { data: T };\n return body.data;\n } catch (err) {\n if (attempt === 1 && isRetryableNetworkError(err)) {\n lastError = err;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw err;\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\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 * Fetch decrypted credentials for ONE specific connection by its\n * stable connectionId (connection-scoped, vs the provider-scoped\n * `get<Provider>Credentials` helpers). Used by the daemon to resolve\n * a Custom Connection-driven integration's credentials from the\n * exact connection it was installed from — every custom connection\n * shares the `custom` provider id, so provider-scoping is ambiguous.\n *\n * For custom connections `accessToken` is the JSON-encoded secret\n * bundle (the daemon un-bundles it); non-secret fields are on\n * `providerMetadata`. The endpoint enforces that the connection is in\n * the calling agent's effective scope (403 otherwise).\n */\n async getConnectionCredentials(connectionId: string): Promise<{\n provider: string;\n connectionId: string;\n accountIdentifier?: string;\n accessToken?: string;\n providerMetadata?: Record<string, unknown>;\n [key: string]: unknown;\n }> {\n return this.request(\n `/agent/connect/connections/${encodeURIComponent(connectionId)}/credentials`,\n );\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/github-mcp` 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 * @deprecated Returns a single primary credential blob. Use\n * `getSalesforceAccounts()` for the multi-account shape required by\n * Pattern A.\n */\n async getSalesforceCredentials(): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n instanceUrl: string;\n orgId: string;\n }> {\n const raw = await this.request<{\n accessToken: string;\n accessTokenExpiresAt?: string;\n instanceUrl?: string;\n orgId?: string;\n }>(\"/agent/connect/salesforce/credentials\");\n return {\n accessToken: raw.accessToken,\n accessTokenExpiresAt: raw.accessTokenExpiresAt ?? \"\",\n instanceUrl: raw.instanceUrl ?? \"\",\n orgId: raw.orgId ?? \"\",\n };\n }\n\n /**\n * Pattern A: multi-account credential fetch for Salesforce. Returns every\n * agent-scoped Salesforce connection. One OAuth grant maps to one org, so\n * `accounts[i].accountIdentifier` (and `orgId`) is the Salesforce org id —\n * the selector every credential-touching tool requires.\n */\n async getSalesforceAccounts(): Promise<{\n accounts: {\n connectionId: string;\n accountIdentifier: string;\n displayName: string | null;\n connectedAt: string;\n accessToken: string;\n accessTokenExpiresAt: string;\n instanceUrl: string;\n orgId: 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 instanceUrl?: string;\n orgId?: string;\n }[];\n }>(\"/agent/connect/salesforce/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 instanceUrl: a.instanceUrl ?? \"\",\n orgId: a.orgId ?? a.accountIdentifier,\n })),\n };\n }\n\n /**\n * Refresh the access token for a specific Salesforce org. Salesforce\n * tokens aren't interchangeable across orgs, so the connection is targeted\n * by `accountIdentifier` (the org id) — mirrors `refreshXeroAccountToken`.\n */\n async refreshSalesforceAccountToken(orgId: string): Promise<{\n accessToken: string;\n accessTokenExpiresAt: string;\n expiresAt: string;\n }> {\n const path = `/agent/connect/salesforce/accounts/${encodeURIComponent(orgId)}/refresh`;\n const raw = await this.request<{\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 * 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 /**\n * Generate an image from a text prompt and get back a STABLE, public URL\n * (served from the agent-assets CDN — it does not expire). Embed the returned\n * `imageUrl` in a reply as markdown to show it to the user.\n *\n * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway\n * 30s ceiling, so this enqueues a job (`POST /agent/images/generate` →\n * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The\n * worker's real failure message (e.g. an unsupported `size`) surfaces via the\n * job's `error` field.\n */\n async generateImage(args: {\n prompt: string;\n model?: string;\n size?: string;\n quality?: string;\n }): Promise<{ imageUrl: string; model: string }> {\n // Enqueue via a bespoke NON-retrying POST. `scheduleJob` mints a fresh job\n // id per call (not idempotent), so the shared `request()` — which retries\n // POSTs on transient failures — could double-enqueue → two metered\n // generations. A lost enqueue response must fail clean, not retry.\n const headers = new Headers();\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"Content-Type\", \"application/json\");\n const enqueueRes = await fetch(`${this.apiUrl}/agent/images/generate`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(args),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!enqueueRes.ok) {\n throw new Error(`Image generation failed to start (${String(enqueueRes.status)})`);\n }\n const { data: enqueued } = (await enqueueRes.json()) as { data: { jobId: string } };\n const jobId = enqueued.jobId;\n\n // Poll until the worker finishes. A transient poll error is TOLERATED — the\n // job keeps running (and bills) server-side, so a blip must not abandon it;\n // only a terminal `failed` or the deadline ends the wait.\n const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await sleep(IMAGE_POLL_INTERVAL_MS);\n let job: {\n status: \"pending\" | \"running\" | \"completed\" | \"failed\";\n imageUrl?: string;\n model?: string;\n error?: string;\n };\n try {\n job = await this.request(`/agent/images/${jobId}`);\n } catch {\n continue; // transient — keep polling until the deadline\n }\n\n if (job.status === \"completed\") {\n if (!job.imageUrl) throw new Error(\"Image generation completed without a URL\");\n return { imageUrl: job.imageUrl, model: job.model ?? args.model ?? \"gpt-image-1\" };\n }\n if (job.status === \"failed\") {\n const detail = job.error ? `: ${job.error.split(\"\\n\")[0]}` : \"\";\n throw new Error(`Image generation failed${detail}`);\n }\n // pending | running → keep polling\n }\n throw new Error(\"Image generation timed out\");\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 // ─── Self identity ────────────────────────────────────────────\n //\n // The agent customizes its OWN name / voice / avatar. agentId + tenantId are\n // resolved from the API key — never passed in the path or body. `avatarUrl`\n // is server-set only, via generate/upload, so `updateSelf` intentionally\n // does not accept it.\n\n /** Update the agent's own name and/or voice config. Returns the updated agent. */\n async updateSelf(update: { name?: string; voiceConfig?: AgentVoiceConfig }): Promise<AgentSelf> {\n return this.request<AgentSelf>(\"/agent/self\", {\n method: \"PATCH\",\n body: JSON.stringify(update),\n });\n }\n\n /**\n * Generate the agent's own avatar from a text prompt. The image is generated,\n * stored, and set on the agent server-side; returns the updated agent.\n *\n * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`\n * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job\n * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)\n * until the avatar is set. Signature unchanged — the plugin is unaffected.\n */\n async generateAvatar(args: { prompt: string }): Promise<AgentSelf> {\n // Enqueue via a bespoke NON-retrying POST (scheduleJob is not idempotent —\n // a retried enqueue would double-run the metered job).\n const headers = new Headers();\n headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n headers.set(\"Content-Type\", \"application/json\");\n const enqueueRes = await fetch(`${this.apiUrl}/agent/avatar/generate`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(args),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!enqueueRes.ok) {\n throw new Error(`Avatar generation failed to start (${String(enqueueRes.status)})`);\n }\n const { data: enqueued } = (await enqueueRes.json()) as { data: { jobId: string } };\n const jobId = enqueued.jobId;\n\n const deadline = Date.now() + IMAGE_JOB_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await sleep(IMAGE_POLL_INTERVAL_MS);\n let job: {\n status: \"pending\" | \"running\" | \"completed\" | \"failed\";\n agent?: AgentSelf;\n error?: string;\n };\n try {\n job = await this.request(`/agent/avatar/${jobId}`);\n } catch {\n continue; // transient — keep polling until the deadline\n }\n\n if (job.status === \"completed\") {\n if (!job.agent) throw new Error(\"Avatar generation completed without an agent\");\n return job.agent;\n }\n if (job.status === \"failed\") {\n const detail = job.error ? `: ${job.error.split(\"\\n\")[0]}` : \"\";\n throw new Error(`Avatar generation failed${detail}`);\n }\n // pending | running → keep polling\n }\n throw new Error(\"Avatar generation timed out\");\n }\n\n /**\n * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to\n * `uploadUrl`, then call `finalizeAvatar(s3Key)` to set it on the agent.\n */\n async presignAvatar(args: { mimeType: string; size: number }): Promise<AgentAvatarPresign> {\n return this.request<AgentAvatarPresign>(\"/agent/avatar/presign\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n /**\n * Finalize an avatar upload — validates ownership + size, then sets the\n * agent's `avatarUrl` server-side. Returns the updated agent.\n */\n async finalizeAvatar(s3Key: string): Promise<AgentSelf> {\n return this.request<AgentSelf>(\"/agent/avatar\", {\n method: \"POST\",\n body: JSON.stringify({ s3Key }),\n });\n }\n\n /** List the platform voice catalogue (ElevenLabs) so the agent can pick its own voice. */\n async listVoices(): Promise<{ voices: AgentVoice[] }> {\n return this.request<{ voices: AgentVoice[] }>(\"/agent/voices\");\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<{\n synced: boolean;\n syncedAt?: string;\n sessionsBackfillSynced?: boolean;\n sessionsBackfillSyncedAt?: string;\n }> {\n return this.request(\"/agent/memory/bootstrap-status\");\n }\n\n async memoryBootstrapStatusMark(scope?: \"files\" | \"sessions\"): Promise<{ synced: true; syncedAt: string }> {\n return this.request(\"/agent/memory/bootstrap-status\", {\n method: \"POST\",\n ...(scope ? { body: JSON.stringify({ scope }) } : {}),\n });\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 // ─── Knowledge resources (org/team/project) ──────────────\n //\n // Scoped knowledge ABOUT a thing being worked on. Search hits\n // `services/knowledge` (RAG); docs + profile hit `services/org`\n // (system of record + per-agent membership gate). All routes resolve\n // to the agent gateway: search under pathPrefix `/knowledge`, org\n // resources under `/org` — same `/agent/...` mapping as the rest.\n //\n // Every write takes an explicit `scopeId`: an agent sees ALL its member\n // scopes (there is no implicit \"current\" one). For the `org` scope,\n // `scopeId` is the tenantId — discover it from `listScopes()`.\n\n /**\n * Semantic search across the agent's member scopes. Fan-out is gated\n * server-side by `listScopes` set-inclusion (fail-closed). Pass\n * `scopeType` + `scopeId` to narrow to one scope; a non-member scope\n * yields empty results (never a cross-scope leak).\n */\n async knowledgeSearch(\n query: string,\n opts?: { limit?: number; scopeType?: KnowledgeScopeType; scopeId?: string },\n ): Promise<KnowledgeSearchResult> {\n return this.request<KnowledgeSearchResult>(\"/agent/knowledge/search\", {\n method: \"POST\",\n body: JSON.stringify({\n query,\n limit: opts?.limit,\n scopeType: opts?.scopeType,\n scopeId: opts?.scopeId,\n }),\n });\n }\n\n /** Enumerate the scopes (org + teams + projects) this agent belongs to. */\n async listScopes(): Promise<{ scopes: KnowledgeScope[] }> {\n return this.request<{ scopes: KnowledgeScope[] }>(\"/agent/org/scopes\");\n }\n\n /** Read a scope's structured knowledge profile (after membership check). */\n async getScopeProfile(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n ): Promise<KnowledgeProfile> {\n return this.request<KnowledgeProfile>(\n `/agent/org/profile/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}`,\n );\n }\n\n /** List a scope's docs (the org-files corpus; mirrored to shared/<scope>/). */\n async listScopeDocs(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n opts?: { limit?: number; cursor?: string },\n ): Promise<{ files: KnowledgeDoc[]; nextCursor: string | null }> {\n const qs = new URLSearchParams();\n if (opts?.limit !== undefined) qs.set(\"limit\", String(opts.limit));\n if (opts?.cursor) qs.set(\"cursor\", opts.cursor);\n const query = qs.toString();\n return this.request<{ files: KnowledgeDoc[]; nextCursor: string | null }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}${query ? `?${query}` : \"\"}`,\n );\n }\n\n /**\n * Read the full text of a scope doc. Resolves a presigned download URL\n * from `services/org`, then fetches the bytes directly from S3 (the one\n * legitimate raw fetch in a plugin — same pattern as sync).\n */\n async readScopeDoc(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n filePath: string,\n ): Promise<{ filePath: string; text: string }> {\n const { downloadUrl } = await this.request<{ downloadUrl: string; expiresIn: number }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}/download/${encodeFilePath(filePath)}`,\n );\n const res = await fetch(downloadUrl, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });\n if (!res.ok) {\n await res.text();\n throw new Error(`Doc download failed (${String(res.status)})`);\n }\n const text = await res.text();\n return { filePath, text };\n }\n\n /**\n * Write (create or overwrite) a scope doc. Two-step presigned upload:\n * `services/org` returns a signed URL plus `requiredHeaders` (author /\n * authorKind / message as `x-amz-meta-*`) that MUST be sent verbatim on\n * the PUT, alongside the same `Content-Type` that was signed. Author and\n * authorKind are server-set from the agent token — never trusted here.\n */\n async writeScopeDoc(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n filePath: string,\n content: string,\n opts?: { contentType?: string; message?: string },\n ): Promise<{ filePath: string }> {\n const contentType = opts?.contentType ?? \"text/markdown\";\n const presign = await this.request<{\n uploadUrl: string;\n filePath: string;\n expiresIn: number;\n requiredHeaders: Record<string, string>;\n }>(\n `/agent/org/files/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}/upload/${encodeFilePath(filePath)}`,\n { method: \"POST\", body: JSON.stringify({ contentType, message: opts?.message }) },\n );\n\n const putHeaders = new Headers(presign.requiredHeaders);\n // The presign signed `ContentType` into the URL — the PUT must echo the\n // exact same value or S3 rejects with SignatureDoesNotMatch.\n putHeaders.set(\"Content-Type\", contentType);\n\n const res = await fetch(presign.uploadUrl, {\n method: \"PUT\",\n body: content,\n headers: putHeaders,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text();\n throw new Error(`Doc upload failed (${String(res.status)})`);\n }\n return { filePath: presign.filePath };\n }\n\n // ─── Knowledge change requests ───────────────────────────\n //\n // Propose a change to a scope's knowledge instead of writing it directly.\n // Use this ONLY when the agent is not a member of the target scope (direct\n // resource_write_* is refused there) or otherwise cannot write directly —\n // the proposal is inert until a scope reviewer approves it. Create is gated\n // on a valid agent token only (no membership needed), which is what lets a\n // non-member contribute.\n\n /**\n * Open a change request against a scope's knowledge resource. For a doc\n * create/update, `services/org` returns a presigned staging PUT; this method\n * uploads the proposed `content` to it (echoing the same Content-Type that\n * was signed), mirroring `writeScopeDoc`. The staged body is applied to the\n * canonical doc — attributed to this agent — only when a reviewer approves.\n */\n async proposeScopeChange(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n input: ProposeScopeChangeInput,\n ): Promise<KnowledgeChangeRequest> {\n const isDocBody =\n input.resourceType === \"doc\" && input.operation !== \"delete\";\n const contentType = input.contentType ?? \"text/markdown\";\n\n const result = await this.request<{\n changeRequest: KnowledgeChangeRequest;\n uploadUrl?: string;\n requiredHeaders?: Record<string, string>;\n }>(\n `/agent/org/change-requests/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n resourceType: input.resourceType,\n operation: input.operation,\n rationale: input.rationale,\n targetPath: input.targetPath,\n proposedContentType: isDocBody ? contentType : undefined,\n proposedValue: input.proposedValue,\n }),\n },\n );\n\n // doc create/update: stage the proposed body at the returned presigned PUT.\n if (isDocBody && result.uploadUrl) {\n const putHeaders = new Headers(result.requiredHeaders ?? {});\n // The staging PUT signed `ContentType` into the URL — the PUT must echo\n // the exact same value or S3 rejects with SignatureDoesNotMatch.\n putHeaders.set(\"Content-Type\", contentType);\n const res = await fetch(result.uploadUrl, {\n method: \"PUT\",\n body: input.content ?? \"\",\n headers: putHeaders,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text();\n throw new Error(`Change-request body upload failed (${String(res.status)})`);\n }\n }\n\n return result.changeRequest;\n }\n\n /**\n * List the agent's OWN change requests in a scope (filtered server-side to\n * this agent as proposer). Pass `status` to narrow to open / approved / etc.\n */\n async listScopeChangeRequests(\n scopeType: KnowledgeScopeType,\n scopeId: string,\n opts?: { status?: ChangeRequestStatus; limit?: number; cursor?: string },\n ): Promise<{ changeRequests: KnowledgeChangeRequest[]; nextCursor: string | null }> {\n const qs = new URLSearchParams();\n if (opts?.status) qs.set(\"status\", opts.status);\n if (opts?.limit !== undefined) qs.set(\"limit\", String(opts.limit));\n if (opts?.cursor) qs.set(\"cursor\", opts.cursor);\n const query = qs.toString();\n return this.request<{ changeRequests: KnowledgeChangeRequest[]; nextCursor: string | null }>(\n `/agent/org/change-requests/${encodeURIComponent(scopeType)}/${encodeURIComponent(scopeId)}${query ? `?${query}` : \"\"}`,\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 // ─── Remote (interactive relay: browser co-browse takeover) ──────\n //\n // The agent asks a human to complete a step on the live browser it's\n // looking at. `requestBrowserTakeover` creates the session and notifies\n // the user (dashboard tab + chat card + push); the plugin then blocks on\n // the relay's RELEASE_CONTROL for the actual handoff, so no long-lived\n // request is held open here. `completeRemoteSession` marks it done.\n\n async requestBrowserTakeover(args: {\n instructions: string;\n url?: string;\n conversationId?: string;\n }): Promise<{ sessionId: string; status: string }> {\n return this.request(\"/agent/remote/takeover\", {\n method: \"POST\",\n body: JSON.stringify(args),\n });\n }\n\n async getRemoteSession(sessionId: string): Promise<RemoteSessionInfo> {\n return this.request(`/agent/remote/sessions/${encodeURIComponent(sessionId)}`);\n }\n\n async completeRemoteSession(sessionId: string): Promise<{ ok: boolean }> {\n return this.request(`/agent/remote/sessions/${encodeURIComponent(sessionId)}/complete`, {\n method: \"POST\",\n body: JSON.stringify({}),\n });\n }\n\n // ─── Voice (one-shot TTS / STT) ──────────────────────────────\n //\n // Binary siblings of `request<T>()`. `request()` forces\n // `Content-Type: application/json` and parses a `{ data: T }` envelope,\n // neither of which fits a raw-audio flow, so voice goes through `rawFetch`\n // instead. Auth (Bearer), the request budget, and the single retry on\n // transient 5xx / network errors are kept in sync with `request()`.\n\n /**\n * Issue a request that returns the raw `Response` (no JSON parsing, no\n * forced Content-Type). The caller sets `Content-Type`/`Accept` on `headers`\n * and reads the body itself (`arrayBuffer()` / `json()`).\n *\n * A single retry fires only on the same transient statuses `request()`\n * retries (authorizer-timeout 500 + LB 502/503/504) and transient network\n * errors — before the route handler runs — so re-issuing a POST does not\n * risk a duplicate side effect. Voice TTS/STT are effectively idempotent\n * (re-synthesize / re-transcribe) and meter server-side keyed on the\n * gateway requestId, so a retried transcription doesn't double-bill.\n */\n private async rawFetch(\n path: string,\n init: { method: string; headers: Headers; body?: BodyInit | Uint8Array },\n ): Promise<Response> {\n const url = `${this.apiUrl}${path}`;\n init.headers.set(\"Authorization\", `Bearer ${this.apiKey}`);\n\n let lastError: unknown;\n for (let attempt = 1; attempt <= 2; attempt++) {\n try {\n const res = await fetch(url, {\n method: init.method,\n headers: init.headers,\n // undici accepts a Uint8Array/Buffer body at runtime; the DOM\n // `BodyInit` type omits it, so widen through `unknown`.\n body: init.body as BodyInit | undefined,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) {\n await res.text(); // drain body\n const error = new Error(`Agent API request failed (${String(res.status)})`);\n if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {\n lastError = error;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw error;\n }\n return res;\n } catch (err) {\n if (attempt === 1 && isRetryableNetworkError(err)) {\n lastError = err;\n await sleep(RETRY_DELAY_MS);\n continue;\n }\n throw err;\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n /**\n * Text-to-speech. Returns raw PCM audio bytes plus their framing — the\n * voice service defaults to 24 kHz / mono / 16-bit. Wrap in a WAV container\n * to produce a playable file. Metered per character against the tenant\n * credit pool server-side; TTS completes regardless of metering outcome.\n */\n async tts(args: VoiceTtsArgs): Promise<VoiceTtsResult> {\n const headers = new Headers();\n headers.set(\"Content-Type\", \"application/json\");\n headers.set(\"Accept\", \"audio/pcm\");\n const res = await this.rawFetch(\"/voice/tts\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(args),\n });\n const audio = Buffer.from(await res.arrayBuffer());\n return {\n audio,\n sampleRate: parseInt(res.headers.get(\"x-sample-rate\") ?? \"24000\", 10),\n channels: parseInt(res.headers.get(\"x-channels\") ?? \"1\", 10),\n bitDepth: parseInt(res.headers.get(\"x-bit-depth\") ?? \"16\", 10),\n };\n }\n\n /**\n * Speech-to-text. Accepts raw linear16 (16-bit LE) mono PCM — NOT a WAV or\n * other container (the endpoint transcribes with a fixed linear16 encoding,\n * so a container header would be transcribed as noise). Strip any WAV header\n * and pass `sampleRate` from it before calling. Metered by transcribed\n * duration against the tenant credit pool server-side.\n */\n async stt(args: VoiceSttArgs): Promise<VoiceSttResult> {\n const headers = new Headers();\n headers.set(\"Content-Type\", \"application/octet-stream\");\n headers.set(\"x-sample-rate\", String(args.sampleRate));\n const res = await this.rawFetch(\"/voice/stt\", {\n method: \"POST\",\n headers,\n body: args.audio,\n });\n const body = (await res.json()) as { data: VoiceSttResult };\n return body.data;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/agent-api-client",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Agent self-service API client — agents calling /agents/ endpoints",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",