@code-yeongyu/senpi 2026.9.11 → 2026.9.12-2
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 +40 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +5 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +13 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +54 -121
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/cursor-history-admission.d.ts +50 -0
- package/dist/core/cursor-history-admission.d.ts.map +1 -0
- package/dist/core/cursor-history-admission.js +130 -0
- package/dist/core/cursor-history-admission.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +2 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +22 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-write-reservation.d.ts +9 -0
- package/dist/core/session-write-reservation.d.ts.map +1 -1
- package/dist/core/session-write-reservation.js +33 -0
- package/dist/core/session-write-reservation.js.map +1 -1
- package/dist/modes/interactive/components/ask-user-async-widget.d.ts +2 -0
- package/dist/modes/interactive/components/ask-user-async-widget.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-user-async-widget.js +17 -1
- package/dist/modes/interactive/components/ask-user-async-widget.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +1 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-path-reservations.d.ts +30 -0
- package/dist/modes/rpc/session-path-reservations.d.ts.map +1 -0
- package/dist/modes/rpc/session-path-reservations.js +58 -0
- package/dist/modes/rpc/session-path-reservations.js.map +1 -0
- package/dist/modes/rpc/session-registry.d.ts +3 -1
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/session-worker-client.d.ts +10 -8
- package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-client.js +14 -23
- package/dist/modes/rpc/session-worker-client.js.map +1 -1
- package/dist/modes/rpc/session-worker-credit.d.ts +17 -0
- package/dist/modes/rpc/session-worker-credit.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker-credit.js +39 -0
- package/dist/modes/rpc/session-worker-credit.js.map +1 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +10 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-protocol.js +2 -0
- package/dist/modes/rpc/session-worker-protocol.js.map +1 -1
- package/dist/modes/rpc/session-worker-signals.d.ts +7 -0
- package/dist/modes/rpc/session-worker-signals.d.ts.map +1 -0
- package/dist/modes/rpc/session-worker-signals.js +19 -0
- package/dist/modes/rpc/session-worker-signals.js.map +1 -0
- package/dist/modes/rpc/session-worker.js +12 -16
- package/dist/modes/rpc/session-worker.js.map +1 -1
- package/dist/modes/rpc/worker-session-registry.d.ts +12 -0
- package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/worker-session-registry.js +51 -24
- package/dist/modes/rpc/worker-session-registry.js.map +1 -1
- package/docs/rpc.md +14 -6
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts +11 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js +18 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js +96 -51
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts +389 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js +132 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts +34 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js +41 -8
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts +18 -6
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js +77 -35
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts +9 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js +30 -38
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.d.ts +16 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.js +69 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/trailer.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.d.ts +26 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.js +61 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/unary.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts +6 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js +6 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts +13 -5
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js +76 -21
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js +7 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.d.ts +32 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.js +62 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/context-limit-store.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/cursor/store-migration.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +11 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/cursor.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +4 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +18 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.d.ts +12 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.js +93 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/cursor-context-limit.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* instead of publishing an empty catalog.
|
|
8
8
|
*/
|
|
9
9
|
import type { Model } from "../../types.ts";
|
|
10
|
+
import { type ClientModelConfig } from "./gen/cascade_pb.ts";
|
|
10
11
|
export interface DevinDiscoveryOptions {
|
|
11
12
|
apiKey: string | undefined;
|
|
12
13
|
baseUrl?: string;
|
|
@@ -14,4 +15,5 @@ export interface DevinDiscoveryOptions {
|
|
|
14
15
|
signal?: AbortSignal;
|
|
15
16
|
}
|
|
16
17
|
export declare function fetchDevinModels(options: DevinDiscoveryOptions): Promise<Model<"devin-agent">[] | undefined>;
|
|
18
|
+
export declare function normalizeDevinModels(configs: readonly ClientModelConfig[], baseUrl: string): Model<"devin-agent">[];
|
|
17
19
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EACN,KAAK,iBAAiB,EAKtB,MAAM,qBAAqB,CAAC;AAwB7B,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,GAAG,SAAS,CAAC,CAwBlH;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,EAAE,CAcnH"}
|
|
@@ -6,39 +6,41 @@
|
|
|
6
6
|
* empty response therefore returns undefined so callers KEEP their static seed
|
|
7
7
|
* instead of publishing an empty catalog.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { devinCliMetadata, normalizeDevinSessionToken } from "./metadata.js";
|
|
9
|
+
import { DisplayOption, GetCliModelConfigsRequestSchema, GetCliModelConfigsResponseSchema, ModelDimensionKind, } from "./gen/cascade_pb.js";
|
|
10
|
+
import { devinDiscoveryMetadata } from "./metadata.js";
|
|
12
11
|
import { DEVIN_CLI_MODEL_CONFIGS_PATH, DEVIN_DEFAULT_BASE_URL } from "./paths.js";
|
|
12
|
+
import { postDevinUnary } from "./unary.js";
|
|
13
13
|
const DISCOVERY_TIMEOUT_MS = 5_000;
|
|
14
14
|
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
15
|
-
const DEFAULT_MAX_TOKENS =
|
|
15
|
+
const DEFAULT_MAX_TOKENS = 64_000;
|
|
16
|
+
/** Slots requested for parity with the native client but never surfaced as models. */
|
|
17
|
+
const INTERNAL_DISPLAYS = new Set([
|
|
18
|
+
DisplayOption.QUICK_REVIEW,
|
|
19
|
+
DisplayOption.INTERNAL_DEFAULT,
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Lanes whose configs advertise image support while the backend silently drops
|
|
23
|
+
* `ChatMessagePrompt.images` (verified live on SWE-1.6 and SWE-1.6 Fast).
|
|
24
|
+
*/
|
|
25
|
+
const IMAGE_BLIND_UIDS = new Set(["swe-1-6", "swe-1-6-fast"]);
|
|
26
|
+
const REASONING_LABEL = /think|thinking|minimal|high|medium|low|xhigh|max|reasoning/i;
|
|
27
|
+
const NO_REASONING_LABEL = /\bno thinking\b/i;
|
|
16
28
|
export async function fetchDevinModels(options) {
|
|
17
|
-
const baseUrl = options.baseUrl ?? DEVIN_DEFAULT_BASE_URL;
|
|
29
|
+
const baseUrl = (options.baseUrl ?? DEVIN_DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
18
30
|
const controller = new AbortController();
|
|
19
31
|
const onAbort = () => controller.abort();
|
|
20
32
|
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
21
33
|
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DISCOVERY_TIMEOUT_MS);
|
|
22
34
|
try {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"connect-protocol-version": "1",
|
|
30
|
-
authorization: `Bearer ${normalizeDevinSessionToken(options.apiKey)}`,
|
|
31
|
-
},
|
|
32
|
-
body: payload,
|
|
35
|
+
const response = await postDevinUnary({
|
|
36
|
+
baseUrl,
|
|
37
|
+
path: DEVIN_CLI_MODEL_CONFIGS_PATH,
|
|
38
|
+
requestSchema: GetCliModelConfigsRequestSchema,
|
|
39
|
+
request: { metadata: devinDiscoveryMetadata(options.apiKey) },
|
|
40
|
+
responseSchema: GetCliModelConfigsResponseSchema,
|
|
33
41
|
signal: controller.signal,
|
|
34
42
|
});
|
|
35
|
-
|
|
36
|
-
return undefined;
|
|
37
|
-
const body = new Uint8Array(await response.arrayBuffer());
|
|
38
|
-
const decoded = decodeUnary(body);
|
|
39
|
-
if (!decoded)
|
|
40
|
-
return undefined;
|
|
41
|
-
const models = decoded.clientModelConfigs.filter(usable).map(toModel);
|
|
43
|
+
const models = normalizeDevinModels(response.clientModelConfigs, baseUrl);
|
|
42
44
|
return models.length > 0 ? models : undefined;
|
|
43
45
|
}
|
|
44
46
|
catch {
|
|
@@ -49,42 +51,85 @@ export async function fetchDevinModels(options) {
|
|
|
49
51
|
options.signal?.removeEventListener("abort", onAbort);
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
+
export function normalizeDevinModels(configs, baseUrl) {
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
const models = [];
|
|
57
|
+
for (const config of configs) {
|
|
58
|
+
if (config.disabled)
|
|
59
|
+
continue;
|
|
60
|
+
const display = config.modelInfo?.displayOption ?? DisplayOption.UNSPECIFIED;
|
|
61
|
+
if (INTERNAL_DISPLAYS.has(display))
|
|
62
|
+
continue;
|
|
63
|
+
const uid = config.modelUid.trim();
|
|
64
|
+
if (!uid || seen.has(uid))
|
|
65
|
+
continue;
|
|
66
|
+
seen.add(uid);
|
|
67
|
+
const isRouter = display === DisplayOption.MODEL_ROUTER || config.modelInfo?.isModelRouter === true;
|
|
68
|
+
models.push(toModel(config, uid, baseUrl, isRouter));
|
|
69
|
+
}
|
|
70
|
+
return models.sort((a, b) => a.id.localeCompare(b.id));
|
|
54
71
|
}
|
|
55
|
-
function toModel(config) {
|
|
72
|
+
function toModel(config, uid, baseUrl, isRouter) {
|
|
73
|
+
const features = config.modelInfo?.modelFeatures;
|
|
74
|
+
const supportsImages = (features ? features.supportsImages : config.supportsImages) && !IMAGE_BLIND_UIDS.has(uid);
|
|
75
|
+
const maxOutputTokens = config.modelInfo?.maxOutputTokens ?? 0;
|
|
76
|
+
const compat = {
|
|
77
|
+
...(isRouter ? { modelRouter: true } : {}),
|
|
78
|
+
...(features?.supportsParallelToolCalls === true ? { supportsParallelToolCalls: true } : {}),
|
|
79
|
+
};
|
|
56
80
|
return {
|
|
57
|
-
id:
|
|
58
|
-
name: config.label ||
|
|
81
|
+
id: uid,
|
|
82
|
+
name: config.label.trim() || uid,
|
|
59
83
|
api: "devin-agent",
|
|
60
84
|
provider: "devin",
|
|
61
|
-
baseUrl
|
|
62
|
-
reasoning:
|
|
63
|
-
input:
|
|
64
|
-
cost:
|
|
65
|
-
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
|
66
|
-
maxTokens:
|
|
85
|
+
baseUrl,
|
|
86
|
+
reasoning: supportsThinking(config),
|
|
87
|
+
input: supportsImages ? ["text", "image"] : ["text"],
|
|
88
|
+
cost: costOf(config),
|
|
89
|
+
contextWindow: config.maxTokens > 0 ? config.maxTokens : DEFAULT_CONTEXT_WINDOW,
|
|
90
|
+
maxTokens: maxOutputTokens > 0 ? maxOutputTokens : DEFAULT_MAX_TOKENS,
|
|
91
|
+
...(Object.keys(compat).length > 0 ? { compat } : {}),
|
|
67
92
|
};
|
|
68
93
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
94
|
+
function supportsThinking(config) {
|
|
95
|
+
const features = config.modelInfo?.modelFeatures;
|
|
96
|
+
if (features !== undefined)
|
|
97
|
+
return features.supportsThinking;
|
|
98
|
+
if (NO_REASONING_LABEL.test(config.label))
|
|
99
|
+
return false;
|
|
100
|
+
return REASONING_LABEL.test(config.label);
|
|
76
101
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
/** Per-million rates from the cost dimensions; Devin bills cache writes at the input rate, so cacheWrite stays 0. */
|
|
103
|
+
function costOf(config) {
|
|
104
|
+
const cost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
105
|
+
for (const dimension of config.modelDimensions) {
|
|
106
|
+
if (dimension.kind !== ModelDimensionKind.COST && dimension.kind !== ModelDimensionKind.COST_FUZZY)
|
|
107
|
+
continue;
|
|
108
|
+
// Dimension values arrive as protobuf floats (0.1 decodes as 0.10000000149…); round at sub-cent precision.
|
|
109
|
+
const perMillion = Math.round(((dimension.value * 1_000_000) / denominatorTokens(dimension.denominator)) * 1e6) / 1e6;
|
|
110
|
+
switch (dimension.label.trim().toLowerCase()) {
|
|
111
|
+
case "input":
|
|
112
|
+
cost.input = perMillion;
|
|
113
|
+
break;
|
|
114
|
+
case "cached input":
|
|
115
|
+
cost.cacheRead = perMillion;
|
|
116
|
+
break;
|
|
117
|
+
case "output":
|
|
118
|
+
cost.output = perMillion;
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
88
123
|
}
|
|
124
|
+
return cost;
|
|
125
|
+
}
|
|
126
|
+
const DENOMINATOR_SCALE = { k: 1_000, m: 1_000_000, b: 1_000_000_000 };
|
|
127
|
+
function denominatorTokens(denominator) {
|
|
128
|
+
const match = /(\d+(?:\.\d+)?)\s*([kmb])?/i.exec(denominator);
|
|
129
|
+
if (!match?.[1])
|
|
130
|
+
return 1_000_000;
|
|
131
|
+
const scale = match[2] ? (DENOMINATOR_SCALE[match[2].toLowerCase()] ?? 1) : 1;
|
|
132
|
+
const tokens = Number(match[1]) * scale;
|
|
133
|
+
return tokens > 0 ? tokens : 1_000_000;
|
|
89
134
|
}
|
|
90
135
|
//# sourceMappingURL=discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,+BAA+B,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAElF,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AACvC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AASnC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAA8B;IACpE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,sBAAsB,CAAC;IAC1D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzC,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,oBAAoB,CAAC,CAAC;IAEhG,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,MAAM,CAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxG,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,GAAG,4BAA4B,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,2BAA2B;gBAC3C,0BAA0B,EAAE,GAAG;gBAC/B,aAAa,EAAE,UAAU,0BAA0B,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;aACrE;YACD,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,UAAU,CAAC,MAAM;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,SAAS,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtE,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;AACF,CAAC;AAED,SAAS,MAAM,CAAC,MAA+C;IAC9D,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;AACvD,CAAC;AAED,SAAS,OAAO,CAAC,MAKhB;IACA,OAAO;QACN,EAAE,EAAE,MAAM,CAAC,QAAQ;QACnB,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ;QACrC,GAAG,EAAE,aAAa;QAClB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,sBAAsB;QAC/B,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3D,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;QAC1D,aAAa,EAAE,sBAAsB;QACrC,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB;KACvE,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,SAAS,YAAY,CACpB,OAA0E;IAE1E,MAAM,OAAO,GAAG,QAAQ,CAAC,+BAA+B,EAAE,OAAO,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrD,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACnE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CACnB,IAAgB;IAEhB,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC;QACJ,OAAO,UAAU,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC","sourcesContent":["/**\n * Cascade model discovery.\n *\n * `GetCliModelConfigs` is credential-scoped: it reports the models the signed-in\n * account may actually use, which differs per plan and per rollout. A failed or\n * empty response therefore returns undefined so callers KEEP their static seed\n * instead of publishing an empty catalog.\n */\n\nimport { create, fromBinary, toBinary } from \"@bufbuild/protobuf\";\nimport type { Model } from \"../../types.ts\";\nimport { GetCliModelConfigsRequestSchema, GetCliModelConfigsResponseSchema } from \"./gen/cascade_pb.ts\";\nimport { devinCliMetadata, normalizeDevinSessionToken } from \"./metadata.ts\";\nimport { DEVIN_CLI_MODEL_CONFIGS_PATH, DEVIN_DEFAULT_BASE_URL } from \"./paths.ts\";\n\nconst DISCOVERY_TIMEOUT_MS = 5_000;\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\nconst DEFAULT_MAX_TOKENS = 128_000;\n\nexport interface DevinDiscoveryOptions {\n\tapiKey: string | undefined;\n\tbaseUrl?: string;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n}\n\nexport async function fetchDevinModels(options: DevinDiscoveryOptions): Promise<Model<\"devin-agent\">[] | undefined> {\n\tconst baseUrl = options.baseUrl ?? DEVIN_DEFAULT_BASE_URL;\n\tconst controller = new AbortController();\n\tconst onAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\tconst timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DISCOVERY_TIMEOUT_MS);\n\n\ttry {\n\t\tconst request = create(GetCliModelConfigsRequestSchema, { metadata: devinCliMetadata(options.apiKey) });\n\t\tconst payload = toUnaryFrame(request);\n\t\tconst response = await fetch(baseUrl + DEVIN_CLI_MODEL_CONFIGS_PATH, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/connect+proto\",\n\t\t\t\t\"connect-protocol-version\": \"1\",\n\t\t\t\tauthorization: `Bearer ${normalizeDevinSessionToken(options.apiKey)}`,\n\t\t\t},\n\t\t\tbody: payload,\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!response.ok) return undefined;\n\t\tconst body = new Uint8Array(await response.arrayBuffer());\n\t\tconst decoded = decodeUnary(body);\n\t\tif (!decoded) return undefined;\n\t\tconst models = decoded.clientModelConfigs.filter(usable).map(toModel);\n\t\treturn models.length > 0 ? models : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\toptions.signal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nfunction usable(config: { modelUid: string; disabled: boolean }): boolean {\n\treturn config.modelUid.length > 0 && !config.disabled;\n}\n\nfunction toModel(config: {\n\tmodelUid: string;\n\tlabel: string;\n\tmaxTokens: number;\n\tsupportsImages: boolean;\n}): Model<\"devin-agent\"> {\n\treturn {\n\t\tid: config.modelUid,\n\t\tname: config.label || config.modelUid,\n\t\tapi: \"devin-agent\",\n\t\tprovider: \"devin\",\n\t\tbaseUrl: DEVIN_DEFAULT_BASE_URL,\n\t\treasoning: true,\n\t\tinput: config.supportsImages ? [\"text\", \"image\"] : [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\tmaxTokens: config.maxTokens > 0 ? config.maxTokens : DEFAULT_MAX_TOKENS,\n\t};\n}\n\n/** Unary Connect bodies use the same 5-byte prefix, uncompressed. */\nfunction toUnaryFrame(\n\tmessage: ReturnType<typeof create<typeof GetCliModelConfigsRequestSchema>>,\n): Uint8Array<ArrayBuffer> {\n\tconst payload = toBinary(GetCliModelConfigsRequestSchema, message);\n\tconst frame = new Uint8Array(5 + payload.byteLength);\n\tnew DataView(frame.buffer).setUint32(1, payload.byteLength, false);\n\tframe.set(payload, 5);\n\treturn frame;\n}\n\nfunction decodeUnary(\n\tbody: Uint8Array,\n): ReturnType<typeof fromBinary<typeof GetCliModelConfigsResponseSchema>> | undefined {\n\tif (body.byteLength < 5) return undefined;\n\tconst view = new DataView(body.buffer, body.byteOffset, body.byteLength);\n\tconst length = view.getUint32(1, false);\n\tconst payload = body.subarray(5, 5 + length);\n\ttry {\n\t\treturn fromBinary(GetCliModelConfigsResponseSchema, payload);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Cascade model discovery.\n *\n * `GetCliModelConfigs` is credential-scoped: it reports the models the signed-in\n * account may actually use, which differs per plan and per rollout. A failed or\n * empty response therefore returns undefined so callers KEEP their static seed\n * instead of publishing an empty catalog.\n */\n\nimport type { Model } from \"../../types.ts\";\nimport {\n\ttype ClientModelConfig,\n\tDisplayOption,\n\tGetCliModelConfigsRequestSchema,\n\tGetCliModelConfigsResponseSchema,\n\tModelDimensionKind,\n} from \"./gen/cascade_pb.ts\";\nimport { devinDiscoveryMetadata } from \"./metadata.ts\";\nimport { DEVIN_CLI_MODEL_CONFIGS_PATH, DEVIN_DEFAULT_BASE_URL } from \"./paths.ts\";\nimport { postDevinUnary } from \"./unary.ts\";\n\nconst DISCOVERY_TIMEOUT_MS = 5_000;\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\nconst DEFAULT_MAX_TOKENS = 64_000;\n\n/** Slots requested for parity with the native client but never surfaced as models. */\nconst INTERNAL_DISPLAYS: ReadonlySet<DisplayOption> = new Set([\n\tDisplayOption.QUICK_REVIEW,\n\tDisplayOption.INTERNAL_DEFAULT,\n]);\n\n/**\n * Lanes whose configs advertise image support while the backend silently drops\n * `ChatMessagePrompt.images` (verified live on SWE-1.6 and SWE-1.6 Fast).\n */\nconst IMAGE_BLIND_UIDS: ReadonlySet<string> = new Set([\"swe-1-6\", \"swe-1-6-fast\"]);\n\nconst REASONING_LABEL = /think|thinking|minimal|high|medium|low|xhigh|max|reasoning/i;\nconst NO_REASONING_LABEL = /\\bno thinking\\b/i;\n\nexport interface DevinDiscoveryOptions {\n\tapiKey: string | undefined;\n\tbaseUrl?: string;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n}\n\nexport async function fetchDevinModels(options: DevinDiscoveryOptions): Promise<Model<\"devin-agent\">[] | undefined> {\n\tconst baseUrl = (options.baseUrl ?? DEVIN_DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n\tconst controller = new AbortController();\n\tconst onAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\tconst timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DISCOVERY_TIMEOUT_MS);\n\n\ttry {\n\t\tconst response = await postDevinUnary({\n\t\t\tbaseUrl,\n\t\t\tpath: DEVIN_CLI_MODEL_CONFIGS_PATH,\n\t\t\trequestSchema: GetCliModelConfigsRequestSchema,\n\t\t\trequest: { metadata: devinDiscoveryMetadata(options.apiKey) },\n\t\t\tresponseSchema: GetCliModelConfigsResponseSchema,\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tconst models = normalizeDevinModels(response.clientModelConfigs, baseUrl);\n\t\treturn models.length > 0 ? models : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\toptions.signal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nexport function normalizeDevinModels(configs: readonly ClientModelConfig[], baseUrl: string): Model<\"devin-agent\">[] {\n\tconst seen = new Set<string>();\n\tconst models: Model<\"devin-agent\">[] = [];\n\tfor (const config of configs) {\n\t\tif (config.disabled) continue;\n\t\tconst display = config.modelInfo?.displayOption ?? DisplayOption.UNSPECIFIED;\n\t\tif (INTERNAL_DISPLAYS.has(display)) continue;\n\t\tconst uid = config.modelUid.trim();\n\t\tif (!uid || seen.has(uid)) continue;\n\t\tseen.add(uid);\n\t\tconst isRouter = display === DisplayOption.MODEL_ROUTER || config.modelInfo?.isModelRouter === true;\n\t\tmodels.push(toModel(config, uid, baseUrl, isRouter));\n\t}\n\treturn models.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction toModel(config: ClientModelConfig, uid: string, baseUrl: string, isRouter: boolean): Model<\"devin-agent\"> {\n\tconst features = config.modelInfo?.modelFeatures;\n\tconst supportsImages = (features ? features.supportsImages : config.supportsImages) && !IMAGE_BLIND_UIDS.has(uid);\n\tconst maxOutputTokens = config.modelInfo?.maxOutputTokens ?? 0;\n\tconst compat = {\n\t\t...(isRouter ? { modelRouter: true } : {}),\n\t\t...(features?.supportsParallelToolCalls === true ? { supportsParallelToolCalls: true } : {}),\n\t};\n\treturn {\n\t\tid: uid,\n\t\tname: config.label.trim() || uid,\n\t\tapi: \"devin-agent\",\n\t\tprovider: \"devin\",\n\t\tbaseUrl,\n\t\treasoning: supportsThinking(config),\n\t\tinput: supportsImages ? [\"text\", \"image\"] : [\"text\"],\n\t\tcost: costOf(config),\n\t\tcontextWindow: config.maxTokens > 0 ? config.maxTokens : DEFAULT_CONTEXT_WINDOW,\n\t\tmaxTokens: maxOutputTokens > 0 ? maxOutputTokens : DEFAULT_MAX_TOKENS,\n\t\t...(Object.keys(compat).length > 0 ? { compat } : {}),\n\t};\n}\n\nfunction supportsThinking(config: ClientModelConfig): boolean {\n\tconst features = config.modelInfo?.modelFeatures;\n\tif (features !== undefined) return features.supportsThinking;\n\tif (NO_REASONING_LABEL.test(config.label)) return false;\n\treturn REASONING_LABEL.test(config.label);\n}\n\n/** Per-million rates from the cost dimensions; Devin bills cache writes at the input rate, so cacheWrite stays 0. */\nfunction costOf(config: ClientModelConfig): Model<\"devin-agent\">[\"cost\"] {\n\tconst cost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\tfor (const dimension of config.modelDimensions) {\n\t\tif (dimension.kind !== ModelDimensionKind.COST && dimension.kind !== ModelDimensionKind.COST_FUZZY) continue;\n\t\t// Dimension values arrive as protobuf floats (0.1 decodes as 0.10000000149…); round at sub-cent precision.\n\t\tconst perMillion =\n\t\t\tMath.round(((dimension.value * 1_000_000) / denominatorTokens(dimension.denominator)) * 1e6) / 1e6;\n\t\tswitch (dimension.label.trim().toLowerCase()) {\n\t\t\tcase \"input\":\n\t\t\t\tcost.input = perMillion;\n\t\t\t\tbreak;\n\t\t\tcase \"cached input\":\n\t\t\t\tcost.cacheRead = perMillion;\n\t\t\t\tbreak;\n\t\t\tcase \"output\":\n\t\t\t\tcost.output = perMillion;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn cost;\n}\n\nconst DENOMINATOR_SCALE: Readonly<Record<string, number>> = { k: 1_000, m: 1_000_000, b: 1_000_000_000 };\n\nfunction denominatorTokens(denominator: string): number {\n\tconst match = /(\\d+(?:\\.\\d+)?)\\s*([kmb])?/i.exec(denominator);\n\tif (!match?.[1]) return 1_000_000;\n\tconst scale = match[2] ? (DENOMINATOR_SCALE[match[2].toLowerCase()] ?? 1) : 1;\n\tconst tokens = Number(match[1]) * scale;\n\treturn tokens > 0 ? tokens : 1_000_000;\n}\n"]}
|