@soba-so/react 0.0.26 → 0.0.28

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.
@@ -1,4 +1,4 @@
1
- import type { ModelGroup, ModelOption } from "./types.js";
1
+ import type { ModelChoice, ModelGroup, ModelLayout, ModelOption } from "./types.js";
2
2
  export interface UseModelOptions {
3
3
  /**
4
4
  * CONTROLLED. Pass both, or neither — a `value` without an `onChange` is a
@@ -10,7 +10,8 @@ export interface UseModelOptions {
10
10
  */
11
11
  value?: string;
12
12
  onChange?: (id: string) => void;
13
- /** What a first-time visitor gets. `auto` unless you have a reason. */
13
+ /** What a first-time visitor gets. Left out: the default model starred on
14
+ * Providers in the dashboard, else `auto`. */
14
15
  defaultValue?: string;
15
16
  /**
16
17
  * Remember the pick in this browser, per app and per person. Left on: the
@@ -28,6 +29,77 @@ export interface UseModelOptions {
28
29
  * somebody here prefers Haiku.
29
30
  */
30
31
  user?: string;
32
+ /**
33
+ * HOW THE APP'S PROVIDERS ARE LAID OUT. `providers` groups them under each
34
+ * provider's name and mark; `models` is one list, each row marked; `choices`
35
+ * shows only your own names — the ones set on Providers in the dashboard,
36
+ * and any in `choices` below. The person's own agents are listed the same
37
+ * way under all three.
38
+ *
39
+ * Left out, it is what the dashboard's Connect page says, so the layout can
40
+ * change without a deploy. Passing it here wins.
41
+ */
42
+ layout?: ModelLayout;
43
+ /**
44
+ * YOUR OWN ENTRIES — "Fast", "Smart" — each naming a model you expose on a
45
+ * provider (or one of the person's agents). Given these and no `layout`,
46
+ * the layout is `choices`. An entry whose model is not on offer is left out.
47
+ *
48
+ * Pass the same list everywhere `useModel` is called — in the menu and where
49
+ * the run is sent — or a pick of one of these is a name the other call site
50
+ * has never heard of. Names set on Providers need none of this.
51
+ *
52
+ * ```js
53
+ * useModel({ choices: [
54
+ * { id: "fast", label: "Fast", model: "gpt-5-mini", provider: "openai" },
55
+ * { id: "smart", label: "Smart", model: "claude-sonnet-5-5" },
56
+ * ] })
57
+ * ```
58
+ */
59
+ choices?: ModelChoice[];
60
+ }
61
+ /**
62
+ * ONE OF THE APP'S OWN PROVIDERS, with the models it exposes — the other half
63
+ * of the menu, for people answered on the app's provider keys rather than, or
64
+ * as well as, their own agents.
65
+ */
66
+ export interface ModelProvider {
67
+ /** The supplier row's id. */
68
+ id: string;
69
+ /** What the app's owner called it: `OpenAI`, `Groq (fast)`. */
70
+ name: string;
71
+ /** Whose API it is — `openai`, `groq` — for `<ProviderMark provider={…} />`;
72
+ * absent for an endpoint nobody recognised. */
73
+ mark?: string;
74
+ /** `frontier` or `open-weights`: which of the plan's classes it bills to. */
75
+ costClass: string;
76
+ /**
77
+ * WHY NONE OF IT CAN BE PICKED, or absent when it can. `plan`: the person's
78
+ * plan does not reach it — draw it as an upgrade, it is the one place a
79
+ * picker can say one exists. `allowance`: the plan stops at an allowance
80
+ * they have used; their own agents still answer.
81
+ */
82
+ locked?: "plan" | "allowance";
83
+ /** Every model the app exposes on it, the same objects as in `options`. */
84
+ options: ModelOption[];
85
+ }
86
+ /**
87
+ * ONE AGENT THE PERSON HAS CONNECTED, with the models it offers — the shape
88
+ * for a menu that lists agents first and opens each one onto its models.
89
+ */
90
+ export interface ModelAgent {
91
+ /** `claude-code`, `codex`, `ollama`. */
92
+ id: string;
93
+ /** `Claude Code`, as the agent names itself. */
94
+ name: string;
95
+ /** Its mark, from `modelLogo`. */
96
+ logo?: string;
97
+ /**
98
+ * Its named models, the same objects as in `options`. EMPTY for an agent
99
+ * that advertises none — Codex — which is connected and answers Automatic,
100
+ * but has nothing to choose between.
101
+ */
102
+ options: ModelOption[];
31
103
  }
