@telora/daemon 0.18.61 → 0.18.68
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/build-info.json +2 -2
- package/dist/config.d.ts +16 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +76 -13
- package/dist/config.js.map +1 -1
- package/dist/discovery-poll.d.ts.map +1 -1
- package/dist/discovery-poll.js +14 -2
- package/dist/discovery-poll.js.map +1 -1
- package/dist/focus-executor.d.ts +26 -3
- package/dist/focus-executor.d.ts.map +1 -1
- package/dist/focus-executor.js +79 -0
- package/dist/focus-executor.js.map +1 -1
- package/dist/git-fetch.d.ts +123 -0
- package/dist/git-fetch.d.ts.map +1 -0
- package/dist/git-fetch.js +164 -0
- package/dist/git-fetch.js.map +1 -0
- package/dist/git-state-detector.d.ts.map +1 -1
- package/dist/git-state-detector.js +63 -26
- package/dist/git-state-detector.js.map +1 -1
- package/dist/host-control/capability.d.ts +31 -0
- package/dist/host-control/capability.d.ts.map +1 -0
- package/dist/host-control/capability.js +50 -0
- package/dist/host-control/capability.js.map +1 -0
- package/dist/host-control/catalog.d.ts +48 -0
- package/dist/host-control/catalog.d.ts.map +1 -0
- package/dist/host-control/catalog.js +149 -0
- package/dist/host-control/catalog.js.map +1 -0
- package/dist/host-control/client.d.ts +76 -0
- package/dist/host-control/client.d.ts.map +1 -0
- package/dist/host-control/client.js +203 -0
- package/dist/host-control/client.js.map +1 -0
- package/dist/host-control/index.d.ts +18 -0
- package/dist/host-control/index.d.ts.map +1 -0
- package/dist/host-control/index.js +14 -0
- package/dist/host-control/index.js.map +1 -0
- package/dist/host-control/load.d.ts +136 -0
- package/dist/host-control/load.d.ts.map +1 -0
- package/dist/host-control/load.js +241 -0
- package/dist/host-control/load.js.map +1 -0
- package/dist/host-control/sizing.d.ts +207 -0
- package/dist/host-control/sizing.d.ts.map +1 -0
- package/dist/host-control/sizing.js +464 -0
- package/dist/host-control/sizing.js.map +1 -0
- package/dist/host-control/types.d.ts +174 -0
- package/dist/host-control/types.d.ts.map +1 -0
- package/dist/host-control/types.js +16 -0
- package/dist/host-control/types.js.map +1 -0
- package/dist/prd-controller.d.ts +10 -12
- package/dist/prd-controller.d.ts.map +1 -1
- package/dist/prd-controller.js +24 -54
- package/dist/prd-controller.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-endpoint host-control capability detection (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* The control plane is an OPTIONAL capability detected per-endpoint, never
|
|
5
|
+
* assumed. `detectHostCapability` runs a CHEAP, FAIL-SAFE probe against the host
|
|
6
|
+
* root's control surface: a 2xx with a well-formed (non-empty, usable) catalog
|
|
7
|
+
* means controllable; ANY other outcome -- error, non-2xx, parse failure,
|
|
8
|
+
* timeout, or an empty/unusable payload -- means NOT controllable, so the caller
|
|
9
|
+
* falls back to the `/v1/models` floor. This guarantees a plain
|
|
10
|
+
* OpenAI-compatible endpoint is never broken by the probe.
|
|
11
|
+
*/
|
|
12
|
+
import type { HostCapability } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pure decision: does a control-surface payload prove the host is controllable?
|
|
15
|
+
* True only when the payload normalizes to at least one usable loadable-model
|
|
16
|
+
* entry. A malformed, empty, or non-catalog payload yields false. Exported for
|
|
17
|
+
* unit testing the interpret-a-payload -> controllable? boundary in isolation.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isControllableCatalogPayload(payload: unknown): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Probe an endpoint's host root for the optional control capability. Cheap (a
|
|
22
|
+
* single GET, time-boxed by the client) and FAIL-SAFE: every failure mode --
|
|
23
|
+
* SSRF rejection, network error, non-2xx, invalid JSON, timeout, or an
|
|
24
|
+
* empty/unusable catalog -- resolves to `{ controllable: false }` rather than
|
|
25
|
+
* throwing, so the caller can unconditionally proceed to the floor.
|
|
26
|
+
*
|
|
27
|
+
* `apiKey` is the bearer VALUE (resolved from the Telora secret) authorizing the
|
|
28
|
+
* probe against an auth-protected host.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectHostCapability(baseUrl: string, apiKey?: string | null): Promise<HostCapability>;
|
|
31
|
+
//# sourceMappingURL=capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/host-control/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEtE;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,cAAc,CAAC,CAezB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-endpoint host-control capability detection (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* The control plane is an OPTIONAL capability detected per-endpoint, never
|
|
5
|
+
* assumed. `detectHostCapability` runs a CHEAP, FAIL-SAFE probe against the host
|
|
6
|
+
* root's control surface: a 2xx with a well-formed (non-empty, usable) catalog
|
|
7
|
+
* means controllable; ANY other outcome -- error, non-2xx, parse failure,
|
|
8
|
+
* timeout, or an empty/unusable payload -- means NOT controllable, so the caller
|
|
9
|
+
* falls back to the `/v1/models` floor. This guarantees a plain
|
|
10
|
+
* OpenAI-compatible endpoint is never broken by the probe.
|
|
11
|
+
*/
|
|
12
|
+
import { hostGet, hostRootFromBaseUrl, HOST_CONTROL_FETCH_TIMEOUT_MS } from './client.js';
|
|
13
|
+
import { HOST_CONTROL_CATALOG_PATH, normalizeLocalCatalog } from './catalog.js';
|
|
14
|
+
/**
|
|
15
|
+
* Pure decision: does a control-surface payload prove the host is controllable?
|
|
16
|
+
* True only when the payload normalizes to at least one usable loadable-model
|
|
17
|
+
* entry. A malformed, empty, or non-catalog payload yields false. Exported for
|
|
18
|
+
* unit testing the interpret-a-payload -> controllable? boundary in isolation.
|
|
19
|
+
*/
|
|
20
|
+
export function isControllableCatalogPayload(payload) {
|
|
21
|
+
return normalizeLocalCatalog(payload).length > 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Probe an endpoint's host root for the optional control capability. Cheap (a
|
|
25
|
+
* single GET, time-boxed by the client) and FAIL-SAFE: every failure mode --
|
|
26
|
+
* SSRF rejection, network error, non-2xx, invalid JSON, timeout, or an
|
|
27
|
+
* empty/unusable catalog -- resolves to `{ controllable: false }` rather than
|
|
28
|
+
* throwing, so the caller can unconditionally proceed to the floor.
|
|
29
|
+
*
|
|
30
|
+
* `apiKey` is the bearer VALUE (resolved from the Telora secret) authorizing the
|
|
31
|
+
* probe against an auth-protected host.
|
|
32
|
+
*/
|
|
33
|
+
export async function detectHostCapability(baseUrl, apiKey) {
|
|
34
|
+
const root = hostRootFromBaseUrl(baseUrl);
|
|
35
|
+
const catalogUrl = `${root}${HOST_CONTROL_CATALOG_PATH}`;
|
|
36
|
+
try {
|
|
37
|
+
const payload = await hostGet(catalogUrl, {
|
|
38
|
+
apiKey,
|
|
39
|
+
timeoutMs: HOST_CONTROL_FETCH_TIMEOUT_MS,
|
|
40
|
+
});
|
|
41
|
+
return { controllable: isControllableCatalogPayload(payload) };
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Fail-safe: any error => not controllable. Detail is intentionally swallowed
|
|
45
|
+
// here (the catalog reader logs on its own fall-through); the probe must never
|
|
46
|
+
// surface a probe-oracle or break the floor path.
|
|
47
|
+
return { controllable: false };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../../src/host-control/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGhF;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAgB;IAC3D,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,MAAsB;IAEtB,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,GAAG,IAAI,GAAG,yBAAyB,EAAE,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAU,UAAU,EAAE;YACjD,MAAM;YACN,SAAS,EAAE,6BAA6B;SACzC,CAAC,CAAC;QACH,OAAO,EAAE,YAAY,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;QAC9E,+EAA+E;QAC/E,kDAAkD;QAClD,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loadable-model catalog reader for the host-control plane (Local model host
|
|
3
|
+
* control, D1).
|
|
4
|
+
*
|
|
5
|
+
* A controllable host (e.g. Unsloth Studio @ :8888) exposes its FULL
|
|
6
|
+
* downloaded-but-unloaded catalog under the control surface
|
|
7
|
+
* `<root>/api/models/local`, returning every loadable model -- not just the one
|
|
8
|
+
* currently loaded that `/v1/models` reports. This module reads that catalog and
|
|
9
|
+
* degrades CLEANLY to the `/v1/models` floor (via discovery-poll's
|
|
10
|
+
* `fetchModels`) when the host is not controllable or the catalog read fails for
|
|
11
|
+
* any reason. The floor path is byte-identical to today's behavior, so a plain
|
|
12
|
+
* OpenAI-compatible endpoint is never broken.
|
|
13
|
+
*
|
|
14
|
+
* The live catalog JSON shape is host-specific (observed: 25 entries under
|
|
15
|
+
* `/api/models/local`, each carrying a load path). We do NOT have the exact live
|
|
16
|
+
* shape pinned, so `normalizeLocalCatalog` is DEFENSIVE: it tolerates a range of
|
|
17
|
+
* reasonable container and field names and is easy to extend per the runbook's
|
|
18
|
+
* live-shape reconciliation.
|
|
19
|
+
*/
|
|
20
|
+
import type { LoadableCatalog, LoadableModel } from './types.js';
|
|
21
|
+
/** The control-surface path (under the host ROOT, not `/v1`) for the full catalog. */
|
|
22
|
+
export declare const HOST_CONTROL_CATALOG_PATH = "/api/models/local";
|
|
23
|
+
/**
|
|
24
|
+
* Normalize a control-surface catalog payload into clean `LoadableModel`
|
|
25
|
+
* entries. Pure + DEFENSIVE: tolerates a bare array or a wrapped container,
|
|
26
|
+
* non-object items, missing/blank ids (dropped), and a missing model_path
|
|
27
|
+
* (captured as null). De-duplicates by id (first entry with a model_path wins
|
|
28
|
+
* its path). Exported for unit testing.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeLocalCatalog(payload: unknown): LoadableModel[];
|
|
31
|
+
/**
|
|
32
|
+
* Read an endpoint's loadable-model catalog, preferring the controllable host
|
|
33
|
+
* catalog and degrading cleanly to the `/v1/models` floor.
|
|
34
|
+
*
|
|
35
|
+
* Control path: GET `<root>/api/models/local`, normalize, and if it yields at
|
|
36
|
+
* least one usable entry return the full loadable list (`controllable: true`).
|
|
37
|
+
*
|
|
38
|
+
* Floor path: on ANY control-surface failure (unreachable, non-2xx, invalid
|
|
39
|
+
* JSON, timeout, or an empty/unusable catalog) fall back to `fetchModels`
|
|
40
|
+
* (`/v1/models`) so behavior is exactly today's load-then-discover. The floor
|
|
41
|
+
* fetch's own failure propagates to the caller (same contract as the existing
|
|
42
|
+
* discovery path).
|
|
43
|
+
*
|
|
44
|
+
* `apiKey` is the bearer VALUE (resolved from the Telora secret); it authorizes
|
|
45
|
+
* both the control probe and the floor fetch.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readLoadableCatalog(baseUrl: string, apiKey?: string | null): Promise<LoadableCatalog>;
|
|
48
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/host-control/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjE,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAgD7D;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,EAAE,CAkBvE;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,eAAe,CAAC,CAwB1B"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loadable-model catalog reader for the host-control plane (Local model host
|
|
3
|
+
* control, D1).
|
|
4
|
+
*
|
|
5
|
+
* A controllable host (e.g. Unsloth Studio @ :8888) exposes its FULL
|
|
6
|
+
* downloaded-but-unloaded catalog under the control surface
|
|
7
|
+
* `<root>/api/models/local`, returning every loadable model -- not just the one
|
|
8
|
+
* currently loaded that `/v1/models` reports. This module reads that catalog and
|
|
9
|
+
* degrades CLEANLY to the `/v1/models` floor (via discovery-poll's
|
|
10
|
+
* `fetchModels`) when the host is not controllable or the catalog read fails for
|
|
11
|
+
* any reason. The floor path is byte-identical to today's behavior, so a plain
|
|
12
|
+
* OpenAI-compatible endpoint is never broken.
|
|
13
|
+
*
|
|
14
|
+
* The live catalog JSON shape is host-specific (observed: 25 entries under
|
|
15
|
+
* `/api/models/local`, each carrying a load path). We do NOT have the exact live
|
|
16
|
+
* shape pinned, so `normalizeLocalCatalog` is DEFENSIVE: it tolerates a range of
|
|
17
|
+
* reasonable container and field names and is easy to extend per the runbook's
|
|
18
|
+
* live-shape reconciliation.
|
|
19
|
+
*/
|
|
20
|
+
import { fetchModels } from '../discovery-poll.js';
|
|
21
|
+
import { hostGet, hostRootFromBaseUrl, HOST_CONTROL_FETCH_TIMEOUT_MS, HostControlError, } from './client.js';
|
|
22
|
+
/** The control-surface path (under the host ROOT, not `/v1`) for the full catalog. */
|
|
23
|
+
export const HOST_CONTROL_CATALOG_PATH = '/api/models/local';
|
|
24
|
+
/**
|
|
25
|
+
* Candidate keys that may carry the array of catalog entries. The live host
|
|
26
|
+
* (Unsloth Studio) returned a bare array under `/api/models/local`; other hosts
|
|
27
|
+
* may wrap it. Defensive: we accept a top-level array OR any of these container
|
|
28
|
+
* keys. Easy to extend per the runbook.
|
|
29
|
+
*/
|
|
30
|
+
const CATALOG_ARRAY_KEYS = ['models', 'data', 'local', 'items'];
|
|
31
|
+
/**
|
|
32
|
+
* Candidate keys for a catalog entry's served model id. `id` is canonical;
|
|
33
|
+
* `model`/`name` are common alternates on local-model hosts.
|
|
34
|
+
*/
|
|
35
|
+
const ID_KEYS = ['id', 'model', 'name'];
|
|
36
|
+
/**
|
|
37
|
+
* Candidate keys for a catalog entry's host load path. `model_path` is the
|
|
38
|
+
* observed convention; the rest are reasonable alternates. Captured verbatim so
|
|
39
|
+
* Delivery 2 can resolve id -> path to load the model.
|
|
40
|
+
*/
|
|
41
|
+
const MODEL_PATH_KEYS = ['model_path', 'modelPath', 'path', 'file', 'gguf_path'];
|
|
42
|
+
/** Read the first string-valued key present on an object, trimmed; '' if none. */
|
|
43
|
+
function firstString(obj, keys) {
|
|
44
|
+
for (const key of keys) {
|
|
45
|
+
const v = obj[key];
|
|
46
|
+
if (typeof v === 'string') {
|
|
47
|
+
const trimmed = v.trim();
|
|
48
|
+
if (trimmed)
|
|
49
|
+
return trimmed;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
/** Extract the catalog-entry array from a payload that is either a bare array or
|
|
55
|
+
* a single-keyed container. Returns [] when no array is found (defensive). */
|
|
56
|
+
function extractEntryArray(payload) {
|
|
57
|
+
if (Array.isArray(payload))
|
|
58
|
+
return payload;
|
|
59
|
+
if (!payload || typeof payload !== 'object')
|
|
60
|
+
return [];
|
|
61
|
+
const obj = payload;
|
|
62
|
+
for (const key of CATALOG_ARRAY_KEYS) {
|
|
63
|
+
const v = obj[key];
|
|
64
|
+
if (Array.isArray(v))
|
|
65
|
+
return v;
|
|
66
|
+
}
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Normalize a control-surface catalog payload into clean `LoadableModel`
|
|
71
|
+
* entries. Pure + DEFENSIVE: tolerates a bare array or a wrapped container,
|
|
72
|
+
* non-object items, missing/blank ids (dropped), and a missing model_path
|
|
73
|
+
* (captured as null). De-duplicates by id (first entry with a model_path wins
|
|
74
|
+
* its path). Exported for unit testing.
|
|
75
|
+
*/
|
|
76
|
+
export function normalizeLocalCatalog(payload) {
|
|
77
|
+
const entries = extractEntryArray(payload);
|
|
78
|
+
const byId = new Map();
|
|
79
|
+
for (const item of entries) {
|
|
80
|
+
if (!item || typeof item !== 'object')
|
|
81
|
+
continue;
|
|
82
|
+
const obj = item;
|
|
83
|
+
const id = firstString(obj, ID_KEYS);
|
|
84
|
+
if (!id)
|
|
85
|
+
continue; // an entry with no usable id is unselectable -- drop it.
|
|
86
|
+
const modelPath = firstString(obj, MODEL_PATH_KEYS) || null;
|
|
87
|
+
const existing = byId.get(id);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
byId.set(id, { id, modelPath });
|
|
90
|
+
}
|
|
91
|
+
else if (existing.modelPath === null && modelPath !== null) {
|
|
92
|
+
// Prefer the duplicate that carries a load path over a path-less twin.
|
|
93
|
+
byId.set(id, { id, modelPath });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return [...byId.values()];
|
|
97
|
+
}
|
|
98
|
+
/** Build the floor-path catalog from a `/v1/models` id list. `modelPath` is null
|
|
99
|
+
* on the floor -- the floor knows only the loaded id, never a load path. */
|
|
100
|
+
function floorCatalog(ids) {
|
|
101
|
+
return {
|
|
102
|
+
controllable: false,
|
|
103
|
+
ids,
|
|
104
|
+
models: ids.map((id) => ({ id, modelPath: null })),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Read an endpoint's loadable-model catalog, preferring the controllable host
|
|
109
|
+
* catalog and degrading cleanly to the `/v1/models` floor.
|
|
110
|
+
*
|
|
111
|
+
* Control path: GET `<root>/api/models/local`, normalize, and if it yields at
|
|
112
|
+
* least one usable entry return the full loadable list (`controllable: true`).
|
|
113
|
+
*
|
|
114
|
+
* Floor path: on ANY control-surface failure (unreachable, non-2xx, invalid
|
|
115
|
+
* JSON, timeout, or an empty/unusable catalog) fall back to `fetchModels`
|
|
116
|
+
* (`/v1/models`) so behavior is exactly today's load-then-discover. The floor
|
|
117
|
+
* fetch's own failure propagates to the caller (same contract as the existing
|
|
118
|
+
* discovery path).
|
|
119
|
+
*
|
|
120
|
+
* `apiKey` is the bearer VALUE (resolved from the Telora secret); it authorizes
|
|
121
|
+
* both the control probe and the floor fetch.
|
|
122
|
+
*/
|
|
123
|
+
export async function readLoadableCatalog(baseUrl, apiKey) {
|
|
124
|
+
const root = hostRootFromBaseUrl(baseUrl);
|
|
125
|
+
const catalogUrl = `${root}${HOST_CONTROL_CATALOG_PATH}`;
|
|
126
|
+
try {
|
|
127
|
+
const payload = await hostGet(catalogUrl, {
|
|
128
|
+
apiKey,
|
|
129
|
+
timeoutMs: HOST_CONTROL_FETCH_TIMEOUT_MS,
|
|
130
|
+
});
|
|
131
|
+
const models = normalizeLocalCatalog(payload);
|
|
132
|
+
if (models.length > 0) {
|
|
133
|
+
return { controllable: true, ids: models.map((m) => m.id), models };
|
|
134
|
+
}
|
|
135
|
+
// Well-formed but empty (or no usable ids): not a usable control catalog --
|
|
136
|
+
// fall through to the floor so the picklist still offers the loaded model.
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
// Fail-safe: any control-surface error means "not controllable here". Log the
|
|
140
|
+
// rich detail daemon-side (address-free dbMessage available for categorizing)
|
|
141
|
+
// and fall through to the floor. Never break a plain endpoint.
|
|
142
|
+
const detail = err instanceof HostControlError ? err.message : err.message;
|
|
143
|
+
console.log(`[host-control] catalog read fell back to /v1/models floor: ${detail}`);
|
|
144
|
+
}
|
|
145
|
+
// Floor: the OpenAI-compatible `/v1/models` listing (today's behavior).
|
|
146
|
+
const ids = await fetchModels(baseUrl, apiKey);
|
|
147
|
+
return floorCatalog(ids);
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/host-control/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed JSON HTTP helpers for the host-control plane (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* These mirror the security posture of `discovery-poll.ts` exactly: the host
|
|
5
|
+
* control surface is an operator-supplied LAN endpoint, so every request must
|
|
6
|
+
* (1) pass the SSRF guard before any network call (TEL-5), (2) time-box with an
|
|
7
|
+
* AbortController so an unreachable host fails fast (TEL-6), (3) cap the body
|
|
8
|
+
* read so a malicious/oversized response can't OOM the daemon (TEL-6), and
|
|
9
|
+
* (4) surface only address-free error categories -- the raw URL/system detail is
|
|
10
|
+
* logged daemon-side, never returned to a caller that may write it to an
|
|
11
|
+
* org-readable column (TEL-5, probe-oracle defense).
|
|
12
|
+
*
|
|
13
|
+
* `hostGet`/`hostPost` are deliberately generic over the decoded shape; the
|
|
14
|
+
* caller validates the `unknown` payload with a defensive normalizer (the
|
|
15
|
+
* control-surface JSON shape is host-specific and reconciled per the runbook).
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Time-box a single host-control fetch. Mirrors `DISCOVERY_FETCH_TIMEOUT_MS`
|
|
19
|
+
* (5000ms) so the control probe fails fast on an unreachable host exactly like
|
|
20
|
+
* the `/v1/models` probe it rides alongside. Re-exported so callers and tests
|
|
21
|
+
* reference one source of truth.
|
|
22
|
+
*/
|
|
23
|
+
export declare const HOST_CONTROL_FETCH_TIMEOUT_MS = 5000;
|
|
24
|
+
/**
|
|
25
|
+
* Hard ceiling on a host-control response body. A model catalog is small (~25
|
|
26
|
+
* entries observed live); this cap defends against an endpoint streaming an
|
|
27
|
+
* unbounded body to OOM the daemon (TEL-6). Mirrors discovery-poll's
|
|
28
|
+
* `MAX_DISCOVERY_BYTES` (1MB) -- declared as its own literal rather than
|
|
29
|
+
* re-exported to avoid an init-order coupling with the cyclic discovery-poll
|
|
30
|
+
* import (this module is imported by discovery-poll, which it also imports from).
|
|
31
|
+
*/
|
|
32
|
+
export declare const HOST_CONTROL_MAX_BYTES = 1000000;
|
|
33
|
+
/**
|
|
34
|
+
* Address-free error categories for the host-control client. The control plane
|
|
35
|
+
* is fail-safe -- callers turn any of these into "not controllable, fall back to
|
|
36
|
+
* the floor" rather than propagating detail -- but they are kept distinct (and
|
|
37
|
+
* address-free) so daemon-side logs can categorize without leaking the endpoint.
|
|
38
|
+
*/
|
|
39
|
+
export declare const HOST_CONTROL_ERROR_REJECTED_URL = "Rejected non-http(s) host URL";
|
|
40
|
+
export declare const HOST_CONTROL_ERROR_STATUS = "Host returned an error status";
|
|
41
|
+
export declare const HOST_CONTROL_ERROR_UNREACHABLE = "Host unreachable or timed out";
|
|
42
|
+
export declare const HOST_CONTROL_ERROR_INVALID = "Host response was not valid";
|
|
43
|
+
/**
|
|
44
|
+
* A host-control client error carrying a sanitized, address-free `dbMessage`
|
|
45
|
+
* alongside the rich `message` (URL/system detail) that is safe only for the
|
|
46
|
+
* daemon log. Same precedent as `discovery-poll`'s `DiscoveryError`.
|
|
47
|
+
*/
|
|
48
|
+
export declare class HostControlError extends Error {
|
|
49
|
+
/** Address-free category string safe to surface anywhere (TEL-5). */
|
|
50
|
+
readonly dbMessage: string;
|
|
51
|
+
constructor(message: string,
|
|
52
|
+
/** Address-free category string safe to surface anywhere (TEL-5). */
|
|
53
|
+
dbMessage: string);
|
|
54
|
+
}
|
|
55
|
+
/** Options common to host-control requests. */
|
|
56
|
+
export interface HostRequestOptions {
|
|
57
|
+
/** Bearer key VALUE for an authenticated host (resolved from the Telora secret). */
|
|
58
|
+
apiKey?: string | null;
|
|
59
|
+
/** Per-request timeout override; defaults to `HOST_CONTROL_FETCH_TIMEOUT_MS`. */
|
|
60
|
+
timeoutMs?: number;
|
|
61
|
+
}
|
|
62
|
+
/** Typed JSON GET against a host-control URL. See `hostRequest` for the posture. */
|
|
63
|
+
export declare function hostGet<T>(url: string, opts?: HostRequestOptions): Promise<T>;
|
|
64
|
+
/** Typed JSON POST against a host-control URL. The body is JSON-encoded. */
|
|
65
|
+
export declare function hostPost<T>(url: string, body: unknown, opts?: HostRequestOptions): Promise<T>;
|
|
66
|
+
/**
|
|
67
|
+
* Derive the host ROOT from a stored `baseUrl`. The registry stores the
|
|
68
|
+
* OpenAI-compatible base (e.g. `http://host:8888/v1`), but the control surface
|
|
69
|
+
* lives under `/api` at the host root, NOT under `/v1`. Strip a single trailing
|
|
70
|
+
* `/v1` segment and any trailing slashes so callers can append `/api/...`. A
|
|
71
|
+
* `baseUrl` that is already a bare root passes through unchanged.
|
|
72
|
+
*
|
|
73
|
+
* Pure + exported for unit testing.
|
|
74
|
+
*/
|
|
75
|
+
export declare function hostRootFromBaseUrl(baseUrl: string): string;
|
|
76
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/host-control/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,kCAAkC,CAAC;AAC/E,eAAO,MAAM,yBAAyB,kCAAkC,CAAC;AACzE,eAAO,MAAM,8BAA8B,kCAAkC,CAAC;AAC9E,eAAO,MAAM,0BAA0B,gCAAgC,CAAC;AAExE;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IAGvC,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM;gBAF1B,OAAO,EAAE,MAAM;IACf,qEAAqE;IAC5D,SAAS,EAAE,MAAM;CAK7B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0ID,oFAAoF;AACpF,wBAAsB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC,CAEvF;AAED,4EAA4E;AAC5E,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,CAAC,CAAC,CAMZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO3D"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed JSON HTTP helpers for the host-control plane (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* These mirror the security posture of `discovery-poll.ts` exactly: the host
|
|
5
|
+
* control surface is an operator-supplied LAN endpoint, so every request must
|
|
6
|
+
* (1) pass the SSRF guard before any network call (TEL-5), (2) time-box with an
|
|
7
|
+
* AbortController so an unreachable host fails fast (TEL-6), (3) cap the body
|
|
8
|
+
* read so a malicious/oversized response can't OOM the daemon (TEL-6), and
|
|
9
|
+
* (4) surface only address-free error categories -- the raw URL/system detail is
|
|
10
|
+
* logged daemon-side, never returned to a caller that may write it to an
|
|
11
|
+
* org-readable column (TEL-5, probe-oracle defense).
|
|
12
|
+
*
|
|
13
|
+
* `hostGet`/`hostPost` are deliberately generic over the decoded shape; the
|
|
14
|
+
* caller validates the `unknown` payload with a defensive normalizer (the
|
|
15
|
+
* control-surface JSON shape is host-specific and reconciled per the runbook).
|
|
16
|
+
*/
|
|
17
|
+
import { isAllowedDiscoveryUrl } from '../discovery-poll.js';
|
|
18
|
+
/**
|
|
19
|
+
* Time-box a single host-control fetch. Mirrors `DISCOVERY_FETCH_TIMEOUT_MS`
|
|
20
|
+
* (5000ms) so the control probe fails fast on an unreachable host exactly like
|
|
21
|
+
* the `/v1/models` probe it rides alongside. Re-exported so callers and tests
|
|
22
|
+
* reference one source of truth.
|
|
23
|
+
*/
|
|
24
|
+
export const HOST_CONTROL_FETCH_TIMEOUT_MS = 5000;
|
|
25
|
+
/**
|
|
26
|
+
* Hard ceiling on a host-control response body. A model catalog is small (~25
|
|
27
|
+
* entries observed live); this cap defends against an endpoint streaming an
|
|
28
|
+
* unbounded body to OOM the daemon (TEL-6). Mirrors discovery-poll's
|
|
29
|
+
* `MAX_DISCOVERY_BYTES` (1MB) -- declared as its own literal rather than
|
|
30
|
+
* re-exported to avoid an init-order coupling with the cyclic discovery-poll
|
|
31
|
+
* import (this module is imported by discovery-poll, which it also imports from).
|
|
32
|
+
*/
|
|
33
|
+
export const HOST_CONTROL_MAX_BYTES = 1_000_000;
|
|
34
|
+
/**
|
|
35
|
+
* Address-free error categories for the host-control client. The control plane
|
|
36
|
+
* is fail-safe -- callers turn any of these into "not controllable, fall back to
|
|
37
|
+
* the floor" rather than propagating detail -- but they are kept distinct (and
|
|
38
|
+
* address-free) so daemon-side logs can categorize without leaking the endpoint.
|
|
39
|
+
*/
|
|
40
|
+
export const HOST_CONTROL_ERROR_REJECTED_URL = 'Rejected non-http(s) host URL';
|
|
41
|
+
export const HOST_CONTROL_ERROR_STATUS = 'Host returned an error status';
|
|
42
|
+
export const HOST_CONTROL_ERROR_UNREACHABLE = 'Host unreachable or timed out';
|
|
43
|
+
export const HOST_CONTROL_ERROR_INVALID = 'Host response was not valid';
|
|
44
|
+
/**
|
|
45
|
+
* A host-control client error carrying a sanitized, address-free `dbMessage`
|
|
46
|
+
* alongside the rich `message` (URL/system detail) that is safe only for the
|
|
47
|
+
* daemon log. Same precedent as `discovery-poll`'s `DiscoveryError`.
|
|
48
|
+
*/
|
|
49
|
+
export class HostControlError extends Error {
|
|
50
|
+
dbMessage;
|
|
51
|
+
constructor(message,
|
|
52
|
+
/** Address-free category string safe to surface anywhere (TEL-5). */
|
|
53
|
+
dbMessage) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.dbMessage = dbMessage;
|
|
56
|
+
this.name = 'HostControlError';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build request headers for a host-control call. When a bearer key VALUE is
|
|
61
|
+
* provided an `Authorization: Bearer <value>` header is added; a blank/absent
|
|
62
|
+
* value yields no auth header (unauthenticated probe). The value is never
|
|
63
|
+
* logged or persisted by this module. Mirrors `buildDiscoveryHeaders`.
|
|
64
|
+
*/
|
|
65
|
+
function buildHostHeaders(apiKey, extra) {
|
|
66
|
+
const headers = { accept: 'application/json', ...extra };
|
|
67
|
+
const value = typeof apiKey === 'string' ? apiKey.trim() : '';
|
|
68
|
+
if (value)
|
|
69
|
+
headers.Authorization = `Bearer ${value}`;
|
|
70
|
+
return headers;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read a fetch response body with a hard byte ceiling, aborting once the cap is
|
|
74
|
+
* exceeded so a lying Content-Length (or a chunked body with none) can't OOM the
|
|
75
|
+
* daemon (TEL-6). Returns the decoded text. Throws a `HostControlError` past the
|
|
76
|
+
* ceiling. Mirrors `discovery-poll`'s `readBodyCapped`.
|
|
77
|
+
*/
|
|
78
|
+
async function readBodyCapped(res) {
|
|
79
|
+
const body = res.body;
|
|
80
|
+
if (!body) {
|
|
81
|
+
// No stream available -- fall back to arrayBuffer but still cap by byteLength.
|
|
82
|
+
const buf = await res.arrayBuffer();
|
|
83
|
+
if (buf.byteLength > HOST_CONTROL_MAX_BYTES) {
|
|
84
|
+
throw new HostControlError('Response body exceeded byte ceiling', HOST_CONTROL_ERROR_INVALID);
|
|
85
|
+
}
|
|
86
|
+
return new TextDecoder().decode(buf);
|
|
87
|
+
}
|
|
88
|
+
const reader = body.getReader();
|
|
89
|
+
const chunks = [];
|
|
90
|
+
let total = 0;
|
|
91
|
+
try {
|
|
92
|
+
for (;;) {
|
|
93
|
+
const { done, value } = await reader.read();
|
|
94
|
+
if (done)
|
|
95
|
+
break;
|
|
96
|
+
if (value) {
|
|
97
|
+
total += value.byteLength;
|
|
98
|
+
if (total > HOST_CONTROL_MAX_BYTES) {
|
|
99
|
+
throw new HostControlError('Response body exceeded byte ceiling', HOST_CONTROL_ERROR_INVALID);
|
|
100
|
+
}
|
|
101
|
+
chunks.push(value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
// Stop the underlying transfer; ignore cancel errors.
|
|
107
|
+
await reader.cancel().catch(() => { });
|
|
108
|
+
}
|
|
109
|
+
const merged = new Uint8Array(total);
|
|
110
|
+
let offset = 0;
|
|
111
|
+
for (const c of chunks) {
|
|
112
|
+
merged.set(c, offset);
|
|
113
|
+
offset += c.byteLength;
|
|
114
|
+
}
|
|
115
|
+
return new TextDecoder().decode(merged);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Map a non-2xx status to an address-free category. 401/403 surface as a status
|
|
119
|
+
* error here (the host-control plane is optional, so an auth wall just means we
|
|
120
|
+
* fall back to the floor) -- unlike discovery, we don't disclose an auth-specific
|
|
121
|
+
* message, because a control-surface 401 is not independently actionable.
|
|
122
|
+
*/
|
|
123
|
+
function statusDbMessage(_status) {
|
|
124
|
+
return HOST_CONTROL_ERROR_STATUS;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Issue a host-control request and decode the JSON body, enforcing the full
|
|
128
|
+
* security posture (SSRF guard, timeout, byte cap, address-free errors). Shared
|
|
129
|
+
* core of `hostGet`/`hostPost`. Throws a `HostControlError` on any failure.
|
|
130
|
+
*/
|
|
131
|
+
async function hostRequest(url, init, opts) {
|
|
132
|
+
// TEL-5: validate the operator-supplied URL before any network call -- reject
|
|
133
|
+
// anything that isn't a parseable http/https URL (no file:, ftp:, etc).
|
|
134
|
+
if (!isAllowedDiscoveryUrl(url)) {
|
|
135
|
+
throw new HostControlError(`Rejected non-http(s) host-control URL: ${url}`, HOST_CONTROL_ERROR_REJECTED_URL);
|
|
136
|
+
}
|
|
137
|
+
const timeoutMs = opts.timeoutMs ?? HOST_CONTROL_FETCH_TIMEOUT_MS;
|
|
138
|
+
const controller = new AbortController();
|
|
139
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
140
|
+
try {
|
|
141
|
+
const extra = init.method === 'POST' && init.contentType ? { 'content-type': init.contentType } : undefined;
|
|
142
|
+
const res = await fetch(url, {
|
|
143
|
+
method: init.method,
|
|
144
|
+
signal: controller.signal,
|
|
145
|
+
headers: buildHostHeaders(opts.apiKey, extra),
|
|
146
|
+
...(init.body !== undefined ? { body: init.body } : {}),
|
|
147
|
+
});
|
|
148
|
+
if (!res.ok) {
|
|
149
|
+
throw new HostControlError(`Host returned HTTP ${res.status}`, statusDbMessage(res.status));
|
|
150
|
+
}
|
|
151
|
+
// TEL-6: reject a too-large declared body up front, then defensively cap the
|
|
152
|
+
// actual stream in case the header lied / is absent.
|
|
153
|
+
const declared = Number(res.headers.get('content-length'));
|
|
154
|
+
if (Number.isFinite(declared) && declared > HOST_CONTROL_MAX_BYTES) {
|
|
155
|
+
throw new HostControlError(`Declared Content-Length ${declared} exceeds cap`, HOST_CONTROL_ERROR_INVALID);
|
|
156
|
+
}
|
|
157
|
+
const text = await readBodyCapped(res);
|
|
158
|
+
try {
|
|
159
|
+
return JSON.parse(text);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
throw new HostControlError('Response body was not valid JSON', HOST_CONTROL_ERROR_INVALID);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
if (err instanceof HostControlError)
|
|
167
|
+
throw err;
|
|
168
|
+
if (err.name === 'AbortError') {
|
|
169
|
+
throw new HostControlError(`Timed out after ${timeoutMs}ms reaching ${url}`, HOST_CONTROL_ERROR_UNREACHABLE);
|
|
170
|
+
}
|
|
171
|
+
// Network-level failure (DNS, connection refused, TLS): generic to callers.
|
|
172
|
+
throw new HostControlError(err.message || `Failed to reach ${url}`, HOST_CONTROL_ERROR_UNREACHABLE);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
clearTimeout(timer);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Typed JSON GET against a host-control URL. See `hostRequest` for the posture. */
|
|
179
|
+
export async function hostGet(url, opts = {}) {
|
|
180
|
+
return hostRequest(url, { method: 'GET' }, opts);
|
|
181
|
+
}
|
|
182
|
+
/** Typed JSON POST against a host-control URL. The body is JSON-encoded. */
|
|
183
|
+
export async function hostPost(url, body, opts = {}) {
|
|
184
|
+
return hostRequest(url, { method: 'POST', body: JSON.stringify(body ?? {}), contentType: 'application/json' }, opts);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Derive the host ROOT from a stored `baseUrl`. The registry stores the
|
|
188
|
+
* OpenAI-compatible base (e.g. `http://host:8888/v1`), but the control surface
|
|
189
|
+
* lives under `/api` at the host root, NOT under `/v1`. Strip a single trailing
|
|
190
|
+
* `/v1` segment and any trailing slashes so callers can append `/api/...`. A
|
|
191
|
+
* `baseUrl` that is already a bare root passes through unchanged.
|
|
192
|
+
*
|
|
193
|
+
* Pure + exported for unit testing.
|
|
194
|
+
*/
|
|
195
|
+
export function hostRootFromBaseUrl(baseUrl) {
|
|
196
|
+
// Trim trailing slashes first so a trailing-slash `/v1/` still matches.
|
|
197
|
+
const trimmed = baseUrl.replace(/\/+$/, '');
|
|
198
|
+
// Strip exactly one trailing `/v1` segment (case-sensitive, the API convention).
|
|
199
|
+
const root = trimmed.replace(/\/v1$/, '');
|
|
200
|
+
// A `/v1` with its own trailing slash (`/v1/`) leaves a dangling slash; clean it.
|
|
201
|
+
return root.replace(/\/+$/, '');
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/host-control/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-control plane barrel (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* The spine for detecting and reading a controllable model host ABOVE the
|
|
5
|
+
* OpenAI-compatible `/v1/models` floor. Delivery 1 ships the client, capability
|
|
6
|
+
* detection, and catalog read; later deliveries add `load.ts` (id -> model_path
|
|
7
|
+
* load/unload) and `sizing.ts` -- export those from here when they land.
|
|
8
|
+
*/
|
|
9
|
+
export type { HostCapability, LoadableCatalog, LoadableModel, HostStatus, LoadModelParams, SwapAction, SwapDecision, HostHardware, KvCacheEstimate, KvCacheEstimateParams, SafeMaxSeqInput, SafeMaxSeqResult, } from './types.js';
|
|
10
|
+
export { hostGet, hostPost, hostRootFromBaseUrl, HostControlError, HOST_CONTROL_FETCH_TIMEOUT_MS, HOST_CONTROL_MAX_BYTES, HOST_CONTROL_ERROR_REJECTED_URL, HOST_CONTROL_ERROR_STATUS, HOST_CONTROL_ERROR_UNREACHABLE, HOST_CONTROL_ERROR_INVALID, } from './client.js';
|
|
11
|
+
export type { HostRequestOptions } from './client.js';
|
|
12
|
+
export { detectHostCapability, isControllableCatalogPayload } from './capability.js';
|
|
13
|
+
export { readLoadableCatalog, normalizeLocalCatalog, HOST_CONTROL_CATALOG_PATH, } from './catalog.js';
|
|
14
|
+
export { loadModel, unloadModel, getStatus, resolveModelPath, decideSwap, ensureLoaded, normalizeStatus, DEFAULT_MAX_SEQ_LENGTH, HOST_CONTROL_LOAD_PATH, HOST_CONTROL_UNLOAD_PATH, HOST_CONTROL_STATUS_PATH, HOST_CONTROL_LOAD_READY_TIMEOUT_MS, HOST_CONTROL_LOAD_POLL_INTERVAL_MS, HOST_CONTROL_ERROR_LOAD_TIMEOUT, } from './load.js';
|
|
15
|
+
export type { EnsureLoadedOptions } from './load.js';
|
|
16
|
+
export { getHardware, getKvCacheEstimate, normalizeHardware, normalizeKvCacheEstimate, computeSafeMaxSeqLength, resolveSafeLoadOptions, CODEX_TURN1_FLOOR, VRAM_SAFETY_MARGIN_MB, KV_CACHE_MB_PER_TOKEN, KV_QUANT_FOOTPRINT_FACTOR, KV_QUANT_CACHE_TYPE, MAX_SEQ_LENGTH_CEILING, HOST_CONTROL_HARDWARE_PATH, HOST_CONTROL_KV_CACHE_PATH, } from './sizing.js';
|
|
17
|
+
export type { SafeLoadSizingHints } from './sizing.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host-control/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACV,cAAc,EACd,eAAe,EACf,aAAa,EACb,UAAU,EACV,eAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,OAAO,EACP,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,+BAA+B,EAC/B,yBAAyB,EACzB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAErF,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,SAAS,EACT,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,kCAAkC,EAClC,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-control plane barrel (Local model host control, D1).
|
|
3
|
+
*
|
|
4
|
+
* The spine for detecting and reading a controllable model host ABOVE the
|
|
5
|
+
* OpenAI-compatible `/v1/models` floor. Delivery 1 ships the client, capability
|
|
6
|
+
* detection, and catalog read; later deliveries add `load.ts` (id -> model_path
|
|
7
|
+
* load/unload) and `sizing.ts` -- export those from here when they land.
|
|
8
|
+
*/
|
|
9
|
+
export { hostGet, hostPost, hostRootFromBaseUrl, HostControlError, HOST_CONTROL_FETCH_TIMEOUT_MS, HOST_CONTROL_MAX_BYTES, HOST_CONTROL_ERROR_REJECTED_URL, HOST_CONTROL_ERROR_STATUS, HOST_CONTROL_ERROR_UNREACHABLE, HOST_CONTROL_ERROR_INVALID, } from './client.js';
|
|
10
|
+
export { detectHostCapability, isControllableCatalogPayload } from './capability.js';
|
|
11
|
+
export { readLoadableCatalog, normalizeLocalCatalog, HOST_CONTROL_CATALOG_PATH, } from './catalog.js';
|
|
12
|
+
export { loadModel, unloadModel, getStatus, resolveModelPath, decideSwap, ensureLoaded, normalizeStatus, DEFAULT_MAX_SEQ_LENGTH, HOST_CONTROL_LOAD_PATH, HOST_CONTROL_UNLOAD_PATH, HOST_CONTROL_STATUS_PATH, HOST_CONTROL_LOAD_READY_TIMEOUT_MS, HOST_CONTROL_LOAD_POLL_INTERVAL_MS, HOST_CONTROL_ERROR_LOAD_TIMEOUT, } from './load.js';
|
|
13
|
+
export { getHardware, getKvCacheEstimate, normalizeHardware, normalizeKvCacheEstimate, computeSafeMaxSeqLength, resolveSafeLoadOptions, CODEX_TURN1_FLOOR, VRAM_SAFETY_MARGIN_MB, KV_CACHE_MB_PER_TOKEN, KV_QUANT_FOOTPRINT_FACTOR, KV_QUANT_CACHE_TYPE, MAX_SEQ_LENGTH_CEILING, HOST_CONTROL_HARDWARE_PATH, HOST_CONTROL_KV_CACHE_PATH, } from './sizing.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/host-control/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiBH,OAAO,EACL,OAAO,EACP,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,+BAA+B,EAC/B,yBAAyB,EACzB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAErF,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,SAAS,EACT,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,kCAAkC,EAClC,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,aAAa,CAAC"}
|