@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.cjs +128 -1
- package/dist/index.d.cts +110 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +110 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +128 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|