@ego-z/contracts 0.15.12 → 0.15.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ego-z/contracts",
3
- "version": "0.15.12",
3
+ "version": "0.15.14",
4
4
  "description": "Wire-format type contracts shared between EgoZ backend, SDK, MCP and console. Type-only — no runtime artifacts.",
5
5
  "types": "./src/index.d.ts",
6
6
  "exports": {
package/src/ask.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { Intent, JsonSchemaDefinition, ResponseFormat, TokenUsage } from './envelope';
9
- import type { InitContextItem, InitContextItemAccepted, InitContextUi } from './draft-conv';
9
+ import type { InitContextItem, InitContextItemAccepted, InitContextTenant, InitContextUi } from './draft-conv';
10
10
  import type { AskQuestionSet } from './questions';
11
11
 
12
12
  // ============================================================================
@@ -90,6 +90,36 @@ export interface AskRequestBody {
90
90
  */
91
91
  externalUserId?: string;
92
92
 
93
+ /**
94
+ * Run THIS turn on a specific chat model, instead of the project's
95
+ * configured default.
96
+ *
97
+ * Only honoured on a project whose owner has turned model switching on and
98
+ * curated a menu (Console → LLM Settings). Read the menu from
99
+ * `GET /egoz/models`, which returns every model this project offers along
100
+ * with which one is the default, and echo an `id` back here verbatim.
101
+ *
102
+ * - omitted → the project's default model, exactly as before.
103
+ * - `"openai:gpt-4o-mini"` → the canonical, always-unambiguous form.
104
+ * - `"gpt-4o-mini"` → accepted while that id is offered by only
105
+ * one provider on this project.
106
+ *
107
+ * A model this project does not offer — and ANY value at all on a project
108
+ * where switching is off — is rejected with `ModelNotAllowed` (400). It is
109
+ * deliberately not ignored: a caller whose override is silently dropped
110
+ * believes it took effect, and the only trace of the truth is a model
111
+ * field on a usage row nobody reads until the invoice arrives.
112
+ *
113
+ * Scope, and what it does NOT change:
114
+ * - Embeddings are pinned to the project. The knowledge base's vectors
115
+ * were written in one embedding space, and retrieving against another
116
+ * returns confident nonsense — so RAG is unaffected by this field.
117
+ * - A voice call ignores it. A call is a latency budget; the tenant's
118
+ * `voiceModel` still wins there. The value is still validated, so a
119
+ * bad one is a 400 rather than a surprise.
120
+ */
121
+ model?: string;
122
+
93
123
  /** Override the tenant's default response format for this single call. */
94
124
  responseFormat?: ResponseFormat;
95
125
 
@@ -212,6 +242,32 @@ export interface AskRequestBody {
212
242
  */
213
243
  contextItems?: InitContextItem[];
214
244
 
245
+ /**
246
+ * The tenant AS IT IS NOW — sent when it may have changed since the
247
+ * conversation began.
248
+ *
249
+ * ── Why per-turn ─────────────────────────────────────────────────────
250
+ *
251
+ * The draft's `initContext.tenant` is captured once, and its `features`
252
+ * are rendered to the agent as a hard rule on every turn: disabled means
253
+ * "never offer". A tenant whose features change mid-conversation — a setup
254
+ * flow switching bookings on — would otherwise be told, turn after turn,
255
+ * that the thing it just enabled is off.
256
+ *
257
+ * ── Merged, and kept ─────────────────────────────────────────────────
258
+ *
259
+ * The keys you SEND replace the stored ones; keys you omit keep their
260
+ * stored value, and `null` clears one. `features` is replaced as a whole
261
+ * map — send the complete current set, not a delta. The merged block is
262
+ * kept on the conversation (except for a no-store tenant), so a later
263
+ * turn that omits this field still sees it.
264
+ *
265
+ * Validated exactly like `initContext.tenant`: an invalid block is a 400.
266
+ *
267
+ * Optional and additive: omit it and nothing changes.
268
+ */
269
+ tenant?: InitContextTenant;
270
+
215
271
  /**
216
272
  * Output a MACHINE produced for this turn — the result of something the
217
273
  * user asked to have run, not anything the user said.
@@ -456,6 +456,8 @@ export interface InitContextTenant {
456
456
  name?: string | null;
457
457
  description?: string | null;
458
458
  category?: string | null;
459
+ /** What the business is, in the caller's words — finer than `category` ("barbershop"). */
460
+ niche?: string | null;
459
461
  /** Enabled-feature flags, e.g. `{ products: true, booking: false }`. */
460
462
  features?: Record<string, boolean>;
461
463
  }
package/src/index.d.ts CHANGED
@@ -74,6 +74,10 @@
74
74
  * create / update / clone bodies,
75
75
  * `ActiveTenantPersonalityWire`. Shared:
76
76
  * `PersonalityTraitsWire`, `PresetType`.
77
+ * - `model.d.ts` — `GET /egoz/models`: the menu of chat models a
78
+ * project offers for `AskRequestBody.model`.
79
+ * `SwitchableModelWire`,
80
+ * `SwitchableModelsResponseData`.
77
81
  * - `user-memory.d.ts` — Per-end-user learning (Phase 15 / exURM).
78
82
  * `UserMemoryWire`, `UserMemoryUserSummaryWire`,
79
83
  * `UpdateUserMemoryFactBody`, list / detail / fact /
@@ -93,6 +97,7 @@
93
97
 
94
98
  export * from './envelope';
95
99
  export * from './ask';
100
+ export * from './model';
96
101
  export * from './stream';
97
102
  export * from './questions';
98
103
  export * from './tool';
package/src/model.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @ego-z/contracts — `GET /egoz/models` wire types.
3
+ *
4
+ * The menu of chat models a project offers for `AskRequestBody.model`. Read
5
+ * this to build a model picker; echo an entry's `id` back verbatim.
6
+ *
7
+ * ── Why this endpoint exists at all ──────────────────────────────────────
8
+ *
9
+ * The alternative was for integrators to hardcode the model ids their picker
10
+ * offers. That list is a copy of one a project owner edits in the Console,
11
+ * with nothing connecting the two: the day the owner drops a model, every
12
+ * caller's picker keeps offering it and every pick 400s, in someone else's
13
+ * deployment, with no signal on the Console side that anything broke.
14
+ *
15
+ * ── Authentication ───────────────────────────────────────────────────────
16
+ *
17
+ * Same trusted-server pattern as `/ask`: the tenant API key in `X-API-Key`
18
+ * (plus `X-Tenant-Id`). It is deliberately NOT anonymous — the menu names a
19
+ * project's providers and model tiers, which is commercial detail, not public
20
+ * information.
21
+ *
22
+ * ── What it is not ───────────────────────────────────────────────────────
23
+ *
24
+ * Not a provider catalogue. It returns exactly what the owner curated, and
25
+ * makes no call to OpenAI/Anthropic/Azure to do so — a hot path on every chat
26
+ * panel open must not fan out to third parties. The Console's model dropdowns
27
+ * are the surface that browses live catalogues
28
+ * (`GET /egoz/tenants/:tenantId/models`); this one publishes the decision.
29
+ */
30
+
31
+ /** One model this project will run. */
32
+ export interface SwitchableModelWire {
33
+ /**
34
+ * Canonical handle, `"<provider>:<model>"` (e.g. `"openai:gpt-4o-mini"`).
35
+ * Send this back as `AskRequestBody.model`. Stable for as long as the
36
+ * owner keeps the entry on the menu.
37
+ */
38
+ id: string;
39
+ /** BYOK provider that will serve the turn — `"openai"`, `"anthropic"`, … */
40
+ provider: string;
41
+ /**
42
+ * Provider-side model id. On Azure this is the DEPLOYMENT name, which is
43
+ * private to the tenant — do not assume it matches a public model name.
44
+ */
45
+ model: string;
46
+ /** True for the model used when `AskRequestBody.model` is omitted. Exactly one entry has it. */
47
+ isDefault: boolean;
48
+ }
49
+
50
+ /** `data` payload of `GET /egoz/models`. */
51
+ export interface SwitchableModelsResponseData {
52
+ /**
53
+ * Whether `AskRequestBody.model` will be honoured. When `false`, `models`
54
+ * still holds exactly one entry — the project default — so a picker can
55
+ * render the same way either way and simply has nothing to switch to.
56
+ *
57
+ * Sending `model` while this is `false` is an error, not a no-op.
58
+ */
59
+ switchable: boolean;
60
+ /** `id` of the default entry. Convenience — it is also the entry with `isDefault: true`. */
61
+ defaultId: string;
62
+ /** The default first, then the owner's curated alternatives. Never empty. */
63
+ models: SwitchableModelWire[];
64
+ }