@stigmer/react 0.4.5 → 0.4.6
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/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/models/ModelRegistryContext.d.ts +21 -0
- package/models/ModelRegistryContext.d.ts.map +1 -0
- package/models/ModelRegistryContext.js +22 -0
- package/models/ModelRegistryContext.js.map +1 -0
- package/models/ModelSelector.js +3 -3
- package/models/ModelSelector.js.map +1 -1
- package/models/__tests__/useModelRegistry.test.js +127 -32
- package/models/__tests__/useModelRegistry.test.js.map +1 -1
- package/models/index.d.ts +3 -1
- package/models/index.d.ts.map +1 -1
- package/models/index.js +2 -1
- package/models/index.js.map +1 -1
- package/models/registry.d.ts +20 -12
- package/models/registry.d.ts.map +1 -1
- package/models/registry.js +51 -27
- package/models/registry.js.map +1 -1
- package/models/useModelRegistry.d.ts +11 -3
- package/models/useModelRegistry.d.ts.map +1 -1
- package/models/useModelRegistry.js +13 -5
- package/models/useModelRegistry.js.map +1 -1
- package/package.json +4 -4
- package/provider.d.ts.map +1 -1
- package/provider.js +42 -1
- package/provider.js.map +1 -1
- package/session/__tests__/useNewSessionFlow.test.js +32 -18
- package/session/__tests__/useNewSessionFlow.test.js.map +1 -1
- package/session/__tests__/usePersistedModel.test.js +26 -12
- package/session/__tests__/usePersistedModel.test.js.map +1 -1
- package/src/index.ts +4 -1
- package/src/models/ModelRegistryContext.ts +32 -0
- package/src/models/ModelSelector.tsx +4 -4
- package/src/models/__tests__/useModelRegistry.test.tsx +150 -41
- package/src/models/index.ts +3 -1
- package/src/models/registry.ts +51 -30
- package/src/models/useModelRegistry.ts +18 -7
- package/src/provider.tsx +58 -8
- package/src/session/__tests__/useNewSessionFlow.test.tsx +39 -18
- package/src/session/__tests__/usePersistedModel.test.tsx +33 -12
package/models/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,aAAa,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGlL,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/models/registry.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model registry — UI-relevant metadata for all platform-supported LLM models.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Fetches from the public model registry API endpoint at runtime and caches
|
|
5
|
+
* the result in the {@link StigmerProvider} context. This eliminates the
|
|
6
|
+
* static JSON file that previously shipped in the npm package.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Platform consumers (React SDK, cursor-runner, graphton) all fetch from the
|
|
9
|
+
* same endpoint, each with their own local TTL cache.
|
|
9
10
|
*/
|
|
10
11
|
import type { HarnessOption } from "./harness";
|
|
11
12
|
/**
|
|
@@ -28,14 +29,14 @@ export type SpeedTier = "fastest" | "fast" | "balanced" | "slow";
|
|
|
28
29
|
/**
|
|
29
30
|
* LLM provider identifier. Each provider maps to a distinct inference
|
|
30
31
|
* backend (or intermediary, in the case of Cursor-served third-party
|
|
31
|
-
* models). The
|
|
32
|
+
* models). The model registry uses this for grouping in the
|
|
32
33
|
* "Show All" expanded view.
|
|
33
34
|
*/
|
|
34
35
|
export type Provider = "anthropic" | "openai" | "google" | "xai" | "cursor" | "moonshot" | "ollama";
|
|
35
36
|
/**
|
|
36
37
|
* Providers whose models should be hidden from the UI.
|
|
37
38
|
*
|
|
38
|
-
* The model entries themselves stay in
|
|
39
|
+
* The model entries themselves stay in the registry so backend
|
|
39
40
|
* compatibility is preserved. The useModelRegistry hook filters
|
|
40
41
|
* them out before anything reaches a component.
|
|
41
42
|
*
|
|
@@ -106,13 +107,20 @@ export interface ParsedModelKey {
|
|
|
106
107
|
*/
|
|
107
108
|
export declare function parseModelKey(key: string): ParsedModelKey | undefined;
|
|
108
109
|
/**
|
|
109
|
-
*
|
|
110
|
-
* unified JSON registry.
|
|
110
|
+
* Parse raw registry JSON (from the API or a static file) into `ModelInfo[]`.
|
|
111
111
|
*
|
|
112
|
-
* {
|
|
113
|
-
*
|
|
112
|
+
* Expects the shape `{ models: RegistryJsonEntry[] }`. Filters out comment
|
|
113
|
+
* entries and invalid rows, then maps to the `ModelInfo` interface.
|
|
114
114
|
*/
|
|
115
|
-
export declare
|
|
115
|
+
export declare function parseRegistryJson(data: unknown): ModelInfo[];
|
|
116
|
+
/**
|
|
117
|
+
* Fetch the model registry from the authenticated API endpoint.
|
|
118
|
+
*
|
|
119
|
+
* @param apiUrl - Base URL of the Stigmer Cloud API (e.g. `https://api.stigmer.ai`)
|
|
120
|
+
* @param token - Bearer token for authentication (from `client.getAuthCredential()`)
|
|
121
|
+
* @returns Parsed `ModelInfo[]`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function fetchModelRegistry(apiUrl: string, token: string | null): Promise<ModelInfo[]>;
|
|
116
124
|
/**
|
|
117
125
|
* Model ID used when no user preference is set (native harness).
|
|
118
126
|
*
|
|
@@ -146,7 +154,7 @@ export interface DefaultModelResolution {
|
|
|
146
154
|
* Future phases will add org-level and agent-level defaults between
|
|
147
155
|
* user preference and harness default.
|
|
148
156
|
*/
|
|
149
|
-
export declare function resolveDefaultModelId(harness: HarnessOption, options?: {
|
|
157
|
+
export declare function resolveDefaultModelId(harness: HarnessOption, models: readonly ModelInfo[], options?: {
|
|
150
158
|
userPreference?: string;
|
|
151
159
|
orgDefault?: string;
|
|
152
160
|
agentDefault?: string;
|
package/models/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"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"}
|
package/models/registry.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model registry — UI-relevant metadata for all platform-supported LLM models.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Fetches from the public model registry API endpoint at runtime and caches
|
|
5
|
+
* the result in the {@link StigmerProvider} context. This eliminates the
|
|
6
|
+
* static JSON file that previously shipped in the npm package.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Platform consumers (React SDK, cursor-runner, graphton) all fetch from the
|
|
9
|
+
* same endpoint, each with their own local TTL cache.
|
|
9
10
|
*/
|
|
10
|
-
import registryData from "../../data/model-registry.json";
|
|
11
11
|
/**
|
|
12
12
|
* Providers whose models should be hidden from the UI.
|
|
13
13
|
*
|
|
14
|
-
* The model entries themselves stay in
|
|
14
|
+
* The model entries themselves stay in the registry so backend
|
|
15
15
|
* compatibility is preserved. The useModelRegistry hook filters
|
|
16
16
|
* them out before anything reaches a component.
|
|
17
17
|
*
|
|
@@ -53,24 +53,48 @@ function isModelEntry(entry) {
|
|
|
53
53
|
typeof entry.costTier === "string" && VALID_COST_TIERS.has(entry.costTier));
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
57
|
-
* unified JSON registry.
|
|
56
|
+
* Parse raw registry JSON (from the API or a static file) into `ModelInfo[]`.
|
|
58
57
|
*
|
|
59
|
-
* {
|
|
60
|
-
*
|
|
58
|
+
* Expects the shape `{ models: RegistryJsonEntry[] }`. Filters out comment
|
|
59
|
+
* entries and invalid rows, then maps to the `ModelInfo` interface.
|
|
61
60
|
*/
|
|
62
|
-
export
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
export function parseRegistryJson(data) {
|
|
62
|
+
if (!data || typeof data !== "object")
|
|
63
|
+
return [];
|
|
64
|
+
const models = data.models;
|
|
65
|
+
if (!Array.isArray(models))
|
|
66
|
+
return [];
|
|
67
|
+
return models
|
|
68
|
+
.filter(isModelEntry)
|
|
69
|
+
.map((m) => ({
|
|
70
|
+
modelId: m.id,
|
|
71
|
+
provider: m.provider,
|
|
72
|
+
displayName: m.displayName,
|
|
73
|
+
shortDescription: m.shortDescription ?? "",
|
|
74
|
+
speedTier: (VALID_SPEED_TIERS.has(m.speedTier ?? "") ? m.speedTier : "fast"),
|
|
75
|
+
costTier: m.costTier,
|
|
76
|
+
harness: m.harness,
|
|
77
|
+
featured: m.featured ?? false,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Fetch the model registry from the authenticated API endpoint.
|
|
82
|
+
*
|
|
83
|
+
* @param apiUrl - Base URL of the Stigmer Cloud API (e.g. `https://api.stigmer.ai`)
|
|
84
|
+
* @param token - Bearer token for authentication (from `client.getAuthCredential()`)
|
|
85
|
+
* @returns Parsed `ModelInfo[]`.
|
|
86
|
+
*/
|
|
87
|
+
export async function fetchModelRegistry(apiUrl, token) {
|
|
88
|
+
const headers = {};
|
|
89
|
+
if (token) {
|
|
90
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
91
|
+
}
|
|
92
|
+
const res = await fetch(`${apiUrl}/v1/proxy/model-registry`, { headers });
|
|
93
|
+
if (!res.ok)
|
|
94
|
+
throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
95
|
+
const data = await res.json();
|
|
96
|
+
return parseRegistryJson(data);
|
|
97
|
+
}
|
|
74
98
|
/**
|
|
75
99
|
* Model ID used when no user preference is set (native harness).
|
|
76
100
|
*
|
|
@@ -92,23 +116,23 @@ export const DEFAULT_CURSOR_MODEL_ID = "default";
|
|
|
92
116
|
* Future phases will add org-level and agent-level defaults between
|
|
93
117
|
* user preference and harness default.
|
|
94
118
|
*/
|
|
95
|
-
export function resolveDefaultModelId(harness, options) {
|
|
119
|
+
export function resolveDefaultModelId(harness, models, options) {
|
|
96
120
|
if (options?.userPreference) {
|
|
97
|
-
const model =
|
|
121
|
+
const model = models.find((m) => m.harness === harness && m.modelId === options.userPreference);
|
|
98
122
|
if (model)
|
|
99
123
|
return { modelId: model.modelId, source: "user_preference" };
|
|
100
124
|
}
|
|
101
125
|
if (options?.orgDefault) {
|
|
102
|
-
const model =
|
|
126
|
+
const model = models.find((m) => m.harness === harness && m.modelId === options.orgDefault);
|
|
103
127
|
if (model)
|
|
104
128
|
return { modelId: model.modelId, source: "org_default" };
|
|
105
129
|
}
|
|
106
130
|
if (options?.agentDefault) {
|
|
107
|
-
const model =
|
|
131
|
+
const model = models.find((m) => m.harness === harness && m.modelId === options.agentDefault);
|
|
108
132
|
if (model)
|
|
109
133
|
return { modelId: model.modelId, source: "agent_default" };
|
|
110
134
|
}
|
|
111
|
-
const featured =
|
|
135
|
+
const featured = models.find((m) => m.harness === harness && m.featured);
|
|
112
136
|
if (featured)
|
|
113
137
|
return { modelId: featured.modelId, source: "harness_default" };
|
|
114
138
|
const fallbackId = harness === "cursor" ? DEFAULT_CURSOR_MODEL_ID : DEFAULT_MODEL_ID;
|
package/models/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsCH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA0B,IAAI,GAAG,CAAC;IAC/D,QAAQ;CACT,CAAC,CAAC;AAgDH;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAsB,EAAE,OAAe;IAC9D,OAAO,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;AACjC,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClC,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACnE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;AAClD,CAAC;AAwBD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AACrE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAC3E,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAElG,SAAS,YAAY,CAAC,KAAwB;IAC5C,OAAO,CACL,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;QAC5B,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACrC,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAClC,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;QACvE,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,MAAM,GAAI,IAAgC,CAAC,MAAM,CAAC;IACxD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,OAAQ,MAA8B;SACnC,MAAM,CAAC,YAAY,CAAC;SACpB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,OAAO,EAAE,CAAC,CAAC,EAAE;QACb,QAAQ,EAAE,CAAC,CAAC,QAAoB;QAChC,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,IAAI,EAAE;QAC1C,SAAS,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAc;QACzF,QAAQ,EAAE,CAAC,CAAC,QAAoB;QAChC,OAAO,EAAE,CAAC,CAAC,OAAwB;QACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;KAC9B,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,KAAoB;IAC3E,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;IAC/C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,0BAA0B,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAY,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IACvC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAEpD,uFAAuF;AACvF,MAAM,CAAC,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAqBjD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAsB,EACtB,MAA4B,EAC5B,OAIC;IAED,IAAI,OAAO,EAAE,cAAc,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,cAAc,CACrE,CAAC;QACF,IAAI,KAAK;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,UAAU,CACjE,CAAC;QACF,IAAI,KAAK;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACtE,CAAC;IAED,IAAI,OAAO,EAAE,YAAY,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,YAAY,CACnE,CAAC;QACF,IAAI,KAAK;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,QAAQ,CAC3C,CAAC;IACF,IAAI,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAE9E,MAAM,UAAU,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACrF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -17,8 +17,8 @@ export interface UseModelRegistryReturn {
|
|
|
17
17
|
readonly models: readonly ModelInfo[];
|
|
18
18
|
/** Models grouped by provider for sectioned rendering. */
|
|
19
19
|
readonly byProvider: ReadonlyMap<Provider, readonly ModelInfo[]>;
|
|
20
|
-
/** The platform default model for the current mode. */
|
|
21
|
-
readonly defaultModel: ModelInfo;
|
|
20
|
+
/** The platform default model for the current mode. `undefined` while the registry is loading. */
|
|
21
|
+
readonly defaultModel: ModelInfo | undefined;
|
|
22
22
|
/**
|
|
23
23
|
* Look up a single model by its `modelId`.
|
|
24
24
|
*
|
|
@@ -37,6 +37,10 @@ export interface UseModelRegistryReturn {
|
|
|
37
37
|
* Always unambiguous, even in unified mode.
|
|
38
38
|
*/
|
|
39
39
|
readonly getByKey: (key: string) => ModelInfo | undefined;
|
|
40
|
+
/** `true` while the model registry is being fetched from the API. */
|
|
41
|
+
readonly isLoading: boolean;
|
|
42
|
+
/** Non-null if the API fetch failed. Models will be empty in this case. */
|
|
43
|
+
readonly error: Error | null;
|
|
40
44
|
}
|
|
41
45
|
/**
|
|
42
46
|
* Data hook that exposes the platform model registry with grouping
|
|
@@ -46,6 +50,10 @@ export interface UseModelRegistryReturn {
|
|
|
46
50
|
* who want full control over rendering import this hook and build
|
|
47
51
|
* their own UI.
|
|
48
52
|
*
|
|
53
|
+
* The model data is fetched from the public model registry API by
|
|
54
|
+
* {@link StigmerProvider} and cached in context. During loading,
|
|
55
|
+
* `isLoading` is `true` and `models` is empty.
|
|
56
|
+
*
|
|
49
57
|
* **Modes:**
|
|
50
58
|
* - `options.harness === "cursor"` — Cursor-harness models only
|
|
51
59
|
* - `options.harness === "native"` — native models, excluding disabled providers
|
|
@@ -54,7 +62,7 @@ export interface UseModelRegistryReturn {
|
|
|
54
62
|
* @example
|
|
55
63
|
* ```tsx
|
|
56
64
|
* // Unified mode — flat picker with all models
|
|
57
|
-
* const { featured, models, getByKey } = useModelRegistry();
|
|
65
|
+
* const { featured, models, getByKey, isLoading } = useModelRegistry();
|
|
58
66
|
*
|
|
59
67
|
* // Legacy single-harness mode
|
|
60
68
|
* const { models, defaultModel } = useModelRegistry({ harness: "native" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModelRegistry.d.ts","sourceRoot":"","sources":["../../src/models/useModelRegistry.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"useModelRegistry.d.ts","sourceRoot":"","sources":["../../src/models/useModelRegistry.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;CAClC;AAED,gDAAgD;AAChD,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC,CAAC;IACjE,kGAAkG;IAClG,QAAQ,CAAC,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7C;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,CAAC;IAC9D,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,CAAC;IAC1D,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CA8D1F"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_MODEL_ID, DISABLED_PROVIDERS, resolveDefaultModelId, modelKey, } from "./registry";
|
|
4
|
+
import { useModelRegistryContext } from "./ModelRegistryContext";
|
|
4
5
|
/**
|
|
5
6
|
* Data hook that exposes the platform model registry with grouping
|
|
6
7
|
* and lookup helpers.
|
|
@@ -9,6 +10,10 @@ import { MODEL_REGISTRY, DEFAULT_MODEL_ID, DISABLED_PROVIDERS, resolveDefaultMod
|
|
|
9
10
|
* who want full control over rendering import this hook and build
|
|
10
11
|
* their own UI.
|
|
11
12
|
*
|
|
13
|
+
* The model data is fetched from the public model registry API by
|
|
14
|
+
* {@link StigmerProvider} and cached in context. During loading,
|
|
15
|
+
* `isLoading` is `true` and `models` is empty.
|
|
16
|
+
*
|
|
12
17
|
* **Modes:**
|
|
13
18
|
* - `options.harness === "cursor"` — Cursor-harness models only
|
|
14
19
|
* - `options.harness === "native"` — native models, excluding disabled providers
|
|
@@ -17,7 +22,7 @@ import { MODEL_REGISTRY, DEFAULT_MODEL_ID, DISABLED_PROVIDERS, resolveDefaultMod
|
|
|
17
22
|
* @example
|
|
18
23
|
* ```tsx
|
|
19
24
|
* // Unified mode — flat picker with all models
|
|
20
|
-
* const { featured, models, getByKey } = useModelRegistry();
|
|
25
|
+
* const { featured, models, getByKey, isLoading } = useModelRegistry();
|
|
21
26
|
*
|
|
22
27
|
* // Legacy single-harness mode
|
|
23
28
|
* const { models, defaultModel } = useModelRegistry({ harness: "native" });
|
|
@@ -25,10 +30,11 @@ import { MODEL_REGISTRY, DEFAULT_MODEL_ID, DISABLED_PROVIDERS, resolveDefaultMod
|
|
|
25
30
|
*/
|
|
26
31
|
export function useModelRegistry(options) {
|
|
27
32
|
const harness = options?.harness;
|
|
33
|
+
const { models: allModels, isLoading, error } = useModelRegistryContext();
|
|
28
34
|
return useMemo(() => {
|
|
29
35
|
const isUnified = harness === undefined;
|
|
30
36
|
const { modelId: defaultId } = harness
|
|
31
|
-
? resolveDefaultModelId(harness)
|
|
37
|
+
? resolveDefaultModelId(harness, allModels)
|
|
32
38
|
: { modelId: DEFAULT_MODEL_ID };
|
|
33
39
|
const byProvider = new Map();
|
|
34
40
|
const byId = new Map();
|
|
@@ -36,7 +42,7 @@ export function useModelRegistry(options) {
|
|
|
36
42
|
const enabledModels = [];
|
|
37
43
|
const featuredModels = [];
|
|
38
44
|
let defaultModel;
|
|
39
|
-
for (const model of
|
|
45
|
+
for (const model of allModels) {
|
|
40
46
|
if (isUnified) {
|
|
41
47
|
if (DISABLED_PROVIDERS.has(model.provider))
|
|
42
48
|
continue;
|
|
@@ -75,7 +81,9 @@ export function useModelRegistry(options) {
|
|
|
75
81
|
providers,
|
|
76
82
|
featured: featuredModels,
|
|
77
83
|
getByKey: (key) => byCompoundKey.get(key),
|
|
84
|
+
isLoading,
|
|
85
|
+
error,
|
|
78
86
|
};
|
|
79
|
-
}, [harness]);
|
|
87
|
+
}, [harness, allModels, isLoading, error]);
|
|
80
88
|
}
|
|
81
89
|
//# sourceMappingURL=useModelRegistry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModelRegistry.js","sourceRoot":"","sources":["../../src/models/useModelRegistry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"useModelRegistry.js","sourceRoot":"","sources":["../../src/models/useModelRegistry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EACL,gBAAgB,EAEhB,kBAAkB,EAClB,qBAAqB,EACrB,QAAQ,GAGT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AA8CjE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAiC;IAChE,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;IACjC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,uBAAuB,EAAE,CAAC;IAE1E,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,SAAS,GAAG,OAAO,KAAK,SAAS,CAAC;QACxC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO;YACpC,CAAC,CAAC,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC;YAC3C,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;QAElC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyB,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC1C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAqB,CAAC;QACnD,MAAM,aAAa,GAAgB,EAAE,CAAC;QACtC,MAAM,cAAc,GAAgB,EAAE,CAAC;QACvC,IAAI,YAAmC,CAAC;QAExC,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;oBAAE,SAAS;YACvD,CAAC;iBAAM,CAAC;gBACN,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO;oBAAE,SAAS;gBACxC,IAAI,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;oBAAE,SAAS;YACvD,CAAC;YAED,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;YAEjE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACjC,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAChC,YAAY,KAAK,KAAK,CAAC;YACzB,CAAC;YAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QAEhD,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,UAAU,EAAE,UAAyD;YACrE,YAAY,EAAE,YAAY,IAAI,aAAa,CAAC,CAAC,CAAC;YAC9C,QAAQ,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAChD,SAAS;YACT,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC;YACjD,SAAS;YACT,KAAK;SACN,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AAC7C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/react",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "React provider and client hook for the Stigmer platform SDK",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@stigmer/theme": "0.4.
|
|
38
|
+
"@stigmer/theme": "0.4.6",
|
|
39
39
|
"react-markdown": "^10.1.0",
|
|
40
40
|
"remark-gfm": "^4.0.1",
|
|
41
41
|
"streamdown": "^2.5.0",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@base-ui/react": "^1.0.0",
|
|
46
46
|
"@bufbuild/protobuf": "^2.0.0",
|
|
47
|
-
"@stigmer/protos": "0.4.
|
|
48
|
-
"@stigmer/sdk": "0.4.
|
|
47
|
+
"@stigmer/protos": "0.4.6",
|
|
48
|
+
"@stigmer/sdk": "0.4.6",
|
|
49
49
|
"lucide-react": ">=0.400.0",
|
|
50
50
|
"react": "^19.0.0",
|
|
51
51
|
"react-dom": "^19.0.0",
|
package/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAqB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAqB,MAAM,cAAc,CAAC;AAOjE,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,QAAQ,EACR,cAAwB,EACxB,MAAM,EACN,SAAS,EACT,SAAmB,GACpB,EAAE,oBAAoB,2CA4BtB"}
|
package/provider.js
CHANGED
|
@@ -6,6 +6,8 @@ import { StigmerContext } from "./context";
|
|
|
6
6
|
import { DeploymentModeContext } from "./deployment-mode";
|
|
7
7
|
import { ColorModeContext, useSystemColorMode } from "./color-mode";
|
|
8
8
|
import { PortalContainerContext } from "./portal-container";
|
|
9
|
+
import { ModelRegistryContext } from "./models/ModelRegistryContext";
|
|
10
|
+
import { fetchModelRegistry } from "./models/registry";
|
|
9
11
|
/**
|
|
10
12
|
* React provider that distributes a {@link Stigmer} SDK client to
|
|
11
13
|
* descendant components via {@link StigmerContext}.
|
|
@@ -41,7 +43,46 @@ export function StigmerProvider({ client, children, deploymentMode = "cloud", pr
|
|
|
41
43
|
const resolvedMode = colorMode === "system" ? systemMode : colorMode;
|
|
42
44
|
const presetClass = preset ? resolvePresetClass(preset) : "";
|
|
43
45
|
const portalContainer = usePortalContainer(resolvedMode, presetClass);
|
|
44
|
-
|
|
46
|
+
const registryState = useModelRegistryFetch(client);
|
|
47
|
+
return (_jsx(StigmerContext.Provider, { value: client, children: _jsx(DeploymentModeContext.Provider, { value: deploymentMode, children: _jsx(ColorModeContext.Provider, { value: resolvedMode, children: _jsx(ModelRegistryContext.Provider, { value: registryState, children: _jsx(PortalContainerContext.Provider, { value: portalContainer, children: _jsx("div", { className: cn("stgm", presetClass, className), "data-stgm-color-mode": resolvedMode, children: children }) }) }) }) }) }));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetches the model registry from the authenticated API on mount and
|
|
51
|
+
* caches the result for the lifetime of the provider.
|
|
52
|
+
*
|
|
53
|
+
* Uses the client's `baseUrl` and `getAuthCredential()` so the fetch
|
|
54
|
+
* is authenticated with the same token the SDK uses for all other calls.
|
|
55
|
+
*/
|
|
56
|
+
function useModelRegistryFetch(client) {
|
|
57
|
+
const [state, setState] = useState({
|
|
58
|
+
models: [],
|
|
59
|
+
isLoading: true,
|
|
60
|
+
error: null,
|
|
61
|
+
});
|
|
62
|
+
const clientRef = useRef(client);
|
|
63
|
+
clientRef.current = client;
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
let cancelled = false;
|
|
66
|
+
const c = clientRef.current;
|
|
67
|
+
c.getAuthCredential()
|
|
68
|
+
.then((token) => fetchModelRegistry(c.baseUrl, token))
|
|
69
|
+
.then((models) => {
|
|
70
|
+
if (!cancelled) {
|
|
71
|
+
setState({ models, isLoading: false, error: null });
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.catch((err) => {
|
|
75
|
+
if (!cancelled) {
|
|
76
|
+
setState({
|
|
77
|
+
models: [],
|
|
78
|
+
isLoading: false,
|
|
79
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return () => { cancelled = true; };
|
|
84
|
+
}, []);
|
|
85
|
+
return state;
|
|
45
86
|
}
|
|
46
87
|
/**
|
|
47
88
|
* Creates and manages a portal container `<div>` appended to
|
package/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAEpE,OAAO,EAAE,EAAE,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
3
|
import { renderHook, act } from "@testing-library/react";
|
|
3
|
-
import { DEFAULT_MODEL_ID, DEFAULT_CURSOR_MODEL_ID } from "../../models/registry";
|
|
4
|
+
import { DEFAULT_MODEL_ID, DEFAULT_CURSOR_MODEL_ID, parseRegistryJson } from "../../models/registry";
|
|
5
|
+
import { ModelRegistryContext } from "../../models/ModelRegistryContext";
|
|
4
6
|
const mockCreateSession = vi.fn();
|
|
5
7
|
vi.mock("../useCreateSession", () => ({
|
|
6
8
|
useCreateSession: () => ({
|
|
@@ -52,6 +54,18 @@ vi.mock("../../execution/useSessionVariables", () => ({
|
|
|
52
54
|
useSessionVariables: () => mockSessionVariables,
|
|
53
55
|
}));
|
|
54
56
|
import { useNewSessionFlow } from "../useNewSessionFlow";
|
|
57
|
+
const TEST_MODELS = parseRegistryJson({
|
|
58
|
+
models: [
|
|
59
|
+
{ id: "claude-sonnet-4.6", displayName: "Claude Sonnet 4.6", shortDescription: "", speedTier: "fast", provider: "anthropic", harness: "native", costTier: "standard", featured: true, pricing: { inputPricePerMillion: 3, outputPricePerMillion: 15, cacheWritePricePerMillion: 3.75, cacheReadPricePerMillion: 0.3 } },
|
|
60
|
+
{ id: "default", displayName: "Cursor Auto", shortDescription: "", speedTier: "fast", provider: "cursor", harness: "cursor", costTier: "standard", featured: true, pricing: { inputPricePerMillion: 1.25, outputPricePerMillion: 6, cacheWritePricePerMillion: 1.25, cacheReadPricePerMillion: 0.25 } },
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
function createWrapper() {
|
|
64
|
+
const state = { models: TEST_MODELS, isLoading: false, error: null };
|
|
65
|
+
return function Wrapper({ children }) {
|
|
66
|
+
return (_jsx(ModelRegistryContext.Provider, { value: state, children: children }));
|
|
67
|
+
};
|
|
68
|
+
}
|
|
55
69
|
const STORAGE_KEY_HARNESS = "stigmer:session:harness";
|
|
56
70
|
const STORAGE_KEY_MODEL_NATIVE = "stigmer:session:model";
|
|
57
71
|
const STORAGE_KEY_MODEL_CURSOR = "stigmer:session:model:cursor";
|
|
@@ -79,53 +93,53 @@ describe("useNewSessionFlow", () => {
|
|
|
79
93
|
});
|
|
80
94
|
describe("harness state", () => {
|
|
81
95
|
it("defaults to native when localStorage is empty", () => {
|
|
82
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
96
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
83
97
|
expect(result.current.harness).toBe("native");
|
|
84
98
|
});
|
|
85
99
|
it("restores cursor harness from localStorage", () => {
|
|
86
100
|
localStorage.setItem(STORAGE_KEY_HARNESS, "cursor");
|
|
87
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
101
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
88
102
|
expect(result.current.harness).toBe("cursor");
|
|
89
103
|
});
|
|
90
104
|
it("falls back to native for unknown localStorage values", () => {
|
|
91
105
|
localStorage.setItem(STORAGE_KEY_HARNESS, "unknown-value");
|
|
92
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
106
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
93
107
|
expect(result.current.harness).toBe("native");
|
|
94
108
|
});
|
|
95
109
|
it("persists harness to localStorage on change", () => {
|
|
96
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
110
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
97
111
|
act(() => result.current.setHarness("cursor"));
|
|
98
112
|
expect(localStorage.getItem(STORAGE_KEY_HARNESS)).toBe("cursor");
|
|
99
113
|
expect(result.current.harness).toBe("cursor");
|
|
100
114
|
});
|
|
101
115
|
it("persists native harness to localStorage", () => {
|
|
102
116
|
localStorage.setItem(STORAGE_KEY_HARNESS, "cursor");
|
|
103
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
117
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
104
118
|
act(() => result.current.setHarness("native"));
|
|
105
119
|
expect(localStorage.getItem(STORAGE_KEY_HARNESS)).toBe("native");
|
|
106
120
|
});
|
|
107
121
|
});
|
|
108
122
|
describe("per-harness model persistence", () => {
|
|
109
123
|
it("uses separate storage keys for native and cursor models", () => {
|
|
110
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
124
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
111
125
|
act(() => result.current.setModelId(DEFAULT_MODEL_ID));
|
|
112
126
|
expect(localStorage.getItem(STORAGE_KEY_MODEL_NATIVE)).toBe(DEFAULT_MODEL_ID);
|
|
113
127
|
expect(localStorage.getItem(STORAGE_KEY_MODEL_CURSOR)).toBeNull();
|
|
114
128
|
});
|
|
115
129
|
it("persists cursor model to cursor-specific key", () => {
|
|
116
130
|
localStorage.setItem(STORAGE_KEY_HARNESS, "cursor");
|
|
117
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
131
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
118
132
|
act(() => result.current.setModelId(DEFAULT_CURSOR_MODEL_ID));
|
|
119
133
|
expect(localStorage.getItem(STORAGE_KEY_MODEL_CURSOR)).toBe(DEFAULT_CURSOR_MODEL_ID);
|
|
120
134
|
});
|
|
121
135
|
it("restores per-harness model when switching harness", () => {
|
|
122
136
|
localStorage.setItem(STORAGE_KEY_MODEL_CURSOR, DEFAULT_CURSOR_MODEL_ID);
|
|
123
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
137
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
124
138
|
act(() => result.current.setHarness("cursor"));
|
|
125
139
|
expect(result.current.modelId).toBe(DEFAULT_CURSOR_MODEL_ID);
|
|
126
140
|
});
|
|
127
141
|
it("clears modelId when switching to a harness with no stored model", () => {
|
|
128
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
142
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
129
143
|
act(() => result.current.setModelId(DEFAULT_MODEL_ID));
|
|
130
144
|
expect(result.current.modelId).toBe(DEFAULT_MODEL_ID);
|
|
131
145
|
act(() => result.current.setHarness("cursor"));
|
|
@@ -137,7 +151,7 @@ describe("useNewSessionFlow", () => {
|
|
|
137
151
|
}
|
|
138
152
|
});
|
|
139
153
|
it("invalidates modelId when it is not in the active harness registry", () => {
|
|
140
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
154
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
141
155
|
// Set a native-only model
|
|
142
156
|
act(() => result.current.setModelId(DEFAULT_MODEL_ID));
|
|
143
157
|
expect(result.current.modelId).toBe(DEFAULT_MODEL_ID);
|
|
@@ -148,7 +162,7 @@ describe("useNewSessionFlow", () => {
|
|
|
148
162
|
});
|
|
149
163
|
it("strips compound keys before persisting to localStorage", () => {
|
|
150
164
|
localStorage.setItem(STORAGE_KEY_HARNESS, "cursor");
|
|
151
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
165
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
152
166
|
// Simulate compound key from unified mode ModelSelector
|
|
153
167
|
act(() => result.current.setModelId("cursor/default"));
|
|
154
168
|
// Should store plain modelId, not compound key
|
|
@@ -158,7 +172,7 @@ describe("useNewSessionFlow", () => {
|
|
|
158
172
|
localStorage.setItem(STORAGE_KEY_HARNESS, "cursor");
|
|
159
173
|
// Legacy: compound key was stored before fix
|
|
160
174
|
localStorage.setItem(STORAGE_KEY_MODEL_CURSOR, "cursor/default");
|
|
161
|
-
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()));
|
|
175
|
+
const { result } = renderHook(() => useNewSessionFlow(defaultOptions()), { wrapper: createWrapper() });
|
|
162
176
|
// Should extract plain modelId and validate against registry
|
|
163
177
|
expect(result.current.modelId).toBe(DEFAULT_CURSOR_MODEL_ID);
|
|
164
178
|
});
|
|
@@ -166,7 +180,7 @@ describe("useNewSessionFlow", () => {
|
|
|
166
180
|
describe("submit with harness", () => {
|
|
167
181
|
it("passes harness field to createSession", async () => {
|
|
168
182
|
const opts = defaultOptions();
|
|
169
|
-
const { result } = renderHook(() => useNewSessionFlow(opts));
|
|
183
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
170
184
|
await act(async () => {
|
|
171
185
|
await result.current.submit("Hello");
|
|
172
186
|
});
|
|
@@ -176,7 +190,7 @@ describe("useNewSessionFlow", () => {
|
|
|
176
190
|
});
|
|
177
191
|
it("passes cursor harness to createSession after switching", async () => {
|
|
178
192
|
const opts = defaultOptions();
|
|
179
|
-
const { result } = renderHook(() => useNewSessionFlow(opts));
|
|
193
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
180
194
|
act(() => result.current.setHarness("cursor"));
|
|
181
195
|
await act(async () => {
|
|
182
196
|
await result.current.submit("Hello");
|
|
@@ -186,7 +200,7 @@ describe("useNewSessionFlow", () => {
|
|
|
186
200
|
});
|
|
187
201
|
it("calls onSessionCreated on success", async () => {
|
|
188
202
|
const opts = defaultOptions();
|
|
189
|
-
const { result } = renderHook(() => useNewSessionFlow(opts));
|
|
203
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
190
204
|
await act(async () => {
|
|
191
205
|
await result.current.submit("Hello");
|
|
192
206
|
});
|
|
@@ -195,7 +209,7 @@ describe("useNewSessionFlow", () => {
|
|
|
195
209
|
it("sets submitError and calls onError on failure", async () => {
|
|
196
210
|
mockCreateSession.mockRejectedValueOnce(new Error("RPC fail"));
|
|
197
211
|
const opts = defaultOptions();
|
|
198
|
-
const { result } = renderHook(() => useNewSessionFlow(opts));
|
|
212
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
199
213
|
await act(async () => {
|
|
200
214
|
await result.current.submit("Hello");
|
|
201
215
|
});
|
|
@@ -204,7 +218,7 @@ describe("useNewSessionFlow", () => {
|
|
|
204
218
|
});
|
|
205
219
|
it("resets isSubmitting after completion", async () => {
|
|
206
220
|
const opts = defaultOptions();
|
|
207
|
-
const { result } = renderHook(() => useNewSessionFlow(opts));
|
|
221
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
208
222
|
await act(async () => {
|
|
209
223
|
await result.current.submit("Hello");
|
|
210
224
|
});
|