@acosmi/sdk-ts 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +296 -52
- package/dist/browser/index.mjs +462 -8
- package/dist/browser/index.mjs.map +1 -1
- package/dist/index.mjs +462 -8
- package/dist/index.mjs.map +1 -1
- package/dist/node/adapters/anthropic.cjs.map +1 -1
- package/dist/node/adapters/anthropic.d.cts +1 -1
- package/dist/node/adapters/anthropic.d.ts +1 -1
- package/dist/node/adapters/anthropic.mjs.map +1 -1
- package/dist/node/adapters/openai.cjs.map +1 -1
- package/dist/node/adapters/openai.d.cts +2 -2
- package/dist/node/adapters/openai.d.ts +2 -2
- package/dist/node/adapters/openai.mjs.map +1 -1
- package/dist/node/{index-C9X5Yuyk.d.cts → index-CI7FM3xe.d.cts} +43 -1
- package/dist/node/{index-C9X5Yuyk.d.ts → index-CI7FM3xe.d.ts} +43 -1
- package/dist/node/index.cjs +480 -7
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +474 -8
- package/dist/node/index.d.ts +474 -8
- package/dist/node/index.mjs +462 -8
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/{openai-BqKAhbSc.d.ts → openai-oeY7dGNW.d.ts} +1 -1
- package/dist/node/{openai-C_UKadSX.d.cts → openai-xKHChcmG.d.cts} +1 -1
- package/docs//345/274/200/345/217/221/344/270/216/345/217/221/345/270/203/346/211/213/345/206/214.md +115 -20
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1010,6 +1010,21 @@ function apiResponseBusinessError(r) {
|
|
|
1010
1010
|
|
|
1011
1011
|
// src/auth/auth.ts
|
|
1012
1012
|
var authTimeoutMs = 3e4;
|
|
1013
|
+
var OAuthTokenEndpointError = class extends Error {
|
|
1014
|
+
status;
|
|
1015
|
+
oauthError;
|
|
1016
|
+
errorDescription;
|
|
1017
|
+
constructor(status, oauthError, errorDescription) {
|
|
1018
|
+
super(`token: HTTP ${status}: ${errorDescription || oauthError}`);
|
|
1019
|
+
this.name = "OAuthTokenEndpointError";
|
|
1020
|
+
this.status = status;
|
|
1021
|
+
this.oauthError = oauthError;
|
|
1022
|
+
this.errorDescription = errorDescription;
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
function isInvalidGrantError(err) {
|
|
1026
|
+
return err instanceof OAuthTokenEndpointError && err.oauthError === "invalid_grant";
|
|
1027
|
+
}
|
|
1013
1028
|
async function discoverWithProfile(serverURL, profile, signal) {
|
|
1014
1029
|
let parsed;
|
|
1015
1030
|
try {
|
|
@@ -1386,7 +1401,9 @@ async function postToken(endpoint, data, signal) {
|
|
|
1386
1401
|
errBody = await resp.json();
|
|
1387
1402
|
} catch {
|
|
1388
1403
|
}
|
|
1389
|
-
|
|
1404
|
+
const oauthError = typeof errBody.error === "string" ? errBody.error : "";
|
|
1405
|
+
const errorDescription = typeof errBody.error_description === "string" ? errBody.error_description : "";
|
|
1406
|
+
throw new OAuthTokenEndpointError(resp.status, oauthError, errorDescription);
|
|
1390
1407
|
}
|
|
1391
1408
|
try {
|
|
1392
1409
|
return await resp.json();
|
|
@@ -1996,6 +2013,53 @@ var FilterStatusFallbackTkdistSkew = "fallback-tkdist-deployment-skew";
|
|
|
1996
2013
|
var FilterStatusFallbackNoBuckets = "fallback-no-buckets";
|
|
1997
2014
|
var FilterStatusFallbackMissingUser = "fallback-missing-userid";
|
|
1998
2015
|
var FilterStatusUnknown = "";
|
|
2016
|
+
var DEFAULT_GATEWAY_BASE_URL = "https://acosmi.com";
|
|
2017
|
+
function normalizeGatewayBaseURL(input) {
|
|
2018
|
+
if (typeof input !== "string") {
|
|
2019
|
+
throw new TypeError(
|
|
2020
|
+
"Acosmi Gateway URL must be a string (see docs/audit/sdk-remote-control-contract-2026-05-27.md \xA72)"
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
const trimmed = input.trim();
|
|
2024
|
+
if (trimmed.length === 0) {
|
|
2025
|
+
throw new Error("Acosmi Gateway URL is empty");
|
|
2026
|
+
}
|
|
2027
|
+
let parsed;
|
|
2028
|
+
try {
|
|
2029
|
+
parsed = new URL(trimmed);
|
|
2030
|
+
} catch {
|
|
2031
|
+
throw new Error(`Acosmi Gateway URL is not a valid URL: ${trimmed}`);
|
|
2032
|
+
}
|
|
2033
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2034
|
+
throw new Error(
|
|
2035
|
+
`Acosmi Gateway URL only allows http/https, got ${parsed.protocol} (${trimmed}). CrabCode --sdk-url (ws/wss) is the RemoteIO session channel, not a SDK gateway URL \u2014 see docs/audit/sdk-remote-control-contract-2026-05-27.md \xA71.`
|
|
2036
|
+
);
|
|
2037
|
+
}
|
|
2038
|
+
if (!parsed.host) {
|
|
2039
|
+
throw new Error(`Acosmi Gateway URL has empty host: ${trimmed}`);
|
|
2040
|
+
}
|
|
2041
|
+
if (parsed.search.length > 0 || parsed.hash.length > 0) {
|
|
2042
|
+
throw new Error(`Acosmi Gateway URL must not contain query or hash: ${trimmed}`);
|
|
2043
|
+
}
|
|
2044
|
+
const path = parsed.pathname.replace(/\/+$/, "");
|
|
2045
|
+
return path ? `${parsed.origin}${path}` : parsed.origin;
|
|
2046
|
+
}
|
|
2047
|
+
function pickAndNormalizeGatewayURL(cfg) {
|
|
2048
|
+
const inputs = [];
|
|
2049
|
+
if (cfg.serverURL !== void 0) inputs.push(["serverURL", cfg.serverURL]);
|
|
2050
|
+
if (cfg.baseURL !== void 0) inputs.push(["baseURL", cfg.baseURL]);
|
|
2051
|
+
if (cfg.baseUrl !== void 0) inputs.push(["baseUrl", cfg.baseUrl]);
|
|
2052
|
+
if (inputs.length === 0) return null;
|
|
2053
|
+
const normalized = inputs.map(([n, v]) => [n, normalizeGatewayBaseURL(v)]);
|
|
2054
|
+
for (let i = 1; i < normalized.length; i++) {
|
|
2055
|
+
if (normalized[i][1] !== normalized[0][1]) {
|
|
2056
|
+
throw new Error(
|
|
2057
|
+
`Acosmi Gateway URL conflict: Config.${normalized[0][0]}=${normalized[0][1]} vs Config.${normalized[i][0]}=${normalized[i][1]} \u2014 pass only one field.`
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
return normalized[0][1];
|
|
2062
|
+
}
|
|
1999
2063
|
var ErrOAuthCORSBlocked = "oauth_cors_blocked";
|
|
2000
2064
|
var ErrRefreshProxyFailed = "refresh_proxy_failed";
|
|
2001
2065
|
var ErrTokenExpired = "token_expired";
|
|
@@ -2053,7 +2117,8 @@ var Client = class _Client {
|
|
|
2053
2117
|
/** 串行化锁 (替代 Go sync.Mutex) */
|
|
2054
2118
|
coefMu = Promise.resolve();
|
|
2055
2119
|
constructor(cfg = {}) {
|
|
2056
|
-
|
|
2120
|
+
const picked = pickAndNormalizeGatewayURL(cfg);
|
|
2121
|
+
this.serverURL = picked ?? DEFAULT_GATEWAY_BASE_URL;
|
|
2057
2122
|
this.complianceBaseURL = cfg.complianceBaseURL ? cfg.complianceBaseURL.replace(/\/+$/, "") : null;
|
|
2058
2123
|
this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
|
|
2059
2124
|
this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
|
|
@@ -2088,6 +2153,20 @@ var Client = class _Client {
|
|
|
2088
2153
|
isAuthorized() {
|
|
2089
2154
|
return this.tokens != null;
|
|
2090
2155
|
}
|
|
2156
|
+
/**
|
|
2157
|
+
* 返回归一化后的 Acosmi Gateway URL (= `serverURL` 字段). readonly helper.
|
|
2158
|
+
*
|
|
2159
|
+
* Phase 0 §2 红线:
|
|
2160
|
+
* - 不要 mutate `client.serverURL` 字段实现 base 切换; 用 per-base Client 实例.
|
|
2161
|
+
* - 该值仅供日志/排查/上层缓存键使用, 不重新 normalize 它 (构造期已 normalize).
|
|
2162
|
+
*/
|
|
2163
|
+
getServerURL() {
|
|
2164
|
+
return this.serverURL;
|
|
2165
|
+
}
|
|
2166
|
+
/** `getServerURL()` 的 alias — Phase 0 §2 baseURL 与 serverURL 同义. */
|
|
2167
|
+
getBaseURL() {
|
|
2168
|
+
return this.serverURL;
|
|
2169
|
+
}
|
|
2091
2170
|
/** 当前 token 信息 (用于 CLI whoami 显示) */
|
|
2092
2171
|
getTokenSet() {
|
|
2093
2172
|
return this.tokens;
|
|
@@ -2354,6 +2433,10 @@ var Client = class _Client {
|
|
|
2354
2433
|
);
|
|
2355
2434
|
} catch (e) {
|
|
2356
2435
|
const message = e instanceof Error ? e.message : String(e);
|
|
2436
|
+
if (isInvalidGrantError(e)) {
|
|
2437
|
+
await this.clearInvalidRefreshToken();
|
|
2438
|
+
throw new Error(`refresh token invalid; local tokens cleared: ${message}`);
|
|
2439
|
+
}
|
|
2357
2440
|
if (isLikelyBrowserOAuthCORSError(message)) {
|
|
2358
2441
|
throw new Error(`${ErrOAuthCORSBlocked}: refresh token: ${message}`);
|
|
2359
2442
|
}
|
|
@@ -2388,11 +2471,18 @@ var Client = class _Client {
|
|
|
2388
2471
|
}
|
|
2389
2472
|
if (!resp.ok) {
|
|
2390
2473
|
let message = "";
|
|
2474
|
+
let oauthError = "";
|
|
2391
2475
|
try {
|
|
2392
2476
|
const body2 = await resp.json();
|
|
2393
2477
|
if (typeof body2.error === "string") message = body2.error;
|
|
2478
|
+
if (typeof body2.error === "string") oauthError = body2.error;
|
|
2479
|
+
if (typeof body2.error_description === "string") message = body2.error_description;
|
|
2394
2480
|
} catch {
|
|
2395
2481
|
}
|
|
2482
|
+
if (oauthError === "invalid_grant") {
|
|
2483
|
+
await this.clearInvalidRefreshToken();
|
|
2484
|
+
throw new Error(`${ErrRefreshProxyFailed}: refresh token invalid; local tokens cleared`);
|
|
2485
|
+
}
|
|
2396
2486
|
throw new Error(`${ErrRefreshProxyFailed}: HTTP ${resp.status}: ${message}`);
|
|
2397
2487
|
}
|
|
2398
2488
|
let body;
|
|
@@ -2419,6 +2509,20 @@ var Client = class _Client {
|
|
|
2419
2509
|
);
|
|
2420
2510
|
}
|
|
2421
2511
|
}
|
|
2512
|
+
async clearInvalidRefreshToken() {
|
|
2513
|
+
this.tokens = null;
|
|
2514
|
+
this.meta = null;
|
|
2515
|
+
this.loginInFlight = false;
|
|
2516
|
+
this.tokenReady = newDeferred();
|
|
2517
|
+
this.tokenReadyResolved = false;
|
|
2518
|
+
try {
|
|
2519
|
+
await this.store.clear();
|
|
2520
|
+
} catch (e) {
|
|
2521
|
+
console.warn(
|
|
2522
|
+
`[acosmi-sdk] warning: clear invalid token failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2422
2526
|
/** 互斥锁 helper (替代 Go sync.Mutex) */
|
|
2423
2527
|
withMu(fn) {
|
|
2424
2528
|
const next = this.mu.then(fn, fn);
|
|
@@ -2624,6 +2728,60 @@ var Client = class _Client {
|
|
|
2624
2728
|
ctl.dispose();
|
|
2625
2729
|
}
|
|
2626
2730
|
}
|
|
2731
|
+
// ===========================================================================
|
|
2732
|
+
// 媒体生成 (v1.3+) — 图片 / 视频生成托管模型 (与 chat 同网关)
|
|
2733
|
+
//
|
|
2734
|
+
// 仅对 capabilities.supports_image_generation / supports_video_generation 的模型有效。
|
|
2735
|
+
// 网关不算钱; 用量由网关上报营销系统结算。
|
|
2736
|
+
// ===========================================================================
|
|
2737
|
+
/** 解析 nexus-v4 {code,message,data} 信封, code!=0 抛 BusinessError, 返回 data。 */
|
|
2738
|
+
unwrapAPIResponse(result) {
|
|
2739
|
+
const env = JSON.parse(new TextDecoder().decode(result));
|
|
2740
|
+
const bizErr = apiResponseBusinessError(env);
|
|
2741
|
+
if (bizErr) throw bizErr;
|
|
2742
|
+
return env.data;
|
|
2743
|
+
}
|
|
2744
|
+
/**
|
|
2745
|
+
* 图片生成 (同步)。POST /managed-models/:id/images/generations
|
|
2746
|
+
*
|
|
2747
|
+
* @param modelID 图片生成托管模型 ID (capabilities.supports_image_generation=true)
|
|
2748
|
+
*/
|
|
2749
|
+
async generateImage(modelID, req, signal) {
|
|
2750
|
+
const endpoint = `/managed-models/${encodeURIComponent(modelID)}/images/generations`;
|
|
2751
|
+
const { result } = await this.doJSONFullRaw(
|
|
2752
|
+
"POST",
|
|
2753
|
+
endpoint,
|
|
2754
|
+
req,
|
|
2755
|
+
signal,
|
|
2756
|
+
CHAT_REQUEST_TIMEOUT_MS
|
|
2757
|
+
);
|
|
2758
|
+
return this.unwrapAPIResponse(result);
|
|
2759
|
+
}
|
|
2760
|
+
/**
|
|
2761
|
+
* 创建视频生成任务 (异步)。POST /managed-models/:id/videos/generations
|
|
2762
|
+
* 返回 taskId; 用 pollVideoTask() 轮询直到 status=completed。
|
|
2763
|
+
* 上报真物理量 (视频秒数) 需在 pollVideoTask 时回传 req.duration。
|
|
2764
|
+
*
|
|
2765
|
+
* @param modelID 视频生成托管模型 ID (capabilities.supports_video_generation=true)
|
|
2766
|
+
*/
|
|
2767
|
+
async generateVideo(modelID, req, signal) {
|
|
2768
|
+
const endpoint = `/managed-models/${encodeURIComponent(modelID)}/videos/generations`;
|
|
2769
|
+
const { result } = await this.doJSONFullRaw("POST", endpoint, req, signal);
|
|
2770
|
+
return this.unwrapAPIResponse(result);
|
|
2771
|
+
}
|
|
2772
|
+
/**
|
|
2773
|
+
* 轮询视频任务状态。GET /managed-models/:id/videos/tasks/:taskId
|
|
2774
|
+
*
|
|
2775
|
+
* @param durationSeconds 创建时的时长 (秒), 透传给网关在 completed 时上报用量。
|
|
2776
|
+
*/
|
|
2777
|
+
async pollVideoTask(modelID, taskID, durationSeconds, signal) {
|
|
2778
|
+
let endpoint = `/managed-models/${encodeURIComponent(modelID)}/videos/tasks/${encodeURIComponent(taskID)}`;
|
|
2779
|
+
if (durationSeconds != null && durationSeconds > 0) {
|
|
2780
|
+
endpoint += `?duration=${encodeURIComponent(String(durationSeconds))}`;
|
|
2781
|
+
}
|
|
2782
|
+
const { result } = await this.doJSONFullRaw("GET", endpoint, null, signal);
|
|
2783
|
+
return this.unwrapAPIResponse(result);
|
|
2784
|
+
}
|
|
2627
2785
|
/**
|
|
2628
2786
|
* Anthropic 原生格式同步聊天
|
|
2629
2787
|
* v0.5.0: 根据 provider 自动路由
|
|
@@ -2968,11 +3126,11 @@ var Client = class _Client {
|
|
|
2968
3126
|
}
|
|
2969
3127
|
}
|
|
2970
3128
|
/** doJSONFull 的 raw bytes 变体 (chat 用, 不立即 JSON.parse) */
|
|
2971
|
-
async doJSONFullRaw(method, path, body, signal) {
|
|
2972
|
-
return this.doJSONFullRawInternal(method, path, body, signal, false);
|
|
3129
|
+
async doJSONFullRaw(method, path, body, signal, timeoutMs = 3e4) {
|
|
3130
|
+
return this.doJSONFullRawInternal(method, path, body, signal, false, timeoutMs);
|
|
2973
3131
|
}
|
|
2974
|
-
async doJSONFullRawInternal(method, path, body, signal, retried) {
|
|
2975
|
-
const ctl = withRequestTimeout(
|
|
3132
|
+
async doJSONFullRawInternal(method, path, body, signal, retried, timeoutMs = 3e4) {
|
|
3133
|
+
const ctl = withRequestTimeout(timeoutMs, signal);
|
|
2976
3134
|
try {
|
|
2977
3135
|
const token = await this.ensureToken(ctl.signal);
|
|
2978
3136
|
let bodyStr = null;
|
|
@@ -3000,7 +3158,7 @@ var Client = class _Client {
|
|
|
3000
3158
|
`unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
3001
3159
|
);
|
|
3002
3160
|
}
|
|
3003
|
-
return this.doJSONFullRawInternal(method, path, body, signal, true);
|
|
3161
|
+
return this.doJSONFullRawInternal(method, path, body, signal, true, timeoutMs);
|
|
3004
3162
|
}
|
|
3005
3163
|
if (resp.status < 200 || resp.status >= 300) {
|
|
3006
3164
|
const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
|
|
@@ -3617,6 +3775,10 @@ function complianceErrorToRetryAdvice(info) {
|
|
|
3617
3775
|
var ScopeAI = "ai";
|
|
3618
3776
|
var ScopeSkills = "skills";
|
|
3619
3777
|
var ScopeAccount = "account";
|
|
3778
|
+
var ScopeRemoteControl = "remote_control";
|
|
3779
|
+
var ScopeRemoteControlAgentRun = "remote_control:agent-run";
|
|
3780
|
+
var ScopeRemoteControlSessionControl = "remote_control:session-control";
|
|
3781
|
+
var ScopeRemoteControlPermissionResponse = "remote_control:permission-response";
|
|
3620
3782
|
var ScopeModels = "models";
|
|
3621
3783
|
var ScopeModelsChat = "models:chat";
|
|
3622
3784
|
var ScopeEntitlements = "entitlements";
|
|
@@ -3639,6 +3801,9 @@ function commerceScopes() {
|
|
|
3639
3801
|
function skillScopes() {
|
|
3640
3802
|
return [ScopeSkills];
|
|
3641
3803
|
}
|
|
3804
|
+
function remoteControlScopes() {
|
|
3805
|
+
return [ScopeRemoteControl];
|
|
3806
|
+
}
|
|
3642
3807
|
|
|
3643
3808
|
// src/models/index.ts
|
|
3644
3809
|
init_types();
|
|
@@ -4484,6 +4649,136 @@ var AgentRunStreamError = class extends Error {
|
|
|
4484
4649
|
}
|
|
4485
4650
|
};
|
|
4486
4651
|
|
|
4652
|
+
// src/agent-runs/remote-control.ts
|
|
4653
|
+
function asRecord(v) {
|
|
4654
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return null;
|
|
4655
|
+
return v;
|
|
4656
|
+
}
|
|
4657
|
+
function str(rec, key) {
|
|
4658
|
+
const v = rec[key];
|
|
4659
|
+
return typeof v === "string" ? v : void 0;
|
|
4660
|
+
}
|
|
4661
|
+
function num(rec, key) {
|
|
4662
|
+
const v = rec[key];
|
|
4663
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
4664
|
+
}
|
|
4665
|
+
function bool(rec, key) {
|
|
4666
|
+
const v = rec[key];
|
|
4667
|
+
return typeof v === "boolean" ? v : void 0;
|
|
4668
|
+
}
|
|
4669
|
+
function parseRemoteControlEvent(raw) {
|
|
4670
|
+
const rec = asRecord(raw);
|
|
4671
|
+
if (!rec) return null;
|
|
4672
|
+
const type = str(rec, "type");
|
|
4673
|
+
if (!type) return null;
|
|
4674
|
+
switch (type) {
|
|
4675
|
+
case "text_delta": {
|
|
4676
|
+
const index = num(rec, "index");
|
|
4677
|
+
const text = str(rec, "text");
|
|
4678
|
+
if (typeof index !== "number" || typeof text !== "string") return null;
|
|
4679
|
+
return { type: "text_delta", index, text };
|
|
4680
|
+
}
|
|
4681
|
+
case "reasoning_delta": {
|
|
4682
|
+
const index = num(rec, "index");
|
|
4683
|
+
const text = str(rec, "text");
|
|
4684
|
+
if (typeof index !== "number" || typeof text !== "string") return null;
|
|
4685
|
+
return { type: "reasoning_delta", index, text };
|
|
4686
|
+
}
|
|
4687
|
+
case "tool_call": {
|
|
4688
|
+
const toolCallId = str(rec, "tool_call_id") ?? str(rec, "toolCallId");
|
|
4689
|
+
const name = str(rec, "name");
|
|
4690
|
+
if (!toolCallId || !name) return null;
|
|
4691
|
+
return {
|
|
4692
|
+
type: "tool_call",
|
|
4693
|
+
toolCallId,
|
|
4694
|
+
name,
|
|
4695
|
+
input: rec["input"],
|
|
4696
|
+
source: str(rec, "source")
|
|
4697
|
+
};
|
|
4698
|
+
}
|
|
4699
|
+
case "tool_result": {
|
|
4700
|
+
const toolCallId = str(rec, "tool_call_id") ?? str(rec, "toolCallId");
|
|
4701
|
+
const ok = bool(rec, "ok");
|
|
4702
|
+
if (!toolCallId || typeof ok !== "boolean") return null;
|
|
4703
|
+
return {
|
|
4704
|
+
type: "tool_result",
|
|
4705
|
+
toolCallId,
|
|
4706
|
+
ok,
|
|
4707
|
+
output: rec["output"],
|
|
4708
|
+
error: str(rec, "error")
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4711
|
+
case "permission_request": {
|
|
4712
|
+
const requestId = str(rec, "request_id") ?? str(rec, "requestId");
|
|
4713
|
+
const kind = str(rec, "kind");
|
|
4714
|
+
if (!requestId || !kind) return null;
|
|
4715
|
+
return {
|
|
4716
|
+
type: "permission_request",
|
|
4717
|
+
requestId,
|
|
4718
|
+
kind,
|
|
4719
|
+
payload: rec["payload"],
|
|
4720
|
+
deadlineMs: num(rec, "deadline_ms") ?? num(rec, "deadlineMs")
|
|
4721
|
+
};
|
|
4722
|
+
}
|
|
4723
|
+
case "permission_result": {
|
|
4724
|
+
const requestId = str(rec, "request_id") ?? str(rec, "requestId");
|
|
4725
|
+
const decision = str(rec, "decision");
|
|
4726
|
+
if (!requestId || !decision) return null;
|
|
4727
|
+
return {
|
|
4728
|
+
type: "permission_result",
|
|
4729
|
+
requestId,
|
|
4730
|
+
decision,
|
|
4731
|
+
actor: str(rec, "actor"),
|
|
4732
|
+
decidedAt: str(rec, "decided_at") ?? str(rec, "decidedAt")
|
|
4733
|
+
};
|
|
4734
|
+
}
|
|
4735
|
+
case "usage": {
|
|
4736
|
+
return {
|
|
4737
|
+
type: "usage",
|
|
4738
|
+
inputTokens: num(rec, "input_tokens") ?? num(rec, "inputTokens"),
|
|
4739
|
+
outputTokens: num(rec, "output_tokens") ?? num(rec, "outputTokens"),
|
|
4740
|
+
cacheRead: num(rec, "cache_read") ?? num(rec, "cacheRead"),
|
|
4741
|
+
cacheCreate: num(rec, "cache_create") ?? num(rec, "cacheCreate"),
|
|
4742
|
+
exact: bool(rec, "exact")
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
case "settle": {
|
|
4746
|
+
const status = str(rec, "status");
|
|
4747
|
+
if (!status) return null;
|
|
4748
|
+
return { type: "settle", status, billed: bool(rec, "billed") };
|
|
4749
|
+
}
|
|
4750
|
+
case "status": {
|
|
4751
|
+
const phase = str(rec, "phase");
|
|
4752
|
+
if (!phase) return null;
|
|
4753
|
+
return { type: "status", phase, message: str(rec, "message") };
|
|
4754
|
+
}
|
|
4755
|
+
case "error": {
|
|
4756
|
+
const code = str(rec, "code");
|
|
4757
|
+
const message = str(rec, "message");
|
|
4758
|
+
if (!code || !message) return null;
|
|
4759
|
+
return {
|
|
4760
|
+
type: "error",
|
|
4761
|
+
code,
|
|
4762
|
+
message,
|
|
4763
|
+
retryable: bool(rec, "retryable"),
|
|
4764
|
+
kind: str(rec, "kind")
|
|
4765
|
+
};
|
|
4766
|
+
}
|
|
4767
|
+
case "done": {
|
|
4768
|
+
const reason = str(rec, "reason");
|
|
4769
|
+
const runId = str(rec, "run_id") ?? str(rec, "runId");
|
|
4770
|
+
const finalStatus = str(rec, "final_status") ?? str(rec, "finalStatus");
|
|
4771
|
+
if (!reason || !runId || !finalStatus) return null;
|
|
4772
|
+
return { type: "done", reason, runId, finalStatus };
|
|
4773
|
+
}
|
|
4774
|
+
default:
|
|
4775
|
+
return null;
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
function isTerminalRemoteEvent(ev) {
|
|
4779
|
+
return ev.type === "done" || ev.type === "settle";
|
|
4780
|
+
}
|
|
4781
|
+
|
|
4487
4782
|
// src/agent-runs/client.ts
|
|
4488
4783
|
var agentRunsByClient = /* @__PURE__ */ new WeakMap();
|
|
4489
4784
|
Object.defineProperty(Client.prototype, "agentRuns", {
|
|
@@ -4536,6 +4831,62 @@ var AgentRunsClient = class {
|
|
|
4536
4831
|
{ retryOn401: false }
|
|
4537
4832
|
).then(fromWireRun);
|
|
4538
4833
|
}
|
|
4834
|
+
/**
|
|
4835
|
+
* Create a CrabCode remote-control agent run (contract §3, ADR-2 + ADR-5).
|
|
4836
|
+
*
|
|
4837
|
+
* Equivalent to `create()` with `runtime: 'crabcode_remote'` and the required
|
|
4838
|
+
* `runner` + `adapter` fields set. Per-session policies (permission/workspace)
|
|
4839
|
+
* are forwarded to the gateway, which is the only side allowed to enforce
|
|
4840
|
+
* them (contract §6). The SDK never enforces remote permissions client-side.
|
|
4841
|
+
*
|
|
4842
|
+
* The corresponding stream uses `streamRemoteControl(runId)`, NOT `stream()`,
|
|
4843
|
+
* because the event union is different (contract §4).
|
|
4844
|
+
*/
|
|
4845
|
+
async createRemoteRun(req, signal) {
|
|
4846
|
+
if (req.runtime !== "crabcode_remote") {
|
|
4847
|
+
throw new Error('createRemoteRun: runtime must be "crabcode_remote"');
|
|
4848
|
+
}
|
|
4849
|
+
if (!req.runner) throw new Error("createRemoteRun: runner is required");
|
|
4850
|
+
if (!req.adapter) throw new Error("createRemoteRun: adapter is required");
|
|
4851
|
+
return this.create(req, signal);
|
|
4852
|
+
}
|
|
4853
|
+
/**
|
|
4854
|
+
* Stream remote-control events for a CrabCode remote run (contract §4).
|
|
4855
|
+
*
|
|
4856
|
+
* Yields the canonical 11-event union: text_delta / reasoning_delta /
|
|
4857
|
+
* tool_call / tool_result / permission_request / permission_result /
|
|
4858
|
+
* usage / settle / status / error / done.
|
|
4859
|
+
*
|
|
4860
|
+
* Iteration ends naturally when a terminal event (`done` or `settle`) is
|
|
4861
|
+
* observed. Per contract §4, `error` alone is non-terminal — terminal errors
|
|
4862
|
+
* are carried by `done.reason` / `done.final_status`.
|
|
4863
|
+
*
|
|
4864
|
+
* Unknown event types and malformed frames are silently skipped (warn-only),
|
|
4865
|
+
* matching `parseRemoteControlEvent`'s null-return contract.
|
|
4866
|
+
*/
|
|
4867
|
+
streamRemoteControl(runId, signal) {
|
|
4868
|
+
return {
|
|
4869
|
+
[Symbol.asyncIterator]: () => this.streamRemoteControlGen(runId, signal)
|
|
4870
|
+
};
|
|
4871
|
+
}
|
|
4872
|
+
async *streamRemoteControlGen(runId, signal) {
|
|
4873
|
+
const resp = await this.requestRaw(
|
|
4874
|
+
"GET",
|
|
4875
|
+
`/agent-runs/${encodeURIComponent(runId)}/stream`,
|
|
4876
|
+
null,
|
|
4877
|
+
signal,
|
|
4878
|
+
{ retryOn401: true, accept: "text/event-stream" }
|
|
4879
|
+
);
|
|
4880
|
+
if (!resp.body) {
|
|
4881
|
+
throw new Error("remote-control stream: empty response body");
|
|
4882
|
+
}
|
|
4883
|
+
for await (const rawEvent of readAgentRunSSEFrames(resp.body)) {
|
|
4884
|
+
const ev = parseRemoteControlEvent(rawEvent);
|
|
4885
|
+
if (!ev) continue;
|
|
4886
|
+
yield ev;
|
|
4887
|
+
if (isTerminalRemoteEvent(ev)) return;
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4539
4890
|
listArtifacts(runId, signal) {
|
|
4540
4891
|
return this.requestAPI(
|
|
4541
4892
|
"GET",
|
|
@@ -4695,6 +5046,24 @@ var AgentRunsClient = class {
|
|
|
4695
5046
|
return resp;
|
|
4696
5047
|
}
|
|
4697
5048
|
};
|
|
5049
|
+
function toWirePermissionPolicy(p) {
|
|
5050
|
+
return {
|
|
5051
|
+
shell_allowed: p.shellAllowed,
|
|
5052
|
+
shell_deny_list: p.shellDenyList,
|
|
5053
|
+
network_allowed: p.networkAllowed,
|
|
5054
|
+
write_allowed: p.writeAllowed,
|
|
5055
|
+
approval_timeout_ms: p.approvalTimeoutMs,
|
|
5056
|
+
required_actors: p.requiredActors
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
5059
|
+
function toWireWorkspacePolicy(p) {
|
|
5060
|
+
return {
|
|
5061
|
+
read_only: p.readOnly,
|
|
5062
|
+
allowed_paths: p.allowedPaths,
|
|
5063
|
+
denied_paths: p.deniedPaths,
|
|
5064
|
+
max_bytes: p.maxBytes
|
|
5065
|
+
};
|
|
5066
|
+
}
|
|
4698
5067
|
function toWireCreateRequest(req) {
|
|
4699
5068
|
return {
|
|
4700
5069
|
app_id: req.appId,
|
|
@@ -4712,6 +5081,11 @@ function toWireCreateRequest(req) {
|
|
|
4712
5081
|
max_bytes: req.localContextPolicy.maxBytes,
|
|
4713
5082
|
allowed_tools: req.localContextPolicy.allowedTools
|
|
4714
5083
|
} : void 0,
|
|
5084
|
+
runtime: req.runtime,
|
|
5085
|
+
runner: req.runner,
|
|
5086
|
+
adapter: req.adapter,
|
|
5087
|
+
permission_policy: req.permissionPolicy ? toWirePermissionPolicy(req.permissionPolicy) : void 0,
|
|
5088
|
+
workspace_policy: req.workspacePolicy ? toWireWorkspacePolicy(req.workspacePolicy) : void 0,
|
|
4715
5089
|
artifact_policy: req.artifactPolicy ? {
|
|
4716
5090
|
enabled: req.artifactPolicy.enabled,
|
|
4717
5091
|
max_files: req.artifactPolicy.maxFiles
|
|
@@ -4757,6 +5131,46 @@ function fromWireArtifact(resp) {
|
|
|
4757
5131
|
metadata: resp.metadata
|
|
4758
5132
|
};
|
|
4759
5133
|
}
|
|
5134
|
+
async function* readAgentRunSSEFrames(body) {
|
|
5135
|
+
let eventName = "";
|
|
5136
|
+
let dataLines = [];
|
|
5137
|
+
const flush = () => {
|
|
5138
|
+
if (dataLines.length === 0) return null;
|
|
5139
|
+
const data = dataLines.join("\n");
|
|
5140
|
+
dataLines = [];
|
|
5141
|
+
if (data === "[DONE]") return null;
|
|
5142
|
+
try {
|
|
5143
|
+
const parsed = JSON.parse(data);
|
|
5144
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5145
|
+
const obj = parsed;
|
|
5146
|
+
if (!("type" in obj) && eventName) {
|
|
5147
|
+
obj.type = eventName;
|
|
5148
|
+
}
|
|
5149
|
+
return obj;
|
|
5150
|
+
}
|
|
5151
|
+
} catch {
|
|
5152
|
+
}
|
|
5153
|
+
return null;
|
|
5154
|
+
};
|
|
5155
|
+
for await (const line of iterSSELines(body)) {
|
|
5156
|
+
if (line === "") {
|
|
5157
|
+
const frame2 = flush();
|
|
5158
|
+
eventName = "";
|
|
5159
|
+
if (frame2) yield frame2;
|
|
5160
|
+
continue;
|
|
5161
|
+
}
|
|
5162
|
+
if (line.startsWith(":")) continue;
|
|
5163
|
+
if (line.startsWith("event:")) {
|
|
5164
|
+
eventName = line.slice("event:".length).trim();
|
|
5165
|
+
continue;
|
|
5166
|
+
}
|
|
5167
|
+
if (line.startsWith("data:")) {
|
|
5168
|
+
dataLines.push(line.slice("data:".length).trimStart());
|
|
5169
|
+
}
|
|
5170
|
+
}
|
|
5171
|
+
const frame = flush();
|
|
5172
|
+
if (frame) yield frame;
|
|
5173
|
+
}
|
|
4760
5174
|
async function* readAgentRunEvents(body) {
|
|
4761
5175
|
let eventName = "";
|
|
4762
5176
|
let dataLines = [];
|
|
@@ -6146,6 +6560,11 @@ Client.prototype.listUserSubscriptions = async function(signal) {
|
|
|
6146
6560
|
);
|
|
6147
6561
|
return Array.isArray(resp.data) ? resp.data : [];
|
|
6148
6562
|
};
|
|
6563
|
+
Client.prototype.getPlanByCode = async function(planCode, signal) {
|
|
6564
|
+
if (!planCode) return null;
|
|
6565
|
+
const plans = await this.listPlans(void 0, signal);
|
|
6566
|
+
return plans.find((p) => p.planCode === planCode) ?? null;
|
|
6567
|
+
};
|
|
6149
6568
|
|
|
6150
6569
|
// src/pricing/client.ts
|
|
6151
6570
|
Client.prototype.getPricingConfig = async function(key, signal) {
|
|
@@ -6519,6 +6938,41 @@ Client.prototype.listMyCorporateTransfers = async function(signal) {
|
|
|
6519
6938
|
return resp.data ?? [];
|
|
6520
6939
|
};
|
|
6521
6940
|
|
|
6522
|
-
|
|
6941
|
+
// src/chatbridge/types.ts
|
|
6942
|
+
var ALL_PLATFORMS = [
|
|
6943
|
+
"feishu",
|
|
6944
|
+
"wecom",
|
|
6945
|
+
"dingtalk",
|
|
6946
|
+
"slack",
|
|
6947
|
+
"teams",
|
|
6948
|
+
"telegram",
|
|
6949
|
+
"whatsapp"
|
|
6950
|
+
];
|
|
6951
|
+
var ALL_REGIONS = ["cn", "intl"];
|
|
6952
|
+
var ALL_INTEGRATION_STATUS = [
|
|
6953
|
+
"pending",
|
|
6954
|
+
"active",
|
|
6955
|
+
"suspended",
|
|
6956
|
+
"revoked"
|
|
6957
|
+
];
|
|
6958
|
+
function isPlatform(v) {
|
|
6959
|
+
return typeof v === "string" && ALL_PLATFORMS.includes(v);
|
|
6960
|
+
}
|
|
6961
|
+
function isRegion(v) {
|
|
6962
|
+
return typeof v === "string" && ALL_REGIONS.includes(v);
|
|
6963
|
+
}
|
|
6964
|
+
function isIntegrationStatus(v) {
|
|
6965
|
+
return typeof v === "string" && ALL_INTEGRATION_STATUS.includes(v);
|
|
6966
|
+
}
|
|
6967
|
+
function isChannelInboundEvent(v) {
|
|
6968
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
6969
|
+
const r = v;
|
|
6970
|
+
return isPlatform(r.platform) && typeof r.threadHash === "string" && r.threadHash.length > 0 && typeof r.content === "string";
|
|
6971
|
+
}
|
|
6972
|
+
function asCredentialRef(s) {
|
|
6973
|
+
return s;
|
|
6974
|
+
}
|
|
6975
|
+
|
|
6976
|
+
export { ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, Client, ComplianceClient, CompliancePollError, DEFAULT_GATEWAY_BASE_URL, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OAuthTokenEndpointError, OpenAIAdapter, OrderTerminalError, ProductFamilyEnum, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, RegionScopeEnum, ScopeAI, ScopeAccount, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeRemoteControl, ScopeRemoteControlAgentRun, ScopeRemoteControlPermissionResponse, ScopeRemoteControlSessionControl, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, asCredentialRef, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, classifyComplianceError, commerceScopes, completeWebAuthorizationRequest, complianceErrorToRetryAdvice, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, isBillingConfirmable, isChannelInboundEvent, isComplianceBusinessError, isComplianceTerminalError, isIntegrationStatus, isInvalidGrantError, isPlatform, isRegion, isSSECommentLine, isSSLError, isTerminalRemoteEvent, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
|
|
6523
6977
|
//# sourceMappingURL=index.mjs.map
|
|
6524
6978
|
//# sourceMappingURL=index.mjs.map
|