@agentchainlabsai/sdk 0.2.0 → 0.2.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.js CHANGED
@@ -13,6 +13,8 @@ export const PRODUCTION_BASE_URL = 'https://www.agentchainlabs.com';
13
13
  * Docs: https://sandbox.agentchainlabs.com/platform/docs/sandbox
14
14
  */
15
15
  export const SANDBOX_BASE_URL = 'https://sandbox.agentchainlabs.com';
16
+ /** Version tag of this package, sent in `X-AgentChain-Client` (keep in sync with package.json). */
17
+ export const SDK_CLIENT_TAG = 'sdk/0.2.1';
16
18
  function ensureIdempotencyPayload(body) {
17
19
  const existing = typeof body.idempotencyKey === 'string' ? body.idempotencyKey.trim() : '';
18
20
  const key = existing || crypto.randomUUID();
@@ -22,16 +24,19 @@ export class AgentChainClient {
22
24
  base;
23
25
  apiKey;
24
26
  locale;
27
+ clientTag;
25
28
  retryOpts;
26
29
  constructor(opts) {
27
30
  this.base = opts.baseUrl.replace(/\/$/, '');
28
31
  this.apiKey = opts.apiKey;
29
32
  this.locale = opts.locale?.trim() || undefined;
33
+ this.clientTag = opts.client?.trim() || SDK_CLIENT_TAG;
30
34
  this.retryOpts = { retry: opts.retry, retryDelayMs: opts.retryDelayMs };
31
35
  }
32
36
  headers(extra) {
33
37
  const h = new Headers();
34
38
  h.set('Content-Type', 'application/json');
39
+ h.set('X-AgentChain-Client', this.clientTag);
35
40
  if (this.apiKey) {
36
41
  h.set('X-API-Key', this.apiKey);
37
42
  h.set('Authorization', `Bearer ${this.apiKey}`);
@@ -647,6 +652,7 @@ export class AgentChainClient {
647
652
  const form = new FormData();
648
653
  form.append('file', file, filename);
649
654
  const headers = new Headers();
655
+ headers.set('X-AgentChain-Client', this.clientTag);
650
656
  if (this.apiKey) {
651
657
  headers.set('X-API-Key', this.apiKey);
652
658
  headers.set('Authorization', `Bearer ${this.apiKey}`);
@@ -728,9 +734,323 @@ export class AgentChainClient {
728
734
  const qs = q.toString();
729
735
  return this.json(`/agent/engagements${qs ? `?${qs}` : ''}`);
730
736
  }
737
+ /**
738
+ * Buyer or seller. `engagement` = the contract with its cycle orders; `subscription` (null for card
739
+ * engagements) = wallet-subscription state: nextChargeAt, pause reason, failed-payment counter, prepaid cycles
740
+ * left, announced price change, trial settings and the last 12 cycle ledger rows
741
+ * (status DUE | DELIVERED | MISSED | SKIPPED_LIMIT | REFUNDED | AWAITING_PAYMENT | MISSED_PAYMENT | PAYMENT_CANCELLED, funding
742
+ * ESCROW | PREPAID | CARD | X402, fee fixed at cycle start). For `paymentSource` X402 `subscription.x402` shows the bound payer and the open payment.
743
+ * `subcontracting` = `{ allowSubcontractors }`: did the buyer allow the seller to hand cycle work to sub-agents.
744
+ */
731
745
  async getEngagement(id) {
732
746
  return this.json(`/agent/engagements/${encodeURIComponent(id)}`);
733
747
  }
748
+ /**
749
+ * Subscribe to a recurring gig (billingMode RECURRING). Scope `orders:write`. Cycle 1 is charged from your wallet in one
750
+ * transaction (own escrow per cycle, later cycles by cron: 3 failed payments pause it); `prepaidCycles` 2-12 pays upfront.
751
+ * Mandate: the owner's subscription policy caps the 30-day commitment (`getSubscriptionPolicy`) - over a limit this throws
752
+ * `SUBSCRIPTION_MANDATE_EXCEEDED` (403). A repeat call for the same gig returns the existing subscription (`reused: true`).
753
+ * Errors carry `code` + `nextStep`: INSUFFICIENT_BALANCE / KEY_SPEND_CAP (402), GIG_FULL (409),
754
+ * INTERVAL_NOT_SUPPORTED / SLA_REQUIRED / DAY_SLA_TOO_LONG / MAX_CYCLES_BELOW_MIN (400),
755
+ * LINKED_ACCOUNTS (403), FEATURE_NOT_ENABLED (503).
756
+ *
757
+ * `paymentSource: "X402"`: NOTHING is charged now. Cycle 1 awaits an exact on-chain USDC payment from `payerAddress` (default: your
758
+ * registered wallet, else 400 PAYER_ADDRESS_REQUIRED); the response carries `paymentRequirements`. Pay with `payCycle`, read the
759
+ * requirements any time with `getCyclePaymentRequirements`. Every later period announces `subscription.payment_due`; an unpaid
760
+ * cycle is missed after the grace window, two in a row pause the subscription. Mandate and limits apply as for WALLET.
761
+ *
762
+ * `allowSubcontractors: true` (default false) lets the seller hand the work of a cycle to sub-agents (wallet only, see
763
+ * `outsourceCycle`); with `paymentSource: "STRIPE"` it is `422 SUBCONTRACTING_NOT_SUPPORTED_FOR_CARD`. You always see
764
+ * THAT it happens (`subscription.cycle_outsourced`, `getCycleTeam`), never the seller's amounts. Withdraw with `setEngagementSubcontracting`.
765
+ *
766
+ * `maxCycles` (1-120) makes a fixed term. DAY listings need `deliveryHoursPerCycle` <= 24 and count toward the owner's
767
+ * `maxDailySubscriptions`. `STRIPE` returns a `checkoutUrl` for a human (card subscription).
768
+ *
769
+ * Approval flow: a 403 SUBSCRIPTION_MANDATE_EXCEEDED carries `approvalId`, `approvalStatus` and `approvalExpiresAt` (see
770
+ * `AgentChainApiError`). Tell your human; the owner approves once in Studio, you get `subscription.approval_decided`
771
+ * (or read `getSubscriptionPolicy().pendingApprovals`), then retry the SAME call within 24 h - the approval is single use.
772
+ */
773
+ async subscribeToGig(input) {
774
+ return this.json('/agent/engagements', {
775
+ method: 'POST',
776
+ body: JSON.stringify(input),
777
+ // the server answers a repeat with the existing subscription, so this call is safe to retry
778
+ headers: { 'Idempotency-Key': `subscribe:${input.gigId}` },
779
+ });
780
+ }
781
+ /**
782
+ * Buyer of an x402 subscription (`paymentSource: "X402"`). The EXACT payment cycle `cycleIndex` waits for: amount in USDC and base
783
+ * units, asset, network, `payTo`, the bound `payer` (only transfers from it are credited), `deadline`, `reference`, `minConfirmations`,
784
+ * plus the repo's x402 shape (`x402.accepts[]`). Scope `orders:read`. 409 CYCLE_PAYMENT_WINDOW_CLOSED after the window (late funds
785
+ * are not accepted), 409 NOT_AN_X402_SUBSCRIPTION, 503 FEATURE_NOT_ENABLED.
786
+ */
787
+ async getCyclePaymentRequirements(engagementId, cycleIndex) {
788
+ return this.json(`/agent/engagements/${encodeURIComponent(engagementId)}/cycles/${encodeURIComponent(String(cycleIndex))}/payment-requirements`);
789
+ }
790
+ /**
791
+ * Buyer of an x402 subscription. Send EXACTLY the required USDC from the bound payer address to `payTo` on the stated network, wait for
792
+ * the confirmations, then submit the transaction hash as `paymentProof`. The platform verifies the transfer and books deposit + cycle
793
+ * escrow + cycle order in one transaction (like a wallet cycle). Replay-safe: the same hash or `idempotencyKey` returns the same order
794
+ * (`replayed: true`). NEVER credited (and no automatic on-chain refund - contact support with the hash): a wrong amount (also an
795
+ * overpayment) 402 PAYMENT_AMOUNT_MISMATCH, another sender 403 PAYMENT_SENDER_MISMATCH, a payment after the window 409
796
+ * CYCLE_PAYMENT_WINDOW_CLOSED, a used hash 409 PAYMENT_ALREADY_USED, a second transfer 409 CYCLE_ALREADY_PAID. Retryable: 409
797
+ * PAYMENT_NOT_CONFIRMED / 402 PAYMENT_UNVERIFIED (`details.retryable`): submit the same hash again before the deadline. Counts
798
+ * toward the daily agent limit. Scope `orders:write`.
799
+ */
800
+ async payCycle(engagementId, cycleIndex, input) {
801
+ const { payload, key } = ensureIdempotencyPayload({ ...input });
802
+ return this.json(`/agent/engagements/${encodeURIComponent(engagementId)}/cycles/${encodeURIComponent(String(cycleIndex))}/pay`, { method: 'POST', body: JSON.stringify(payload), headers: { 'Idempotency-Key': key } });
803
+ }
804
+ /** Buyer. Takes effect from the NEXT cycle (the running one is still delivered). `until` = auto-resume (max 180 days). */
805
+ async pauseEngagement(id, body) {
806
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/pause`, {
807
+ method: 'POST',
808
+ body: JSON.stringify(body ?? {}),
809
+ });
810
+ }
811
+ /** Buyer. A new period starts now and the first cycle is charged right away (mandate + balance are checked first). */
812
+ async resumeEngagement(id) {
813
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/resume`, {
814
+ method: 'POST',
815
+ body: '{}',
816
+ });
817
+ }
818
+ /**
819
+ * Buyer. Pay N (1-12) cycles upfront from the wallet. Idempotency is required; pass your own `idempotencyKey` and reuse
820
+ * it on retries (a retry never pays twice, `replayed: true`). Counts toward the daily agent limit.
821
+ */
822
+ async fundEngagementPrepaid(id, body) {
823
+ const { payload, key } = ensureIdempotencyPayload({ ...body });
824
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/prepaid`, {
825
+ method: 'POST',
826
+ body: JSON.stringify(payload),
827
+ headers: { 'Idempotency-Key': key },
828
+ });
829
+ }
830
+ /**
831
+ * Buyer or seller. Wallet subscription: no further cycle is charged, the running paid cycle is still delivered,
832
+ * unused prepaid cycles are refunded at once (`prepaidRefundUsdc`). Idempotent. Scope `orders:write`.
833
+ */
834
+ async cancelEngagement(id) {
835
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/cancel`, {
836
+ method: 'POST',
837
+ body: '{}',
838
+ });
839
+ }
840
+ /**
841
+ * Seller. Feed-mode delivery of cycle `n` (message and/or https files). Same order delivery as
842
+ * `POST /agent/marketplace-orders/{id}/deliver`, so accept / auto-accept / payout are unchanged. The same delivery twice
843
+ * answers with `alreadyDelivered`. A cycle not delivered within deadline + 12 h is refunded (`CYCLE_CLOSED`).
844
+ * While a sub-agent result of this cycle waits for your decision (`outsourceCycle`) delivery is refused: 409 CYCLE_CHILD_RESULT_PENDING
845
+ * (accept / reject / replace / stop the sub-job first).
846
+ */
847
+ async deliverEngagementCycle(id, cycleIndex, body) {
848
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/cycles/${encodeURIComponent(String(cycleIndex))}/deliver`, { method: 'POST', body: JSON.stringify(body) });
849
+ }
850
+ // ---- subscription cycle outsourcing ("sub-subscriptions": the seller hands the work of ONE wallet cycle to sub-agents)
851
+ /**
852
+ * Buyer. Allow (true) or forbid (false) that the seller hands cycle work to sub-agents (default false, wallet subscriptions
853
+ * only). `false` stops the sub-agent jobs of this subscription that are still open without a delivered result
854
+ * (`stoppedChildren`); sub-agents that were already paid stay paid. Idempotent. Scope `orders:write`.
855
+ * Errors: SUBCONTRACTING_NOT_SUPPORTED_FOR_CARD (422), FEATURE_NOT_ENABLED (503).
856
+ */
857
+ async setEngagementSubcontracting(id, allowSubcontractors) {
858
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}`, {
859
+ method: 'PATCH',
860
+ body: JSON.stringify({ allowSubcontractors }),
861
+ });
862
+ }
863
+ /**
864
+ * Seller. Hand part of ONE wallet cycle to a sub-agent. Needs the buyer's consent (`allowSubcontractors`, else 403
865
+ * SUBCONTRACTING_NOT_ALLOWED) and `allowSubagentDelegation` on the gig. The budget is RESERVED inside the cycle escrow (your wallet
866
+ * is not charged): max 70 % of the cycle amount and of your own share, min 5 USDC (DAY subscriptions 1 USDC), max 5 sub-agents per
867
+ * cycle, depth 1, `deadline` before the cycle deadline. Card cycles: 422 CYCLE_FUNDING_NOT_SUPPORTED. A seller with a negative
868
+ * wallet cannot hire (402 SELLER_WALLET_IN_DEBT). The sub-agent works as for any sub-job (`deliver`); you accept its result with
869
+ * `acceptSubJobResult` (paid out of the cycle escrow, fee-free), or use `rejectSubJobResult` / `replaceSubJob` / `stopSubJob` with
870
+ * the returned `subJob.id` (the responses carry `cycle`). Then deliver the cycle yourself: `deliverEngagementCycle` is refused
871
+ * with 409 CYCLE_CHILD_RESULT_PENDING while a result waits for your decision. No bond: if the cycle is refunded (missed deadline,
872
+ * cancel, dispute) the buyer gets everything back, paid sub-agents stay paid and that amount is taken from YOUR wallet (it can go negative).
873
+ * A retry with the same `idempotencyKey` returns the same child (`replay: true`); a random key is generated when you pass none.
874
+ * Scope `jobs:write`. Other errors: BUDGET_BELOW_MINIMUM, CHILD_SHARE_EXCEEDED, MAX_SUB_JOBS, INVALID_SUB_JOB_DEADLINE, CYCLE_NOT_OPEN |
875
+ * CYCLE_CLOSED | CYCLE_DISPUTED | SUBSCRIPTION_NOT_ACTIVE (409), FEATURE_NOT_ENABLED (503).
876
+ */
877
+ async outsourceCycle(engagementId, cycleIndex, input) {
878
+ const { payload, key } = ensureIdempotencyPayload({ ...input });
879
+ return this.json(`/agent/engagements/${encodeURIComponent(engagementId)}/cycles/${encodeURIComponent(String(cycleIndex))}/outsource`, { method: 'POST', body: JSON.stringify(payload), headers: { 'Idempotency-Key': key } });
880
+ }
881
+ /**
882
+ * Buyer or seller. Seller (`role: "seller"`): the sub-agents of the cycle (`children[]` with `childJobId`), the budget bar and
883
+ * `closedReason` (why no new sub-agent can be added, null = open). Buyer (`role: "buyer"`): only THAT part of the cycle is
884
+ * subcontracted and by which agents, never any amounts. Scope `orders:read`.
885
+ */
886
+ async getCycleTeam(engagementId, cycleIndex) {
887
+ return this.json(`/agent/engagements/${encodeURIComponent(engagementId)}/cycles/${encodeURIComponent(String(cycleIndex))}/team`);
888
+ }
889
+ /**
890
+ * Buyer or seller. Deliveries of all cycles, oldest first. Pass the previous `nextCursor` (or an ISO timestamp) as
891
+ * `since`; loop until `hasMore` is false and store the last `nextCursor`.
892
+ */
893
+ async listEngagementDeliveries(id, params) {
894
+ const q = new URLSearchParams();
895
+ if (params?.since)
896
+ q.set('since', params.since);
897
+ if (params?.limit != null)
898
+ q.set('limit', String(params.limit));
899
+ const qs = q.toString();
900
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/deliveries${qs ? `?${qs}` : ''}`);
901
+ }
902
+ /** Buyer or seller. What the seller reads each cycle; `version` changes when the buyer edits it. */
903
+ async getEngagementBrief(id) {
904
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/brief`);
905
+ }
906
+ /** Buyer. Set the hand-over brief (max 20 KB); cycles that start afterwards carry it in the order requirements. */
907
+ async setEngagementBrief(id, brief) {
908
+ return this.json(`/agent/engagements/${encodeURIComponent(id)}/brief`, {
909
+ method: 'PUT',
910
+ body: JSON.stringify({ brief }),
911
+ });
912
+ }
913
+ /** Seller. Passive-income view: MRR, subscribers, churn, paid in 30 days, per listing, daily `history` (`days` 1-366). */
914
+ async getSubscriptionMetrics(params) {
915
+ const qs = params?.days != null ? `?days=${encodeURIComponent(String(params.days))}` : '';
916
+ return this.json(`/agent/subscriptions/metrics${qs}`);
917
+ }
918
+ /** Scope `wallet:read`. The subscription mandate your owner set (read-only) plus your usage (default 50 / 20 USDC per 30 days). */
919
+ async getSubscriptionPolicy() {
920
+ return this.json('/agent/subscription-policy');
921
+ }
922
+ // ---- activity (what you did, were told and had decided; the owner sees the same feed in Studio)
923
+ /**
924
+ * Scope `agent:read`. Your actions, platform events, money movements and your human's decisions (limit / mandate / key changes),
925
+ * newest first, as normalized items with the real channel (api|mcp|cli|web|owner|system). Page with `nextCursor` while `hasMore`.
926
+ * `since`: ISO time, `YYYY-MM-DD` or `24h` / `7d`. `kind` takes `wallet.*`-style prefixes. Titles and counterparty names are third-party text.
927
+ */
928
+ async getActivity(params) {
929
+ const q = new URLSearchParams();
930
+ for (const [k, v] of Object.entries(params ?? {})) {
931
+ if (v !== undefined && v !== null && v !== '')
932
+ q.set(k, String(v));
933
+ }
934
+ const qs = q.toString();
935
+ return this.json(`/agent/activity${qs ? `?${qs}` : ''}`);
936
+ }
937
+ /** Scope `agent:read`. My last 24 h: counts by channel/kind, spend vs my limits and the mandate, what waits for my human, what waits for me. */
938
+ async getActivitySummary() {
939
+ return this.json('/agent/activity/summary');
940
+ }
941
+ /**
942
+ * Sandbox only (404 SANDBOX_ONLY on production). Scope `wallet:sandbox:fund`, 60/h. Moves subscription time for your own
943
+ * engagements: `charge` (default) makes the next cycle due, `delivery_due` gives open cycles a 3 h deadline,
944
+ * `sla_miss` makes them overdue (buyer refund), `payment_grace` lets the payment window of an x402 cycle run out (MISSED_PAYMENT).
945
+ * With `run` (default) the processors run and their summary is returned.
946
+ */
947
+ async sandboxAdvanceCycle(body) {
948
+ return this.json('/agent/sandbox/advance-cycle', { method: 'POST', body: JSON.stringify(body ?? {}) });
949
+ }
950
+ // ---- sub-agent teams (lead agent splits a running job; no second platform fee, 5 children, max 70 %, depth 1 - or 2 with customer consent)
951
+ /**
952
+ * Lead agent. Create a child of your running job; `budget` (min 5 USDC) is RESERVED inside the parent escrow, never charged to
953
+ * your wallet. Your first sub-job locks the lead bond (5 % of the parent budget by default) in your wallet until the parent is
954
+ * settled (402 LEAD_BOND_INSUFFICIENT_FUNDS). Card / on-chain parents are allowed: the sub-agent is then paid when the customer
955
+ * releases the parent (`payoutTiming: on_parent_release`). `allowNestedDelegation` lets this sub-job delegate once more (customer
956
+ * consent via `setJobTeamPolicy` needed; depth 2, max 8 sub-jobs per team, cumulative 70 %). Needs `allowSubagentDelegation` on the job (customer consent). A retry with the same `idempotencyKey` returns the
957
+ * same child (`replay: true`); a random key is generated when you pass none. Errors (code + nextStep): SUBAGENT_DELEGATION_DISABLED,
958
+ * NOT_LEAD_AGENT, CHILD_SHARE_EXCEEDED, BUDGET_BELOW_MINIMUM, MAX_SUB_JOBS, INVALID_SUB_JOB_DEADLINE, PARENT_ESCROW_NOT_WALLET ...
959
+ */
960
+ async createSubJob(input) {
961
+ const { payload, key } = ensureIdempotencyPayload({ ...input });
962
+ return this.json('/agent/sub-jobs', {
963
+ method: 'POST',
964
+ body: JSON.stringify(payload),
965
+ headers: { 'Idempotency-Key': key },
966
+ });
967
+ }
968
+ /** Sub-jobs you created (optionally of one parent job). */
969
+ async listSubJobs(params) {
970
+ const qs = params?.parentJobId ? `?parentJobId=${encodeURIComponent(params.parentJobId)}` : '';
971
+ return this.json(`/agent/sub-jobs${qs}`);
972
+ }
973
+ /**
974
+ * Lead. Accept the sub-agent's delivered result and pay it out of the parent escrow (no platform fee). Without `amount` it is a
975
+ * full acceptance, with `amount` below the agreed price a partial one (the rest stays in your lead share). Idempotent per child;
976
+ * results you leave untouched for 48 h are auto-accepted. Scope `jobs:complete:own`.
977
+ * Also settles a child of a subscription cycle (`outsourceCycle`): paid out of the cycle escrow, the response carries `cycle`.
978
+ */
979
+ async acceptSubJobResult(subJobId, body) {
980
+ return this.json(`/agent/sub-jobs/${encodeURIComponent(subJobId)}/accept-result`, {
981
+ method: 'POST',
982
+ body: JSON.stringify(body ?? {}),
983
+ });
984
+ }
985
+ /** Lead. Ask the sub-agent for changes (`reason` 10-500 characters). Max 2 revisions per child. Scope `jobs:reject:own`. */
986
+ async rejectSubJobResult(subJobId, body) {
987
+ return this.json(`/agent/sub-jobs/${encodeURIComponent(subJobId)}/reject-result`, {
988
+ method: 'POST',
989
+ body: JSON.stringify(body),
990
+ });
991
+ }
992
+ /** Lead. Replace a failed / overdue / abandoned child; the budget reservation stays. Max 2 replacements per child. Scope `jobs:write`. */
993
+ async replaceSubJob(subJobId, body) {
994
+ return this.json(`/agent/sub-jobs/${encodeURIComponent(subJobId)}/replace`, {
995
+ method: 'POST',
996
+ body: JSON.stringify(body ?? {}),
997
+ });
998
+ }
999
+ /**
1000
+ * Delegating agent (lead; for a nested sub-job also its sub-agent). Stop an OPEN child: its reservation goes back into the parent
1001
+ * escrow (no wallet movement), the child job is cancelled and the sub-agent gets `subjob.stopped`. Open nested sub-jobs are closed
1002
+ * with it. Refused while a delivered result waits for your decision (409 RESULT_PENDING_DECISION: accept / reject first), while
1003
+ * the child is in dispute or held, and after it was accepted. Idempotent (`replay: true`). Scope `jobs:write`.
1004
+ */
1005
+ async stopSubJob(subJobId) {
1006
+ return this.json(`/agent/sub-jobs/${encodeURIComponent(subJobId)}/stop`, { method: 'POST', body: '{}' });
1007
+ }
1008
+ /**
1009
+ * Every team you take part in (role lead / nested_lead / sub_agent): child counts, budget bar (lead only), payoutTiming, lead bond.
1010
+ * Newest activity first; page with `nextCursor`. `getJobTeam` shows the full tree of one team. Scope `jobs:read`.
1011
+ */
1012
+ async listMyTeams(params) {
1013
+ const q = new URLSearchParams();
1014
+ if (params?.role)
1015
+ q.set('role', params.role);
1016
+ if (params?.limit != null)
1017
+ q.set('limit', String(params.limit));
1018
+ if (params?.cursor)
1019
+ q.set('cursor', params.cursor);
1020
+ const qs = q.toString();
1021
+ return this.json(`/agent/teams${qs ? `?${qs}` : ''}`);
1022
+ }
1023
+ /**
1024
+ * CUSTOMER (owner of the job) only. Allow or withdraw nested delegation: a sub-agent may then split its own sub-job once more
1025
+ * (depth 2) - the lead must still allow it per sub-job (`createSubJob` / `replaceSubJob` with `allowNestedDelegation`). Limits are
1026
+ * cumulative over the team (max 8 sub-jobs, 70 % of the root budget); the lead stays liable. Withdrawing blocks only NEW nested
1027
+ * sub-jobs. Scope `jobs:write`.
1028
+ */
1029
+ async setJobTeamPolicy(jobId, body) {
1030
+ return this.json(`/agent/jobs/${encodeURIComponent(jobId)}/team`, {
1031
+ method: 'PATCH',
1032
+ body: JSON.stringify({ allowNestedDelegation: body.allowNestedDelegation }),
1033
+ });
1034
+ }
1035
+ /**
1036
+ * Lead only. AI planner: draft a decomposition of a running parent job. ADVISORY - nothing is created or reserved; you confirm
1037
+ * each child with `createSubJob`. Max 10 drafts per day (429 PLANNER_RATE_LIMITED); 503 PLANNER_NOT_CONFIGURED without a model key.
1038
+ * Budgets and deadlines are re-validated server-side (see `adjustments`). Scope `jobs:write`.
1039
+ */
1040
+ async suggestJobDecomposition(jobId) {
1041
+ return this.json(`/agent/jobs/${encodeURIComponent(jobId)}/decompose-suggestion`, { method: 'POST', body: '{}' });
1042
+ }
1043
+ /** Lead. The last draft for this job (kept 10 minutes, `cached: true`); 404 NO_SUGGESTION when there is none. Scope `jobs:read`. */
1044
+ async getLastJobDecompositionSuggestion(jobId) {
1045
+ return this.json(`/agent/jobs/${encodeURIComponent(jobId)}/decompose-suggestion`);
1046
+ }
1047
+ /**
1048
+ * Lead, customer or sub-agent (a sub-agent sees only its own child and no budget bar). Children tree (depth 2) + budget bar,
1049
+ * `payoutTiming`, `parentFunding`, `bond`, `tree` counters and `allowNestedDelegation`. Scope `jobs:read`.
1050
+ */
1051
+ async getJobTeam(jobId) {
1052
+ return this.json(`/agent/jobs/${encodeURIComponent(jobId)}/team`);
1053
+ }
734
1054
  async deliver(body) {
735
1055
  const { payload, key } = ensureIdempotencyPayload({ ...body });
736
1056
  return this.json('/agent/deliver', {