@stigmer/runner 3.1.9 → 3.1.10
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/README.md +1 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/execute-cursor/model-pricing-data.d.ts +5 -8
- package/dist/activities/execute-cursor/model-pricing-data.js +7 -22
- package/dist/activities/execute-cursor/model-pricing-data.js.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/shared/model-pricing-data.js +2 -8
- package/dist/shared/model-pricing-data.js.map +1 -1
- package/dist/shared/model-registry.d.ts +2 -1
- package/dist/shared/model-registry.js +14 -11
- package/dist/shared/model-registry.js.map +1 -1
- package/dist/shared/registry-endpoint.d.ts +32 -0
- package/dist/shared/registry-endpoint.js +49 -0
- package/dist/shared/registry-endpoint.js.map +1 -0
- package/package.json +2 -2
- package/src/activities/execute-cursor/model-pricing-data.ts +8 -24
- package/src/config.ts +4 -1
- package/src/shared/__tests__/model-registry.test.ts +74 -1
- package/src/shared/__tests__/registry-endpoint.test.ts +80 -0
- package/src/shared/model-pricing-data.ts +3 -8
- package/src/shared/model-registry.ts +17 -11
- package/src/shared/registry-endpoint.ts +53 -0
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ The claim-check codec offloads oversized Temporal payloads to artifact storage a
|
|
|
191
191
|
| `OPENAI_API_KEY` | Direct mode (native/OpenAI) | When using OpenAI directly | _(empty)_ | OpenAI API key for the native harness in direct mode. Not needed in proxy mode. |
|
|
192
192
|
| `ANTHROPIC_API_KEY` | Direct mode (native/Anthropic) | When using Anthropic directly | _(empty)_ | Anthropic API key for the native harness in direct mode. Not needed in proxy mode. |
|
|
193
193
|
| `STIGMER_LLM_REQUEST_TIMEOUT_MS` | Native harness | No | `0` (no timeout) | Per-request timeout for native LLM calls, in milliseconds. `0` or unset means no explicit timeout. |
|
|
194
|
-
| `STIGMER_CLOUD_API_URL` | All | No |
|
|
194
|
+
| `STIGMER_CLOUD_API_URL` | All | No | _(unset)_ | Explicit override for the origin serving `/v1/proxy/model-registry` (model resolution and pricing). When unset, fetches go to `STIGMER_PROXY_ENDPOINT` (proxy mode) or `STIGMER_BACKEND_ENDPOINT` (direct/local mode — the local stigmer-server serves the registry). |
|
|
195
195
|
| `STIGMER_AUTH_TOKEN` | Pricing/registry fetch | No | value of `STIGMER_TOKEN` | Fallback bearer token for model-pricing and model-registry requests when `STIGMER_TOKEN` is not set. |
|
|
196
196
|
| `GITHUB_TOKEN` | Deep-agent git writeback | When writing back to GitHub | _(none)_ | Token used by the deep-agent harness for git writeback operations. |
|
|
197
197
|
|
package/dist/.build-fingerprint
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"hash":"
|
|
1
|
+
{"hash":"e78d5fd48fba6018","builtAt":"2026-07-13T09:31:58.389Z","fileCount":247}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cursor model pricing data — fetched from the
|
|
2
|
+
* Cursor model pricing data — fetched from the model registry endpoint.
|
|
3
3
|
*
|
|
4
4
|
* On first access (or after the TTL expires), fetches the full model
|
|
5
|
-
* registry from the
|
|
6
|
-
*
|
|
7
|
-
* pricing if the
|
|
8
|
-
*
|
|
9
|
-
* Environment variables:
|
|
10
|
-
* - STIGMER_CLOUD_API_URL: API base URL (defaults to https://api.stigmer.ai)
|
|
11
|
-
* - STIGMER_AUTH_TOKEN: Bearer token for authentication (required)
|
|
5
|
+
* registry from the runner's control plane (see registry-endpoint.ts for
|
|
6
|
+
* endpoint resolution), filters to cursor-harness models, and caches the
|
|
7
|
+
* result in memory. Falls back to conservative default pricing if the
|
|
8
|
+
* endpoint is unreachable.
|
|
12
9
|
*/
|
|
13
10
|
/** Per-million rates for a speed/mode variant (e.g. "fast") of a base model. */
|
|
14
11
|
export interface CursorVariantPricing {
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cursor model pricing data — fetched from the
|
|
2
|
+
* Cursor model pricing data — fetched from the model registry endpoint.
|
|
3
3
|
*
|
|
4
4
|
* On first access (or after the TTL expires), fetches the full model
|
|
5
|
-
* registry from the
|
|
6
|
-
*
|
|
7
|
-
* pricing if the
|
|
8
|
-
*
|
|
9
|
-
* Environment variables:
|
|
10
|
-
* - STIGMER_CLOUD_API_URL: API base URL (defaults to https://api.stigmer.ai)
|
|
11
|
-
* - STIGMER_AUTH_TOKEN: Bearer token for authentication (required)
|
|
5
|
+
* registry from the runner's control plane (see registry-endpoint.ts for
|
|
6
|
+
* endpoint resolution), filters to cursor-harness models, and caches the
|
|
7
|
+
* result in memory. Falls back to conservative default pricing if the
|
|
8
|
+
* endpoint is unreachable.
|
|
12
9
|
*/
|
|
13
|
-
|
|
10
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "../../shared/registry-endpoint.js";
|
|
14
11
|
const CACHE_TTL_MS = 3_600_000; // 1 hour
|
|
15
12
|
const DEFAULT_PRICING = {
|
|
16
13
|
model: "unknown",
|
|
@@ -23,12 +20,6 @@ const DEFAULT_PRICING = {
|
|
|
23
20
|
};
|
|
24
21
|
let cache = null;
|
|
25
22
|
let inflightFetch = null;
|
|
26
|
-
function getApiUrl() {
|
|
27
|
-
return process.env.STIGMER_CLOUD_API_URL ?? DEFAULT_API_URL;
|
|
28
|
-
}
|
|
29
|
-
function getAuthToken() {
|
|
30
|
-
return process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
31
|
-
}
|
|
32
23
|
function parsePricingTable(json) {
|
|
33
24
|
if (!json || typeof json !== "object")
|
|
34
25
|
return [];
|
|
@@ -65,13 +56,7 @@ function parseVariants(variants) {
|
|
|
65
56
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
66
57
|
}
|
|
67
58
|
async function fetchFromApi() {
|
|
68
|
-
const
|
|
69
|
-
const headers = {};
|
|
70
|
-
const token = getAuthToken();
|
|
71
|
-
if (token) {
|
|
72
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
73
|
-
}
|
|
74
|
-
const res = await fetch(url, { headers });
|
|
59
|
+
const res = await fetch(resolveModelRegistryUrl(), { headers: buildRegistryHeaders() });
|
|
75
60
|
if (!res.ok)
|
|
76
61
|
throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
77
62
|
const data = await res.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-pricing-data.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/model-pricing-data.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-pricing-data.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/model-pricing-data.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -100,3 +100,11 @@ export interface Config {
|
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
export declare function loadConfig(): Config;
|
|
103
|
+
/**
|
|
104
|
+
* Ensures the endpoint has an HTTP(S) scheme. Port 443 implies TLS;
|
|
105
|
+
* all other bare host:port endpoints get http://.
|
|
106
|
+
*
|
|
107
|
+
* Exported so registry-endpoint.ts applies the same normalization to
|
|
108
|
+
* STIGMER_BACKEND_ENDPOINT that this module applies when loading config.
|
|
109
|
+
*/
|
|
110
|
+
export declare function normalizeEndpoint(endpoint: string): string;
|
package/dist/config.js
CHANGED
|
@@ -135,8 +135,11 @@ function requireEnv(name) {
|
|
|
135
135
|
/**
|
|
136
136
|
* Ensures the endpoint has an HTTP(S) scheme. Port 443 implies TLS;
|
|
137
137
|
* all other bare host:port endpoints get http://.
|
|
138
|
+
*
|
|
139
|
+
* Exported so registry-endpoint.ts applies the same normalization to
|
|
140
|
+
* STIGMER_BACKEND_ENDPOINT that this module applies when loading config.
|
|
138
141
|
*/
|
|
139
|
-
function normalizeEndpoint(endpoint) {
|
|
142
|
+
export function normalizeEndpoint(endpoint) {
|
|
140
143
|
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
141
144
|
return endpoint;
|
|
142
145
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* with pricing info, and caches the result. Falls back to conservative
|
|
6
6
|
* default pricing if the API is unreachable.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "./registry-endpoint.js";
|
|
9
9
|
const CACHE_TTL_MS = 3_600_000;
|
|
10
10
|
export const DEFAULT_PRICING = {
|
|
11
11
|
model: "unknown",
|
|
@@ -37,13 +37,7 @@ function parsePricingTable(json) {
|
|
|
37
37
|
}));
|
|
38
38
|
}
|
|
39
39
|
async function fetchFromApi() {
|
|
40
|
-
const
|
|
41
|
-
const headers = {};
|
|
42
|
-
const token = process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
43
|
-
if (token) {
|
|
44
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
45
|
-
}
|
|
46
|
-
const res = await fetch(url, { headers });
|
|
40
|
+
const res = await fetch(resolveModelRegistryUrl(), { headers: buildRegistryHeaders() });
|
|
47
41
|
if (!res.ok)
|
|
48
42
|
throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
49
43
|
const data = await res.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-pricing-data.js","sourceRoot":"","sources":["../../src/shared/model-pricing-data.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA0BH,
|
|
1
|
+
{"version":3,"file":"model-pricing-data.js","sourceRoot":"","sources":["../../src/shared/model-pricing-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model registry — provider lookup and economy-tier model derivation.
|
|
3
3
|
*
|
|
4
|
-
* Fetches the model registry from the
|
|
4
|
+
* Fetches the model registry from the runner's control plane (see
|
|
5
|
+
* registry-endpoint.ts for endpoint resolution — same endpoint as
|
|
5
6
|
* model-pricing-data.ts) and uses `costTier` + `harness` fields to
|
|
6
7
|
* dynamically resolve economy-tier models for extraction/summarization.
|
|
7
8
|
*/
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model registry — provider lookup and economy-tier model derivation.
|
|
3
3
|
*
|
|
4
|
-
* Fetches the model registry from the
|
|
4
|
+
* Fetches the model registry from the runner's control plane (see
|
|
5
|
+
* registry-endpoint.ts for endpoint resolution — same endpoint as
|
|
5
6
|
* model-pricing-data.ts) and uses `costTier` + `harness` fields to
|
|
6
7
|
* dynamically resolve economy-tier models for extraction/summarization.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "./registry-endpoint.js";
|
|
9
10
|
const CACHE_TTL_MS = 3_600_000;
|
|
11
|
+
// Failed fetches are cached much shorter than successes: a transient failure
|
|
12
|
+
// must not poison id -> apiModelId resolution (and thereby fail every llm_call
|
|
13
|
+
// with LLM_MODEL_NOT_FOUND) for a full hour.
|
|
14
|
+
const FAILURE_CACHE_TTL_MS = 60_000;
|
|
10
15
|
let cache = null;
|
|
11
16
|
let inflightFetch = null;
|
|
12
17
|
function parseRegistry(json) {
|
|
@@ -27,13 +32,8 @@ function parseRegistry(json) {
|
|
|
27
32
|
}));
|
|
28
33
|
}
|
|
29
34
|
async function fetchRegistry() {
|
|
30
|
-
const url =
|
|
31
|
-
const
|
|
32
|
-
const token = process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
33
|
-
if (token) {
|
|
34
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
35
|
-
}
|
|
36
|
-
const res = await fetch(url, { headers });
|
|
35
|
+
const url = resolveModelRegistryUrl();
|
|
36
|
+
const res = await fetch(url, { headers: buildRegistryHeaders() });
|
|
37
37
|
if (!res.ok)
|
|
38
38
|
throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
39
39
|
const data = await res.json();
|
|
@@ -51,8 +51,11 @@ async function getRegistry() {
|
|
|
51
51
|
return models;
|
|
52
52
|
})
|
|
53
53
|
.catch((err) => {
|
|
54
|
-
console.warn(`Failed to fetch model registry
|
|
55
|
-
|
|
54
|
+
console.warn(`Failed to fetch model registry from ${resolveModelRegistryUrl()}: ${err}. ` +
|
|
55
|
+
`Model id resolution degrades to pass-through until the next attempt ` +
|
|
56
|
+
`(${FAILURE_CACHE_TTL_MS / 1000}s). Check that the control plane is ` +
|
|
57
|
+
`reachable and, for cloud endpoints, that STIGMER_TOKEN is set.`);
|
|
58
|
+
cache = { models: [], expiresAt: Date.now() + FAILURE_CACHE_TTL_MS };
|
|
56
59
|
return [];
|
|
57
60
|
})
|
|
58
61
|
.finally(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/shared/model-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/shared/model-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry endpoint resolution — where the runner fetches the model registry.
|
|
3
|
+
*
|
|
4
|
+
* The model registry (canonical id → provider apiModelId, pricing, tiers) is
|
|
5
|
+
* served at `/v1/proxy/model-registry` by whichever control plane the runner
|
|
6
|
+
* talks to: the cloud API in proxy mode, or the local stigmer-server in
|
|
7
|
+
* direct/local mode (stigmer/stigmer#240). Resolution is therefore
|
|
8
|
+
* topology-based, not token-based:
|
|
9
|
+
*
|
|
10
|
+
* 1. STIGMER_CLOUD_API_URL — explicit override (tests, unusual topologies)
|
|
11
|
+
* 2. STIGMER_PROXY_ENDPOINT — proxy mode: the origin that serves the rest of
|
|
12
|
+
* the runner's /v1/proxy surface (LLM proxy, checkpoints, artifacts) also
|
|
13
|
+
* serves the registry
|
|
14
|
+
* 3. STIGMER_BACKEND_ENDPOINT — direct/local mode: the runner's own control
|
|
15
|
+
* plane, defaulting to the local stigmer-server address
|
|
16
|
+
*
|
|
17
|
+
* A hardcoded cloud URL is deliberately absent: every runner already knows a
|
|
18
|
+
* control-plane origin that serves the registry, so falling back to the hosted
|
|
19
|
+
* API would only mask misconfiguration (and breaks offline/local use).
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the base URL (origin, no path) for model-registry and pricing
|
|
23
|
+
* fetches. See module doc for the tier order.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveRegistryBaseUrl(env?: NodeJS.ProcessEnv): string;
|
|
26
|
+
/**
|
|
27
|
+
* Build request headers for registry fetches: bearer auth when a token is
|
|
28
|
+
* present (cloud requires it; the local server ignores it).
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildRegistryHeaders(env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
31
|
+
/** Full URL of the model registry endpoint for the resolved control plane. */
|
|
32
|
+
export declare function resolveModelRegistryUrl(env?: NodeJS.ProcessEnv): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry endpoint resolution — where the runner fetches the model registry.
|
|
3
|
+
*
|
|
4
|
+
* The model registry (canonical id → provider apiModelId, pricing, tiers) is
|
|
5
|
+
* served at `/v1/proxy/model-registry` by whichever control plane the runner
|
|
6
|
+
* talks to: the cloud API in proxy mode, or the local stigmer-server in
|
|
7
|
+
* direct/local mode (stigmer/stigmer#240). Resolution is therefore
|
|
8
|
+
* topology-based, not token-based:
|
|
9
|
+
*
|
|
10
|
+
* 1. STIGMER_CLOUD_API_URL — explicit override (tests, unusual topologies)
|
|
11
|
+
* 2. STIGMER_PROXY_ENDPOINT — proxy mode: the origin that serves the rest of
|
|
12
|
+
* the runner's /v1/proxy surface (LLM proxy, checkpoints, artifacts) also
|
|
13
|
+
* serves the registry
|
|
14
|
+
* 3. STIGMER_BACKEND_ENDPOINT — direct/local mode: the runner's own control
|
|
15
|
+
* plane, defaulting to the local stigmer-server address
|
|
16
|
+
*
|
|
17
|
+
* A hardcoded cloud URL is deliberately absent: every runner already knows a
|
|
18
|
+
* control-plane origin that serves the registry, so falling back to the hosted
|
|
19
|
+
* API would only mask misconfiguration (and breaks offline/local use).
|
|
20
|
+
*/
|
|
21
|
+
import { normalizeEndpoint } from "../config.js";
|
|
22
|
+
/** Default local stigmer-server origin — mirrors config.ts's local-mode default. */
|
|
23
|
+
const DEFAULT_LOCAL_BACKEND = "http://localhost:7234";
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the base URL (origin, no path) for model-registry and pricing
|
|
26
|
+
* fetches. See module doc for the tier order.
|
|
27
|
+
*/
|
|
28
|
+
export function resolveRegistryBaseUrl(env = process.env) {
|
|
29
|
+
const override = env.STIGMER_CLOUD_API_URL;
|
|
30
|
+
if (override)
|
|
31
|
+
return normalizeEndpoint(override);
|
|
32
|
+
const proxyEndpoint = env.STIGMER_PROXY_ENDPOINT;
|
|
33
|
+
if (proxyEndpoint)
|
|
34
|
+
return normalizeEndpoint(proxyEndpoint);
|
|
35
|
+
return normalizeEndpoint(env.STIGMER_BACKEND_ENDPOINT ?? DEFAULT_LOCAL_BACKEND);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build request headers for registry fetches: bearer auth when a token is
|
|
39
|
+
* present (cloud requires it; the local server ignores it).
|
|
40
|
+
*/
|
|
41
|
+
export function buildRegistryHeaders(env = process.env) {
|
|
42
|
+
const token = env.STIGMER_TOKEN ?? env.STIGMER_AUTH_TOKEN;
|
|
43
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
44
|
+
}
|
|
45
|
+
/** Full URL of the model registry endpoint for the resolved control plane. */
|
|
46
|
+
export function resolveModelRegistryUrl(env = process.env) {
|
|
47
|
+
return `${resolveRegistryBaseUrl(env)}/v1/proxy/model-registry`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=registry-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-endpoint.js","sourceRoot":"","sources":["../../src/shared/registry-endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,oFAAoF;AACpF,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzE,MAAM,QAAQ,GAAG,GAAG,CAAC,qBAAqB,CAAC;IAC3C,IAAI,QAAQ;QAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAEjD,MAAM,aAAa,GAAG,GAAG,CAAC,sBAAsB,CAAC;IACjD,IAAI,aAAa;QAAE,OAAO,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAE3D,OAAO,iBAAiB,CAAC,GAAG,CAAC,wBAAwB,IAAI,qBAAqB,CAAC,CAAC;AAClF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACvE,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,kBAAkB,CAAC;IAC1D,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC1E,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,0BAA0B,CAAC;AAClE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.10",
|
|
4
4
|
"description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
86
86
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
87
87
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
88
|
-
"@stigmer/protos": "3.1.
|
|
88
|
+
"@stigmer/protos": "3.1.10",
|
|
89
89
|
"@temporalio/activity": "^1.11.0",
|
|
90
90
|
"@temporalio/client": "^1.11.0",
|
|
91
91
|
"@temporalio/common": "^1.11.0",
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cursor model pricing data — fetched from the
|
|
2
|
+
* Cursor model pricing data — fetched from the model registry endpoint.
|
|
3
3
|
*
|
|
4
4
|
* On first access (or after the TTL expires), fetches the full model
|
|
5
|
-
* registry from the
|
|
6
|
-
*
|
|
7
|
-
* pricing if the
|
|
8
|
-
*
|
|
9
|
-
* Environment variables:
|
|
10
|
-
* - STIGMER_CLOUD_API_URL: API base URL (defaults to https://api.stigmer.ai)
|
|
11
|
-
* - STIGMER_AUTH_TOKEN: Bearer token for authentication (required)
|
|
5
|
+
* registry from the runner's control plane (see registry-endpoint.ts for
|
|
6
|
+
* endpoint resolution), filters to cursor-harness models, and caches the
|
|
7
|
+
* result in memory. Falls back to conservative default pricing if the
|
|
8
|
+
* endpoint is unreachable.
|
|
12
9
|
*/
|
|
13
10
|
|
|
11
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "../../shared/registry-endpoint.js";
|
|
12
|
+
|
|
14
13
|
/** Per-million rates for a speed/mode variant (e.g. "fast") of a base model. */
|
|
15
14
|
export interface CursorVariantPricing {
|
|
16
15
|
readonly inputPricePerMillion: number;
|
|
@@ -53,7 +52,6 @@ interface RegistryEntry {
|
|
|
53
52
|
pricingVariants?: Record<string, RegistryVariantEntry>;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
const DEFAULT_API_URL = "https://api.stigmer.ai";
|
|
57
55
|
const CACHE_TTL_MS = 3_600_000; // 1 hour
|
|
58
56
|
|
|
59
57
|
const DEFAULT_PRICING: CursorModelPricing = {
|
|
@@ -69,14 +67,6 @@ const DEFAULT_PRICING: CursorModelPricing = {
|
|
|
69
67
|
let cache: { data: readonly CursorModelPricing[]; expiresAt: number } | null = null;
|
|
70
68
|
let inflightFetch: Promise<readonly CursorModelPricing[]> | null = null;
|
|
71
69
|
|
|
72
|
-
function getApiUrl(): string {
|
|
73
|
-
return process.env.STIGMER_CLOUD_API_URL ?? DEFAULT_API_URL;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function getAuthToken(): string | undefined {
|
|
77
|
-
return process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
70
|
function parsePricingTable(json: unknown): CursorModelPricing[] {
|
|
81
71
|
if (!json || typeof json !== "object") return [];
|
|
82
72
|
const models = (json as Record<string, unknown>).models;
|
|
@@ -114,13 +104,7 @@ function parseVariants(
|
|
|
114
104
|
}
|
|
115
105
|
|
|
116
106
|
async function fetchFromApi(): Promise<readonly CursorModelPricing[]> {
|
|
117
|
-
const
|
|
118
|
-
const headers: Record<string, string> = {};
|
|
119
|
-
const token = getAuthToken();
|
|
120
|
-
if (token) {
|
|
121
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
122
|
-
}
|
|
123
|
-
const res = await fetch(url, { headers });
|
|
107
|
+
const res = await fetch(resolveModelRegistryUrl(), { headers: buildRegistryHeaders() });
|
|
124
108
|
if (!res.ok) throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
125
109
|
const data: unknown = await res.json();
|
|
126
110
|
const table = parsePricingTable(data);
|
package/src/config.ts
CHANGED
|
@@ -230,8 +230,11 @@ function requireEnv(name: string): string {
|
|
|
230
230
|
/**
|
|
231
231
|
* Ensures the endpoint has an HTTP(S) scheme. Port 443 implies TLS;
|
|
232
232
|
* all other bare host:port endpoints get http://.
|
|
233
|
+
*
|
|
234
|
+
* Exported so registry-endpoint.ts applies the same normalization to
|
|
235
|
+
* STIGMER_BACKEND_ENDPOINT that this module applies when loading config.
|
|
233
236
|
*/
|
|
234
|
-
function normalizeEndpoint(endpoint: string): string {
|
|
237
|
+
export function normalizeEndpoint(endpoint: string): string {
|
|
235
238
|
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
236
239
|
return endpoint;
|
|
237
240
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getSummarizationModel,
|
|
4
|
+
getEconomyModel,
|
|
5
|
+
getDefaultModel,
|
|
6
|
+
resolveToApiModelId,
|
|
7
|
+
_resetRegistryCache,
|
|
8
|
+
} from "../model-registry.js";
|
|
3
9
|
|
|
4
10
|
describe("getSummarizationModel", () => {
|
|
5
11
|
beforeEach(() => {
|
|
@@ -178,6 +184,73 @@ describe("getDefaultModel", () => {
|
|
|
178
184
|
});
|
|
179
185
|
});
|
|
180
186
|
|
|
187
|
+
describe("resolveToApiModelId", () => {
|
|
188
|
+
beforeEach(() => {
|
|
189
|
+
_resetRegistryCache();
|
|
190
|
+
vi.restoreAllMocks();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
afterEach(() => {
|
|
194
|
+
_resetRegistryCache();
|
|
195
|
+
vi.useRealTimers();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("resolves a canonical registry id to the provider api id", async () => {
|
|
199
|
+
mockRegistryResponse([
|
|
200
|
+
{ id: "claude-haiku-4.5", apiModelId: "claude-haiku-4-5-20251001", provider: "anthropic", costTier: "economy", harness: "native" },
|
|
201
|
+
]);
|
|
202
|
+
|
|
203
|
+
const result = await resolveToApiModelId("claude-haiku-4.5");
|
|
204
|
+
expect(result).toBe("claude-haiku-4-5-20251001");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("passes unknown ids through unchanged (provider api ids stay verbatim)", async () => {
|
|
208
|
+
mockRegistryResponse([
|
|
209
|
+
{ id: "claude-haiku-4.5", apiModelId: "claude-haiku-4-5-20251001", provider: "anthropic", costTier: "economy", harness: "native" },
|
|
210
|
+
]);
|
|
211
|
+
|
|
212
|
+
const result = await resolveToApiModelId("claude-haiku-4-5-20251001");
|
|
213
|
+
expect(result).toBe("claude-haiku-4-5-20251001");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("degrades to pass-through when the registry fetch fails", async () => {
|
|
217
|
+
vi.spyOn(globalThis, "fetch").mockRejectedValueOnce(new Error("network error"));
|
|
218
|
+
|
|
219
|
+
const result = await resolveToApiModelId("claude-haiku-4.5");
|
|
220
|
+
expect(result).toBe("claude-haiku-4.5");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("retries after the short failure TTL instead of caching the failure for an hour", async () => {
|
|
224
|
+
vi.useFakeTimers();
|
|
225
|
+
const fetchSpy = vi
|
|
226
|
+
.spyOn(globalThis, "fetch")
|
|
227
|
+
.mockRejectedValueOnce(new Error("network error"))
|
|
228
|
+
.mockResolvedValueOnce(
|
|
229
|
+
new Response(
|
|
230
|
+
JSON.stringify({
|
|
231
|
+
models: [
|
|
232
|
+
{ id: "claude-haiku-4.5", apiModelId: "claude-haiku-4-5-20251001", provider: "anthropic", costTier: "economy", harness: "native" },
|
|
233
|
+
],
|
|
234
|
+
}),
|
|
235
|
+
{ status: 200, headers: { "Content-Type": "application/json" } },
|
|
236
|
+
),
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// First call fails and degrades to pass-through.
|
|
240
|
+
expect(await resolveToApiModelId("claude-haiku-4.5")).toBe("claude-haiku-4.5");
|
|
241
|
+
|
|
242
|
+
// Within the failure TTL the empty result stays cached (no refetch).
|
|
243
|
+
vi.advanceTimersByTime(30_000);
|
|
244
|
+
expect(await resolveToApiModelId("claude-haiku-4.5")).toBe("claude-haiku-4.5");
|
|
245
|
+
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
|
246
|
+
|
|
247
|
+
// Past the failure TTL the registry is refetched and resolution recovers.
|
|
248
|
+
vi.advanceTimersByTime(31_000);
|
|
249
|
+
expect(await resolveToApiModelId("claude-haiku-4.5")).toBe("claude-haiku-4-5-20251001");
|
|
250
|
+
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
181
254
|
interface MockModel {
|
|
182
255
|
id: string;
|
|
183
256
|
apiModelId?: string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
resolveRegistryBaseUrl,
|
|
4
|
+
resolveModelRegistryUrl,
|
|
5
|
+
buildRegistryHeaders,
|
|
6
|
+
} from "../registry-endpoint.js";
|
|
7
|
+
|
|
8
|
+
describe("resolveRegistryBaseUrl", () => {
|
|
9
|
+
it("prefers STIGMER_CLOUD_API_URL over everything (explicit override)", () => {
|
|
10
|
+
const env = {
|
|
11
|
+
STIGMER_CLOUD_API_URL: "https://override.example.com",
|
|
12
|
+
STIGMER_PROXY_ENDPOINT: "https://proxy.example.com",
|
|
13
|
+
STIGMER_BACKEND_ENDPOINT: "http://localhost:7234",
|
|
14
|
+
};
|
|
15
|
+
expect(resolveRegistryBaseUrl(env)).toBe("https://override.example.com");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("uses the proxy origin in proxy mode (it serves /v1/proxy/model-registry)", () => {
|
|
19
|
+
const env = {
|
|
20
|
+
STIGMER_PROXY_ENDPOINT: "https://api.stigmer.ai",
|
|
21
|
+
STIGMER_BACKEND_ENDPOINT: "http://localhost:7234",
|
|
22
|
+
};
|
|
23
|
+
expect(resolveRegistryBaseUrl(env)).toBe("https://api.stigmer.ai");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("uses the backend endpoint in direct/local mode (no proxy, no override)", () => {
|
|
27
|
+
const env = { STIGMER_BACKEND_ENDPOINT: "http://localhost:7234" };
|
|
28
|
+
expect(resolveRegistryBaseUrl(env)).toBe("http://localhost:7234");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("defaults to the local stigmer-server when nothing is set", () => {
|
|
32
|
+
expect(resolveRegistryBaseUrl({})).toBe("http://localhost:7234");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("normalizes bare host:port endpoints (443 implies TLS)", () => {
|
|
36
|
+
expect(resolveRegistryBaseUrl({ STIGMER_BACKEND_ENDPOINT: "api.stigmer.ai:443" }))
|
|
37
|
+
.toBe("https://api.stigmer.ai:443");
|
|
38
|
+
expect(resolveRegistryBaseUrl({ STIGMER_BACKEND_ENDPOINT: "backend:7234" }))
|
|
39
|
+
.toBe("http://backend:7234");
|
|
40
|
+
expect(resolveRegistryBaseUrl({ STIGMER_PROXY_ENDPOINT: "proxy.internal:443" }))
|
|
41
|
+
.toBe("https://proxy.internal:443");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("treats empty-string env values as unset", () => {
|
|
45
|
+
const env = {
|
|
46
|
+
STIGMER_CLOUD_API_URL: "",
|
|
47
|
+
STIGMER_PROXY_ENDPOINT: "",
|
|
48
|
+
STIGMER_BACKEND_ENDPOINT: "http://localhost:9999",
|
|
49
|
+
};
|
|
50
|
+
expect(resolveRegistryBaseUrl(env)).toBe("http://localhost:9999");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("resolveModelRegistryUrl", () => {
|
|
55
|
+
it("appends the model registry path to the resolved base", () => {
|
|
56
|
+
const env = { STIGMER_BACKEND_ENDPOINT: "http://localhost:7234" };
|
|
57
|
+
expect(resolveModelRegistryUrl(env)).toBe("http://localhost:7234/v1/proxy/model-registry");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("buildRegistryHeaders", () => {
|
|
62
|
+
it("returns bearer auth when STIGMER_TOKEN is set", () => {
|
|
63
|
+
expect(buildRegistryHeaders({ STIGMER_TOKEN: "tok-1" }))
|
|
64
|
+
.toEqual({ Authorization: "Bearer tok-1" });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("falls back to STIGMER_AUTH_TOKEN", () => {
|
|
68
|
+
expect(buildRegistryHeaders({ STIGMER_AUTH_TOKEN: "tok-2" }))
|
|
69
|
+
.toEqual({ Authorization: "Bearer tok-2" });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("prefers STIGMER_TOKEN over STIGMER_AUTH_TOKEN", () => {
|
|
73
|
+
expect(buildRegistryHeaders({ STIGMER_TOKEN: "tok-1", STIGMER_AUTH_TOKEN: "tok-2" }))
|
|
74
|
+
.toEqual({ Authorization: "Bearer tok-1" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("returns no headers when tokenless (local server needs none)", () => {
|
|
78
|
+
expect(buildRegistryHeaders({})).toEqual({});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -30,7 +30,8 @@ interface RegistryEntry {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "./registry-endpoint.js";
|
|
34
|
+
|
|
34
35
|
const CACHE_TTL_MS = 3_600_000;
|
|
35
36
|
|
|
36
37
|
export const DEFAULT_PRICING: ModelPricing = {
|
|
@@ -65,13 +66,7 @@ function parsePricingTable(json: unknown): ModelPricing[] {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
async function fetchFromApi(): Promise<readonly ModelPricing[]> {
|
|
68
|
-
const
|
|
69
|
-
const headers: Record<string, string> = {};
|
|
70
|
-
const token = process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
71
|
-
if (token) {
|
|
72
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
73
|
-
}
|
|
74
|
-
const res = await fetch(url, { headers });
|
|
69
|
+
const res = await fetch(resolveModelRegistryUrl(), { headers: buildRegistryHeaders() });
|
|
75
70
|
if (!res.ok) throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
76
71
|
const data: unknown = await res.json();
|
|
77
72
|
const table = parsePricingTable(data);
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model registry — provider lookup and economy-tier model derivation.
|
|
3
3
|
*
|
|
4
|
-
* Fetches the model registry from the
|
|
4
|
+
* Fetches the model registry from the runner's control plane (see
|
|
5
|
+
* registry-endpoint.ts for endpoint resolution — same endpoint as
|
|
5
6
|
* model-pricing-data.ts) and uses `costTier` + `harness` fields to
|
|
6
7
|
* dynamically resolve economy-tier models for extraction/summarization.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
import { resolveModelRegistryUrl, buildRegistryHeaders } from "./registry-endpoint.js";
|
|
11
|
+
|
|
10
12
|
const CACHE_TTL_MS = 3_600_000;
|
|
13
|
+
// Failed fetches are cached much shorter than successes: a transient failure
|
|
14
|
+
// must not poison id -> apiModelId resolution (and thereby fail every llm_call
|
|
15
|
+
// with LLM_MODEL_NOT_FOUND) for a full hour.
|
|
16
|
+
const FAILURE_CACHE_TTL_MS = 60_000;
|
|
11
17
|
|
|
12
18
|
interface RegistryModel {
|
|
13
19
|
id: string;
|
|
@@ -39,13 +45,8 @@ function parseRegistry(json: unknown): RegistryModel[] {
|
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
async function fetchRegistry(): Promise<readonly RegistryModel[]> {
|
|
42
|
-
const url =
|
|
43
|
-
const
|
|
44
|
-
const token = process.env.STIGMER_TOKEN ?? process.env.STIGMER_AUTH_TOKEN;
|
|
45
|
-
if (token) {
|
|
46
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
47
|
-
}
|
|
48
|
-
const res = await fetch(url, { headers });
|
|
48
|
+
const url = resolveModelRegistryUrl();
|
|
49
|
+
const res = await fetch(url, { headers: buildRegistryHeaders() });
|
|
49
50
|
if (!res.ok) throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
50
51
|
const data: unknown = await res.json();
|
|
51
52
|
return parseRegistry(data);
|
|
@@ -64,8 +65,13 @@ async function getRegistry(): Promise<readonly RegistryModel[]> {
|
|
|
64
65
|
return models;
|
|
65
66
|
})
|
|
66
67
|
.catch((err) => {
|
|
67
|
-
console.warn(
|
|
68
|
-
|
|
68
|
+
console.warn(
|
|
69
|
+
`Failed to fetch model registry from ${resolveModelRegistryUrl()}: ${err}. ` +
|
|
70
|
+
`Model id resolution degrades to pass-through until the next attempt ` +
|
|
71
|
+
`(${FAILURE_CACHE_TTL_MS / 1000}s). Check that the control plane is ` +
|
|
72
|
+
`reachable and, for cloud endpoints, that STIGMER_TOKEN is set.`,
|
|
73
|
+
);
|
|
74
|
+
cache = { models: [], expiresAt: Date.now() + FAILURE_CACHE_TTL_MS };
|
|
69
75
|
return [] as readonly RegistryModel[];
|
|
70
76
|
})
|
|
71
77
|
.finally(() => {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry endpoint resolution — where the runner fetches the model registry.
|
|
3
|
+
*
|
|
4
|
+
* The model registry (canonical id → provider apiModelId, pricing, tiers) is
|
|
5
|
+
* served at `/v1/proxy/model-registry` by whichever control plane the runner
|
|
6
|
+
* talks to: the cloud API in proxy mode, or the local stigmer-server in
|
|
7
|
+
* direct/local mode (stigmer/stigmer#240). Resolution is therefore
|
|
8
|
+
* topology-based, not token-based:
|
|
9
|
+
*
|
|
10
|
+
* 1. STIGMER_CLOUD_API_URL — explicit override (tests, unusual topologies)
|
|
11
|
+
* 2. STIGMER_PROXY_ENDPOINT — proxy mode: the origin that serves the rest of
|
|
12
|
+
* the runner's /v1/proxy surface (LLM proxy, checkpoints, artifacts) also
|
|
13
|
+
* serves the registry
|
|
14
|
+
* 3. STIGMER_BACKEND_ENDPOINT — direct/local mode: the runner's own control
|
|
15
|
+
* plane, defaulting to the local stigmer-server address
|
|
16
|
+
*
|
|
17
|
+
* A hardcoded cloud URL is deliberately absent: every runner already knows a
|
|
18
|
+
* control-plane origin that serves the registry, so falling back to the hosted
|
|
19
|
+
* API would only mask misconfiguration (and breaks offline/local use).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { normalizeEndpoint } from "../config.js";
|
|
23
|
+
|
|
24
|
+
/** Default local stigmer-server origin — mirrors config.ts's local-mode default. */
|
|
25
|
+
const DEFAULT_LOCAL_BACKEND = "http://localhost:7234";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the base URL (origin, no path) for model-registry and pricing
|
|
29
|
+
* fetches. See module doc for the tier order.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveRegistryBaseUrl(env: NodeJS.ProcessEnv = process.env): string {
|
|
32
|
+
const override = env.STIGMER_CLOUD_API_URL;
|
|
33
|
+
if (override) return normalizeEndpoint(override);
|
|
34
|
+
|
|
35
|
+
const proxyEndpoint = env.STIGMER_PROXY_ENDPOINT;
|
|
36
|
+
if (proxyEndpoint) return normalizeEndpoint(proxyEndpoint);
|
|
37
|
+
|
|
38
|
+
return normalizeEndpoint(env.STIGMER_BACKEND_ENDPOINT ?? DEFAULT_LOCAL_BACKEND);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build request headers for registry fetches: bearer auth when a token is
|
|
43
|
+
* present (cloud requires it; the local server ignores it).
|
|
44
|
+
*/
|
|
45
|
+
export function buildRegistryHeaders(env: NodeJS.ProcessEnv = process.env): Record<string, string> {
|
|
46
|
+
const token = env.STIGMER_TOKEN ?? env.STIGMER_AUTH_TOKEN;
|
|
47
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Full URL of the model registry endpoint for the resolved control plane. */
|
|
51
|
+
export function resolveModelRegistryUrl(env: NodeJS.ProcessEnv = process.env): string {
|
|
52
|
+
return `${resolveRegistryBaseUrl(env)}/v1/proxy/model-registry`;
|
|
53
|
+
}
|