@alfe.ai/agent-api-client 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -137,6 +137,7 @@ var AgentApiClient = class {
137
137
  if (!res.ok) {
138
138
  await res.text();
139
139
  const error = /* @__PURE__ */ new Error(`Agent API request failed (${String(res.status)})`);
140
+ error.status = res.status;
140
141
  if (attempt === 1 && RETRYABLE_STATUS.has(res.status)) {
141
142
  lastError = error;
142
143
  await sleep(RETRY_DELAY_MS);
@@ -210,7 +211,17 @@ var AgentApiClient = class {
210
211
  return this.request("/agent/integrations");
211
212
  }
212
213
  async getIntegrationConfig(integrationId) {
213
- return this.request(`/agent/integrations/${encodeURIComponent(integrationId)}/config`);
214
+ try {
215
+ return await this.request(`/agent/integrations/${encodeURIComponent(integrationId)}/config`);
216
+ } catch (err) {
217
+ if (err.status === 404) return {
218
+ integrationId,
219
+ config: {},
220
+ configSchema: [],
221
+ installed: false
222
+ };
223
+ throw err;
224
+ }
214
225
  }
215
226
  async updateIntegrationConfig(integrationId, config) {
216
227
  await this.request(`/agent/integrations/${encodeURIComponent(integrationId)}`, {
@@ -289,6 +300,99 @@ var AgentApiClient = class {
289
300
  return this.request(`/agent/connect/connections/${encodeURIComponent(connectionId)}/credentials`);
290
301
  }
291
302
  /**
303
+ * Resolve the primary cTrader Connection's credentials for the calling
304
+ * agent. Unlike most providers, the cTrader Open API needs app-level auth
305
+ * (`clientId` + `clientSecret`) AND account auth (`accessToken` +
306
+ * `accountId`) on the socket, so `@alfe.ai/ctrader-mcp` self-fetches the
307
+ * full set here at startup (the atlassian/google pattern). `clientId` /
308
+ * `clientSecret` are the SST-sourced global app credentials the connect
309
+ * endpoint injects — they are never persisted on the connection. `host` is
310
+ * the resolved TLS endpoint (`live.ctraderapi.com` / `demo.ctraderapi.com`)
311
+ * derived from the selected account's live/demo flag.
312
+ */
313
+ async getCTraderCredentials() {
314
+ const raw = await this.request("/agent/connect/ctrader/credentials");
315
+ return {
316
+ accessToken: raw.accessToken ?? "",
317
+ refreshToken: raw.refreshToken ?? "",
318
+ accountId: raw.accountId != null ? String(raw.accountId) : "",
319
+ host: raw.host ?? "",
320
+ clientId: raw.clientId ?? "",
321
+ clientSecret: raw.clientSecret ?? ""
322
+ };
323
+ }
324
+ /**
325
+ * Pattern A: multi-account credential fetch for cTrader.
326
+ *
327
+ * Unlike atlassian/salesforce (one Connection row per account/site), a
328
+ * cTrader is MULTI-grant per agent: an agent may connect several distinct
329
+ * cTrader logins, each its own Connection row keyed on `accountIdentifier =
330
+ * ctid:<userId>` (Phase 1). This aggregates the *trading accounts* across
331
+ * ALL of those Connection rows — each row contributes its `availableAccounts`
332
+ * flattened, and every account carries ITS OWN grant's `accessToken` (the
333
+ * token that authenticates that account against the cTrader Open API). One
334
+ * OAuth grant still covers all accounts under that single login on one shared
335
+ * token; only the `ctidTraderAccountId` and the protobuf socket `host` (live
336
+ * vs demo) differ within a grant. Across grants the tokens differ, so the
337
+ * token is now PER-ACCOUNT rather than hoisted to the top level.
338
+ *
339
+ * `host` per account is derived from the account's `isLive` flag
340
+ * (`live.ctraderapi.com` / `demo.ctraderapi.com`) — the same mapping the
341
+ * connect provider applies server-side when an account is auto-selected.
342
+ *
343
+ * `clientId` / `clientSecret` are the SST-sourced GLOBAL app credentials the
344
+ * connect endpoint injects — identical across every Connection row (one
345
+ * cTrader app), never persisted on a connection. We take them from the first
346
+ * row that carries them.
347
+ *
348
+ * Accounts are deduped on `ctidTraderAccountId` first-wins: Spotware ids are
349
+ * globally unique across logins, so a duplicate can only appear if the same
350
+ * account somehow surfaced under two grants — first-wins keeps it
351
+ * deterministic.
352
+ *
353
+ * `accounts` may be empty (no cTrader Connection at all), in which case we
354
+ * return empty creds rather than throwing.
355
+ */
356
+ async getCTraderAccounts() {
357
+ const raw = await this.request("/agent/connect/ctrader/accounts");
358
+ if (raw.accounts.length === 0) return {
359
+ accounts: [],
360
+ clientId: "",
361
+ clientSecret: ""
362
+ };
363
+ let clientId = "";
364
+ let clientSecret = "";
365
+ for (const row of raw.accounts) {
366
+ if (!clientId && row.clientId) clientId = row.clientId;
367
+ if (!clientSecret && row.clientSecret) clientSecret = row.clientSecret;
368
+ if (clientId && clientSecret) break;
369
+ }
370
+ const seen = /* @__PURE__ */ new Set();
371
+ const accounts = [];
372
+ for (const row of raw.accounts) {
373
+ const rowToken = row.accessToken ?? "";
374
+ for (const a of row.availableAccounts ?? []) {
375
+ const id = a.ctidTraderAccountId != null ? String(a.ctidTraderAccountId) : a.accountId != null ? String(a.accountId) : "";
376
+ if (id.length === 0 || seen.has(id)) continue;
377
+ seen.add(id);
378
+ const isLive = a.isLive === true;
379
+ accounts.push({
380
+ ctidTraderAccountId: id,
381
+ host: isLive ? "live.ctraderapi.com" : "demo.ctraderapi.com",
382
+ isLive,
383
+ ...a.brokerName != null ? { brokerName: a.brokerName } : {},
384
+ ...a.accountNumber != null ? { accountNumber: String(a.accountNumber) } : {},
385
+ accessToken: rowToken
386
+ });
387
+ }
388
+ }
389
+ return {
390
+ accounts,
391
+ clientId,
392
+ clientSecret
393
+ };
394
+ }
395
+ /**
292
396
  * @deprecated Returns a single primary credential blob (legacy "pick-the-
293
397
  * default-connection" shape). Use `getGithubAccounts()` for the multi-
294
398
  * account shape required by Pattern A — explicit selector args on every
@@ -1068,6 +1172,15 @@ var AgentApiClient = class {
1068
1172
  ...scope ? { body: JSON.stringify({ scope }) } : {}
1069
1173
  });
1070
1174
  }
1175
+ async sendSms(args) {
1176
+ return this.request("/mobile/sms/send", {
1177
+ method: "POST",
1178
+ body: JSON.stringify({
1179
+ to: args.to,
1180
+ body: args.body
1181
+ })
1182
+ });
1183
+ }
1071
1184
  async searchWeb(params) {
1072
1185
  return this.request("/agent/search/web", {
1073
1186
  method: "POST",
@@ -1086,6 +1199,20 @@ var AgentApiClient = class {
1086
1199
  body: JSON.stringify(params)
1087
1200
  });
1088
1201
  }
1202
+ /** Search news across the selected provider's corpus. → POST /agent/news/search */
1203
+ async newsSearch(params) {
1204
+ return this.request("/agent/news/search", {
1205
+ method: "POST",
1206
+ body: JSON.stringify(params)
1207
+ });
1208
+ }
1209
+ /** Top headlines for the selected provider. → POST /agent/news/headlines */
1210
+ async newsHeadlines(params) {
1211
+ return this.request("/agent/news/headlines", {
1212
+ method: "POST",
1213
+ body: JSON.stringify(params ?? {})
1214
+ });
1215
+ }
1089
1216
  /**
1090
1217
  * Semantic search across the agent's member scopes. Fan-out is gated
1091
1218
  * server-side by `listScopes` set-inclusion (fail-closed). Pass