32
104
  export interface ModelView {
33
105
  /** Every model this person could be answered by, Automatic first. */
@@ -39,6 +111,23 @@ export interface ModelView {
39
111
  * what was picked is not here. */
40
112
  selected: ModelOption;
41
113
  select: (id: string) => void;
114
+ /** Every connected agent, in the panel's own order, each with its models.
115
+ * Agents that offer none are included; see `ModelAgent.options`. */
116
+ agents: ModelAgent[];
117
+ /** The app's own providers and every model it exposes on them, in the
118
+ * gateway's order, locked ones included. Empty for an app with none. */
119
+ providers: ModelProvider[];
120
+ /** Every provider's models in one list, for the `models` layout. */
121
+ models: ModelOption[];
122
+ /** Your `choices`, resolved — the rows of the `choices` layout. */
123
+ choices: ModelOption[];
124
+ /** The layout in force. */
125
+ layout: ModelLayout;
126
+ /** Under `models`, whether their own agents' models are in the one list
127
+ * too, as the app set it on Connect. */
128
+ ownInList: boolean;
129
+ /** Whether a long list gets a search field, as the app set it on Connect. */
130
+ search: boolean;
42
131
  /**
43
132
  * SPREAD THIS INTO THE RUN, and spread it rather than reading `model` off it.
44
133
  *
@@ -48,10 +137,17 @@ export interface ModelView {
48
137
  * is handed to whatever agent the broker finds first. An app that forwards
49
138
  * only `model` works until somebody with two agents picks a model from the
50
139
  * second one.
140
+ *
141
+ * For one of the app's providers it is `{ model, route: { allow: [class] } }`,
142
+ * which is what keeps `gpt-5` off the person's laptop: pass `route` through to
143
+ * `soba.run()` as well. It only narrows — the plan still decides.
51
144
  */
52
145
  run: {
53
146
  model: string;
54
147
  runtime?: string;
148
+ route?: {
149
+ allow: string[];
150
+ };
55
151
  };
56
152
  /**
57
153
  * WHAT THEY PICKED THAT IS NOT CURRENTLY ON OFFER — the laptop with Opus on
@@ -66,8 +162,9 @@ export interface ModelView {
66
162
  /** More than Automatic to choose between. False with nothing connected,
67
163
  * which is when `<ModelPicker />` draws nothing. */
68
164
  pickable: boolean;
69
- /** The first machines poll is still in flight. The list is Automatic only
70
- * until it lands, so a picker drawn on this is a picker that pops in. */
165
+ /** The first machines poll, or the first read of the app's providers, is
166
+ * still in flight with nothing else to show. The list is Automatic only
167
+ * until one lands, so a picker drawn on this is a picker that pops in. */
71
168
  loading: boolean;
72
169
  }
73
170
  /**
@@ -91,3 +188,19 @@ export interface ModelView {
91
188
  * rather than configured.
92
189
  */
93
190
  export declare function useModel(options?: UseModelOptions): ModelView;
191
+ /**
192
+ * THE AGENT'S OWN MARK, for an app drawing `useModel()` in its own menu — a
193
+ * data URI, or undefined for Automatic and the sizes, which belong to no one
194
+ * agent, and for an agent this package has no mark for.
195
+ *
196
+ * Full colour and never to be tinted: an app icon recoloured is not that
197
+ * company's mark any more.
198
+ *
199
+ * ```jsx
200
+ * const logo = modelLogo(option)
201
+ * {logo && <img src={logo} alt="" width={16} height={16} />}
202
+ * ```
203
+ */
204
+ export declare function modelLogo(option: {
205
+ runtime?: string;
206
+ }): string | undefined;
@@ -1,4 +1,4 @@
1
- import type { Plan } from "./types.js";
1
+ import type { FeatureItem, Plan } from "./types.js";
2
2
  /**
3
3
  * THE PRICE LIST AS A DECISION, NOT AS MARKUP.
4
4
  *
@@ -86,6 +86,14 @@ export interface PlanOffer {
86
86
  /** What follows from it: `Included each month · then $0.02 a run · 14-day
87
87
  * trial`. A consequence of the figure rather than a second fact beside it. */
88
88
  allowanceNote: string;
89
+ /** `Unlimited runs on your own AI`, or `50 runs a month on your own AI`:
90
+ * the second allowance, which `allowance` above does not include. Null when
91
+ * the plan never runs on their AI or both are unlimited. */
92
+ ownAllowance: string | null;
93
+ /** The plan's features as card lines — `Export to PDF`, `5 projects` —
94
+ * each with whether the plan has it; a "no" is drawn crossed out. What the
95
+ * vendor's app enforces, never Soba. */
96
+ features: FeatureItem[];
89
97
  /** Null `route_allow` is any compute, an empty one is none, and both are
90
98
  * sentences rather than lists. Null here means `compute` below is the list. */
91
99
  computeLabel: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soba-so/react",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Connect the AI your users already pay for, from your own React app.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://soba.so/docs/components",