@egox/contracts 0.5.0
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/LICENSE +201 -0
- package/NOTICE +10 -0
- package/README.md +87 -0
- package/package.json +46 -0
- package/src/api-key.d.ts +155 -0
- package/src/ask.d.ts +225 -0
- package/src/envelope.d.ts +66 -0
- package/src/index.d.ts +87 -0
- package/src/mcp-token.d.ts +133 -0
- package/src/personality.d.ts +275 -0
- package/src/rag.d.ts +188 -0
- package/src/search.d.ts +23 -0
- package/src/stream.d.ts +186 -0
- package/src/tenant.d.ts +215 -0
- package/src/thread.d.ts +183 -0
- package/src/tool.d.ts +269 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @egox/contracts — `/egox/personality/*` and
|
|
3
|
+
* `/egox/tenants/:tenantId/personality/*` wire types.
|
|
4
|
+
*
|
|
5
|
+
* Two related but distinct surfaces share this file:
|
|
6
|
+
*
|
|
7
|
+
* - **User-level templates** (`/egox/personality/*`). A library of
|
|
8
|
+
* personality profiles a console user authors and later clones
|
|
9
|
+
* into specific projects. NOT used at `/ask` resolution time.
|
|
10
|
+
* - **Project-scoped profiles** (`/egox/tenants/:tenantId/personality/*`,
|
|
11
|
+
* Item #6 refactor). The single ACTIVE row per tenant drives the
|
|
12
|
+
* LLM's persona on every `/ask`. Cloned from a template or
|
|
13
|
+
* authored fresh in the project.
|
|
14
|
+
*
|
|
15
|
+
* Both shapes share `PersonalityTraitsWire` and `PresetType` —
|
|
16
|
+
* cloning a template is a structural copy plus a `templateSourceUserId`
|
|
17
|
+
* / `templateSourceProfileId` pointer.
|
|
18
|
+
*
|
|
19
|
+
* Drift cleaned up:
|
|
20
|
+
* - Backend `PersonalityProfile` and `TenantPersonalityProfile`
|
|
21
|
+
* used `Date` for timestamps; wire and console already used ISO.
|
|
22
|
+
* Backend formatters now match.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Locked vocabularies
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Preset personality archetypes the console offers as starting points.
|
|
31
|
+
* Mirrors the keys of the backend's preset registry. Adding a preset
|
|
32
|
+
* is a one-edit change here + a new entry in the registry; the union
|
|
33
|
+
* fails the build on any consumer that hard-codes the old set.
|
|
34
|
+
*/
|
|
35
|
+
export type PresetType =
|
|
36
|
+
| 'balanced'
|
|
37
|
+
| 'professional'
|
|
38
|
+
| 'friendly'
|
|
39
|
+
| 'casual'
|
|
40
|
+
| 'expert'
|
|
41
|
+
| 'playful'
|
|
42
|
+
| 'empathetic'
|
|
43
|
+
| 'concise';
|
|
44
|
+
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Supporting shapes
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The eight personality dials (0-100 each). Used as the active
|
|
51
|
+
* configuration on both user templates and project profiles, and as
|
|
52
|
+
* the slider values the console renders.
|
|
53
|
+
*
|
|
54
|
+
* Each axis is documented relative to its low / high pole — that
|
|
55
|
+
* documentation belongs in the contracts package because it's part
|
|
56
|
+
* of what consumers (the SDK exposing it, future MCP tools surfacing
|
|
57
|
+
* it) need to render the control correctly.
|
|
58
|
+
*/
|
|
59
|
+
export interface PersonalityTraitsWire {
|
|
60
|
+
/** 0 = serious, 100 = playful. */
|
|
61
|
+
senseOfHumor: number;
|
|
62
|
+
/** 0 = casual, 100 = formal/grave. */
|
|
63
|
+
seriousness: number;
|
|
64
|
+
/** 0 = diplomatic, 100 = blunt. */
|
|
65
|
+
directness: number;
|
|
66
|
+
/** 0 = conventional, 100 = creative. */
|
|
67
|
+
creativity: number;
|
|
68
|
+
/** 0 = neutral, 100 = caring. */
|
|
69
|
+
empathy: number;
|
|
70
|
+
/** 0 = casual, 100 = formal. */
|
|
71
|
+
formality: number;
|
|
72
|
+
/** 0 = brief, 100 = detailed. */
|
|
73
|
+
verbosity: number;
|
|
74
|
+
/** 0 = calm, 100 = energetic. */
|
|
75
|
+
enthusiasm: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// User-level personality template (the templates library)
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Wire-format user-level personality profile. Returned by
|
|
84
|
+
* `/egox/personality/*` endpoints. Owned by a console user and
|
|
85
|
+
* intended to be cloned INTO projects via the tenant-personality
|
|
86
|
+
* clone endpoint.
|
|
87
|
+
*
|
|
88
|
+
* `isActive` here is a per-template "currently authoring this one"
|
|
89
|
+
* flag, NOT the `/ask` resolution flag (that's
|
|
90
|
+
* `TenantPersonalityProfileWire.isActive`).
|
|
91
|
+
*/
|
|
92
|
+
export interface PersonalityProfileWire {
|
|
93
|
+
id: string;
|
|
94
|
+
userId: string;
|
|
95
|
+
name: string;
|
|
96
|
+
traits: PersonalityTraitsWire;
|
|
97
|
+
|
|
98
|
+
customInstructions: string | null;
|
|
99
|
+
exampleResponses: string[];
|
|
100
|
+
avoidPhrases: string[];
|
|
101
|
+
preferredPhrases: string[];
|
|
102
|
+
|
|
103
|
+
agentName: string | null;
|
|
104
|
+
agentRole: string | null;
|
|
105
|
+
agentTone: string | null;
|
|
106
|
+
|
|
107
|
+
isActive: boolean;
|
|
108
|
+
/** `true` for the immutable seed templates the backend ships with. */
|
|
109
|
+
isPreset: boolean;
|
|
110
|
+
presetType: PresetType | null;
|
|
111
|
+
|
|
112
|
+
/** ISO 8601 timestamp. */
|
|
113
|
+
createdAt: string;
|
|
114
|
+
/** ISO 8601 timestamp. */
|
|
115
|
+
updatedAt: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Definition of one immutable seed preset. Returned by the
|
|
120
|
+
* "list presets" endpoint so the console can render the picker
|
|
121
|
+
* without hard-coding the catalogue.
|
|
122
|
+
*/
|
|
123
|
+
export interface PresetDefinitionWire {
|
|
124
|
+
type: PresetType;
|
|
125
|
+
name: string;
|
|
126
|
+
description: string;
|
|
127
|
+
traits: PersonalityTraitsWire;
|
|
128
|
+
/** Optional emoji / lucide icon name; console-renderer-defined. */
|
|
129
|
+
icon?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Wire body of `POST /egox/personality/profiles`. `userId` is derived
|
|
134
|
+
* from the console JWT, not the body.
|
|
135
|
+
*/
|
|
136
|
+
export interface PersonalityProfileCreateBody {
|
|
137
|
+
name: string;
|
|
138
|
+
traits?: Partial<PersonalityTraitsWire>;
|
|
139
|
+
customInstructions?: string;
|
|
140
|
+
exampleResponses?: string[];
|
|
141
|
+
avoidPhrases?: string[];
|
|
142
|
+
preferredPhrases?: string[];
|
|
143
|
+
agentName?: string;
|
|
144
|
+
agentRole?: string;
|
|
145
|
+
agentTone?: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Wire body of `PUT /egox/personality/profiles/:profileId`. Every
|
|
150
|
+
* field is optional; `null` is a meaningful value for the nullable
|
|
151
|
+
* string columns (clears them), `undefined` means "leave alone". The
|
|
152
|
+
* service distinguishes between the two.
|
|
153
|
+
*/
|
|
154
|
+
export interface PersonalityProfileUpdateBody {
|
|
155
|
+
name?: string;
|
|
156
|
+
traits?: Partial<PersonalityTraitsWire>;
|
|
157
|
+
customInstructions?: string | null;
|
|
158
|
+
exampleResponses?: string[];
|
|
159
|
+
avoidPhrases?: string[];
|
|
160
|
+
preferredPhrases?: string[];
|
|
161
|
+
agentName?: string | null;
|
|
162
|
+
agentRole?: string | null;
|
|
163
|
+
agentTone?: string | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Project-scoped personality (Item #6 — drives /ask)
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Wire-format project-scoped personality profile. Returned by
|
|
172
|
+
* `/egox/tenants/:tenantId/personality/*`. The single row with
|
|
173
|
+
* `isActive: true` per tenant is what the orchestrator resolves for
|
|
174
|
+
* `/ask`.
|
|
175
|
+
*
|
|
176
|
+
* `templateSourceUserId` and `templateSourceProfileId` are nullable
|
|
177
|
+
* provenance pointers — preserved as `SET NULL` if the source
|
|
178
|
+
* template or its owner is deleted. They power the future "compare
|
|
179
|
+
* against template" UX without coupling project profile lifetime to
|
|
180
|
+
* template lifetime.
|
|
181
|
+
*/
|
|
182
|
+
export interface TenantPersonalityProfileWire {
|
|
183
|
+
id: string;
|
|
184
|
+
tenantId: string;
|
|
185
|
+
name: string;
|
|
186
|
+
traits: PersonalityTraitsWire;
|
|
187
|
+
|
|
188
|
+
customInstructions: string | null;
|
|
189
|
+
exampleResponses: string[];
|
|
190
|
+
avoidPhrases: string[];
|
|
191
|
+
preferredPhrases: string[];
|
|
192
|
+
|
|
193
|
+
agentName: string | null;
|
|
194
|
+
agentRole: string | null;
|
|
195
|
+
agentTone: string | null;
|
|
196
|
+
|
|
197
|
+
isActive: boolean;
|
|
198
|
+
|
|
199
|
+
templateSourceUserId: string | null;
|
|
200
|
+
templateSourceProfileId: string | null;
|
|
201
|
+
|
|
202
|
+
/** ISO 8601 timestamp. */
|
|
203
|
+
createdAt: string;
|
|
204
|
+
/** ISO 8601 timestamp. */
|
|
205
|
+
updatedAt: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Wire body of `POST /egox/tenants/:tenantId/personality/profiles`
|
|
210
|
+
* (fresh, no template lineage). `tenantId` is the URL param, not the
|
|
211
|
+
* body.
|
|
212
|
+
*/
|
|
213
|
+
export interface TenantPersonalityCreateBody {
|
|
214
|
+
name: string;
|
|
215
|
+
traits?: Partial<PersonalityTraitsWire>;
|
|
216
|
+
customInstructions?: string;
|
|
217
|
+
exampleResponses?: string[];
|
|
218
|
+
avoidPhrases?: string[];
|
|
219
|
+
preferredPhrases?: string[];
|
|
220
|
+
agentName?: string;
|
|
221
|
+
agentRole?: string;
|
|
222
|
+
agentTone?: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Wire body of `PUT /egox/tenants/:tenantId/personality/profiles/:profileId`.
|
|
227
|
+
* Same null-vs-undefined semantics as `PersonalityProfileUpdateBody`.
|
|
228
|
+
*/
|
|
229
|
+
export interface TenantPersonalityUpdateBody {
|
|
230
|
+
name?: string;
|
|
231
|
+
traits?: Partial<PersonalityTraitsWire>;
|
|
232
|
+
customInstructions?: string | null;
|
|
233
|
+
exampleResponses?: string[];
|
|
234
|
+
avoidPhrases?: string[];
|
|
235
|
+
preferredPhrases?: string[];
|
|
236
|
+
agentName?: string | null;
|
|
237
|
+
agentRole?: string | null;
|
|
238
|
+
agentTone?: string | null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Wire body of the clone endpoint. `sourceUserId` MUST be the
|
|
243
|
+
* requesting console user (validated server-side); a stolen
|
|
244
|
+
* `sourceProfileId` therefore can't be cloned across user boundaries.
|
|
245
|
+
*/
|
|
246
|
+
export interface TenantPersonalityCloneBody {
|
|
247
|
+
sourceUserId: string;
|
|
248
|
+
sourceProfileId: string;
|
|
249
|
+
/** Defaults to `${source.name} (cloned)` server-side. */
|
|
250
|
+
name?: string;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ============================================================================
|
|
254
|
+
// Resolution envelopes (returned by the "what's active?" endpoints)
|
|
255
|
+
// ============================================================================
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Response of `GET /egox/personality/active`. `isDefault: true`
|
|
259
|
+
* means no user-level profile is selected and the future caller
|
|
260
|
+
* should treat the user as having no template-level preference.
|
|
261
|
+
*/
|
|
262
|
+
export interface ActivePersonalityWire {
|
|
263
|
+
profile: PersonalityProfileWire | null;
|
|
264
|
+
isDefault: boolean;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Response of `GET /egox/tenants/:tenantId/personality/active`.
|
|
269
|
+
* `isDefault: true` means no project-level profile is active —
|
|
270
|
+
* `/ask` falls back to the orchestrator's built-in baseline prompt.
|
|
271
|
+
*/
|
|
272
|
+
export interface ActiveTenantPersonalityWire {
|
|
273
|
+
profile: TenantPersonalityProfileWire | null;
|
|
274
|
+
isDefault: boolean;
|
|
275
|
+
}
|
package/src/rag.d.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @egox/contracts — `/egox/tenants/:tenantId/rag/documents/*` +
|
|
3
|
+
* `/egox/mcp-admin/rag-documents/*` wire types.
|
|
4
|
+
*
|
|
5
|
+
* Three independent consumers used to hand-mirror these shapes:
|
|
6
|
+
* - the backend (`modules/rag/interfaces.ts`)
|
|
7
|
+
* - the MCP server (`egox-mcp/src/backend-client.ts` — `BackendRagDoc`)
|
|
8
|
+
* - the console (`console/src/types/models.ts` — `RagDocument`)
|
|
9
|
+
* Each mirror had its own subtle drift:
|
|
10
|
+
* - MCP's `sourceType` / `processingStatus` were typed as bare `string`
|
|
11
|
+
* (no `'file'|'url'|'manual'` lock), and `sourceUrl` was missing entirely.
|
|
12
|
+
* - Console's `RagDocument` had no `source` (provenance) field at all,
|
|
13
|
+
* so the manual-vs-MCP distinction was invisible in the UI.
|
|
14
|
+
* - Backend timestamps were `Date` in-process but ISO strings on the
|
|
15
|
+
* wire — same wire/runtime mismatch we removed for Tools in P1.
|
|
16
|
+
* Phase 9.2 unifies all three under `RagDocumentWire`.
|
|
17
|
+
*
|
|
18
|
+
* Mirrors the pattern locked in P1 (`tool.d.ts`):
|
|
19
|
+
* - locked vocabularies prefixed `Rag*` to avoid collisions with
|
|
20
|
+
* future families that have their own "source type" concept;
|
|
21
|
+
* - timestamps as ISO 8601 `string` (backend `formatDocument` now
|
|
22
|
+
* emits ISO via the same `toIso` helper Tools uses);
|
|
23
|
+
* - request bodies omit context fields the route layer attaches
|
|
24
|
+
* (`tenantId`, identifying URL params).
|
|
25
|
+
*
|
|
26
|
+
* **Backend-only.** `RagChunk`, `RetrievedChunk`, `RetrievalRequest`,
|
|
27
|
+
* `RetrievalResponse`, and `ChunkOptions` are NOT wire types — they're
|
|
28
|
+
* orchestrator-internal retrieval shapes. The only chunk info that
|
|
29
|
+
* crosses the wire is the minimal `{ documentTitle, score }` pair
|
|
30
|
+
* already on `AskStreamRagRetrievedEvent` in `stream.d.ts`.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Locked vocabularies
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* How a RAG document entered the system.
|
|
39
|
+
* - `'file'` — uploaded via Console.
|
|
40
|
+
* - `'url'` — fetched from a URL the user provided.
|
|
41
|
+
* - `'manual'` — pasted as text in the Console editor.
|
|
42
|
+
*
|
|
43
|
+
* Distinct from `RagDocumentSource` (provenance: which user surface
|
|
44
|
+
* created the row, `'manual'` console vs `'mcp'` Cursor flow).
|
|
45
|
+
*/
|
|
46
|
+
export type RagDocumentSourceType = 'file' | 'url' | 'manual';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Async ingestion state. Documents start `'pending'`, advance to
|
|
50
|
+
* `'processing'` while chunking + embedding run, then settle at
|
|
51
|
+
* `'completed'` or `'failed'`. Console surfaces these as badge colors.
|
|
52
|
+
*/
|
|
53
|
+
export type RagProcessingStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Provenance of the document.
|
|
57
|
+
* - `'manual'` — created in the Console.
|
|
58
|
+
* - `'mcp'` — created via the MCP server (Cursor / 3rd-party MCP
|
|
59
|
+
* client). Overwriting a `'manual'` document from MCP
|
|
60
|
+
* requires `force: true` (see `RagDocumentUpsertByTitleBody`).
|
|
61
|
+
*
|
|
62
|
+
* Structurally identical to `ToolSource` from `tool.d.ts` but kept as a
|
|
63
|
+
* distinct nominal type so a function expecting one can't be passed the
|
|
64
|
+
* other by mistake — each family owns its own source-of-truth vocab.
|
|
65
|
+
*/
|
|
66
|
+
export type RagDocumentSource = 'manual' | 'mcp';
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// RagDocumentWire — the canonical row shape
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Wire-format RAG document row. Returned by every
|
|
74
|
+
* `/egox/tenants/:tenantId/rag/documents/*` and
|
|
75
|
+
* `/egox/mcp-admin/rag-documents/*` response that produces a document.
|
|
76
|
+
*
|
|
77
|
+
* Backend in-process `RagDocument` is an alias of this type. Timestamps
|
|
78
|
+
* are typed as `string` (ISO 8601) because that's what Fastify
|
|
79
|
+
* serialises Date values to; the backend's `formatDocument` emits ISO
|
|
80
|
+
* strings to match so wire and in-process shapes never disagree.
|
|
81
|
+
*
|
|
82
|
+
* The body of the document and its chunked content live in different
|
|
83
|
+
* places — this row carries the raw `content` (so consumers can
|
|
84
|
+
* display the source text) but does NOT include the derived chunks.
|
|
85
|
+
* Chunks are an orchestrator-internal concept; only the `chunkCount`
|
|
86
|
+
* is exposed.
|
|
87
|
+
*/
|
|
88
|
+
export interface RagDocumentWire {
|
|
89
|
+
id: string;
|
|
90
|
+
/**
|
|
91
|
+
* Owning tenant. Present on every response for audit; the request
|
|
92
|
+
* side never carries it (the backend derives tenant from the API
|
|
93
|
+
* key / JWT context).
|
|
94
|
+
*/
|
|
95
|
+
tenantId: string;
|
|
96
|
+
/**
|
|
97
|
+
* Display title. Also the natural key for the MCP upsert path
|
|
98
|
+
* (`PUT /egox/mcp-admin/rag-documents/:title`) — uniqueness is
|
|
99
|
+
* enforced per tenant.
|
|
100
|
+
*/
|
|
101
|
+
title: string;
|
|
102
|
+
sourceType: RagDocumentSourceType;
|
|
103
|
+
/** Origin URL when `sourceType === 'url'`; `null` otherwise. */
|
|
104
|
+
sourceUrl: string | null;
|
|
105
|
+
/** Raw text content. May be large — Console truncates in list views. */
|
|
106
|
+
content: string;
|
|
107
|
+
/** Tenant-supplied tags. Used for retrieval filtering (`tags?: string[]` on `/ask`). */
|
|
108
|
+
tags: string[];
|
|
109
|
+
/** Free-form per-document metadata (provenance hints, authoring info, etc.). */
|
|
110
|
+
metadata: Record<string, unknown>;
|
|
111
|
+
processingStatus: RagProcessingStatus;
|
|
112
|
+
/** Number of chunks the document was split into. `0` until processing completes. */
|
|
113
|
+
chunkCount: number;
|
|
114
|
+
source: RagDocumentSource;
|
|
115
|
+
/** ISO 8601 timestamp. */
|
|
116
|
+
createdAt: string;
|
|
117
|
+
/** ISO 8601 timestamp. */
|
|
118
|
+
updatedAt: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// Request bodies (what the client SENDS)
|
|
123
|
+
// ============================================================================
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Wire body of `POST /egox/tenants/:tenantId/rag/documents` (the
|
|
127
|
+
* Console admin path). Notable absences:
|
|
128
|
+
* - `tenantId` — URL param, not body.
|
|
129
|
+
* - `processingStatus` — server-managed, starts at `'pending'`.
|
|
130
|
+
* - `chunkCount` — server-managed, populated by the chunker.
|
|
131
|
+
* - `source` — admin route hardcodes `'manual'`; the MCP
|
|
132
|
+
* path uses `RagDocumentUpsertByTitleBody`
|
|
133
|
+
* and hardcodes `'mcp'`.
|
|
134
|
+
* - timestamps — server-managed.
|
|
135
|
+
*/
|
|
136
|
+
export interface RagDocumentCreateBody {
|
|
137
|
+
title: string;
|
|
138
|
+
content: string;
|
|
139
|
+
sourceType?: RagDocumentSourceType;
|
|
140
|
+
sourceUrl?: string;
|
|
141
|
+
tags?: string[];
|
|
142
|
+
metadata?: Record<string, unknown>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Wire body of `PUT /egox/mcp-admin/rag-documents/:title` (the MCP
|
|
147
|
+
* idempotent upsert path). Differs from `RagDocumentCreateBody`:
|
|
148
|
+
* - `title` — URL param, not body.
|
|
149
|
+
* - `sourceType`/`sourceUrl` — not accepted; MCP-created docs are
|
|
150
|
+
* always `sourceType: 'manual'`,
|
|
151
|
+
* `sourceUrl: null`, `source: 'mcp'`.
|
|
152
|
+
* - `force` — opt-in escape hatch to overwrite a `'manual'`
|
|
153
|
+
* document of the same title. Without it the
|
|
154
|
+
* backend returns `McpManualOverrideRequired`.
|
|
155
|
+
*/
|
|
156
|
+
export interface RagDocumentUpsertByTitleBody {
|
|
157
|
+
content: string;
|
|
158
|
+
tags?: string[];
|
|
159
|
+
metadata?: Record<string, unknown>;
|
|
160
|
+
/** Set to `true` to overwrite a `'manual'`-source document of the same title. */
|
|
161
|
+
force?: boolean;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// Response data shapes (carried inside `EgoxApiResponse.data`)
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
export interface RagDocumentListResponseData {
|
|
169
|
+
documents: RagDocumentWire[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface RagDocumentGetResponseData {
|
|
173
|
+
document: RagDocumentWire;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Response payload of the MCP upsert endpoint
|
|
178
|
+
* (`PUT /egox/mcp-admin/rag-documents/:title`).
|
|
179
|
+
* - `action: 'created'` — there was no prior row for this title.
|
|
180
|
+
* - `action: 'replaced'` — the old row was deleted and a fresh one
|
|
181
|
+
* created; chunks are recomputed asynchronously.
|
|
182
|
+
* - `message` — operator-facing hint about async processing.
|
|
183
|
+
*/
|
|
184
|
+
export interface RagDocumentUpsertResponseData {
|
|
185
|
+
document: RagDocumentWire;
|
|
186
|
+
action: 'created' | 'replaced';
|
|
187
|
+
message: string;
|
|
188
|
+
}
|
package/src/search.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* search.d.ts — unified tenant search (`GET /egox/tenants/:tenantId/search`).
|
|
3
|
+
*
|
|
4
|
+
* Powers the console command-palette's dynamic fallback: when the static page
|
|
5
|
+
* matrix has no match, the palette searches this tenant's tools/endpoints and
|
|
6
|
+
* KB documents by keyword (min 3 chars) and indexes the results client-side.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** A single searchable entity (tool/endpoint or KB document). */
|
|
10
|
+
export interface SearchResultItem {
|
|
11
|
+
type: 'tool' | 'document';
|
|
12
|
+
id: string;
|
|
13
|
+
/** Display name — tool `toolName` or document `title`. */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Secondary line — tool `toolDescription` or document processing status. */
|
|
16
|
+
subtitle?: string;
|
|
17
|
+
tenantId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Response of `GET /egox/tenants/:tenantId/search?q=<keyword>&limit=<n>`. */
|
|
21
|
+
export interface TenantSearchResponseData {
|
|
22
|
+
results: SearchResultItem[];
|
|
23
|
+
}
|
package/src/stream.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @egox/contracts — `/ask/stream` SSE event union.
|
|
3
|
+
*
|
|
4
|
+
* Each event is JSON-serialized and framed as a single `data: …\n\n`
|
|
5
|
+
* Server-Sent Event. Backend writes these; SDK + Console parse them.
|
|
6
|
+
* The discriminated union is the single source of truth for both sides
|
|
7
|
+
* so adding a new event variant is a single-edit, type-checked change
|
|
8
|
+
* across the stack.
|
|
9
|
+
*
|
|
10
|
+
* `AskStreamRequestBody` (the wire request shape) lives in `ask.d.ts`
|
|
11
|
+
* because it inherits from `AskRequestBody`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { Intent, TokenUsage } from './envelope';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Discriminated union of every event the streaming `/ask` endpoint emits.
|
|
18
|
+
*
|
|
19
|
+
* Notes on subset behaviour:
|
|
20
|
+
* - `stream: 'minimal'` requests omit `rag.*` and `tool.*` events.
|
|
21
|
+
* - `done` is always the terminal success frame.
|
|
22
|
+
* - `error` may appear at any point and is also terminal.
|
|
23
|
+
*/
|
|
24
|
+
export type AskStreamEvent =
|
|
25
|
+
| AskStreamIntentEvent
|
|
26
|
+
| AskStreamRagSearchingEvent
|
|
27
|
+
| AskStreamRagRetrievedEvent
|
|
28
|
+
| AskStreamDeltaEvent
|
|
29
|
+
| AskStreamToolCallingEvent
|
|
30
|
+
| AskStreamToolResultEvent
|
|
31
|
+
| AskStreamLLMDebugEvent
|
|
32
|
+
| AskStreamToolDebugEvent
|
|
33
|
+
| AskStreamDoneEvent
|
|
34
|
+
| AskStreamErrorEvent;
|
|
35
|
+
|
|
36
|
+
export interface AskStreamIntentEvent {
|
|
37
|
+
type: 'intent';
|
|
38
|
+
intent: Intent;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AskStreamRagSearchingEvent {
|
|
42
|
+
type: 'rag.searching';
|
|
43
|
+
query: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AskStreamRagRetrievedEvent {
|
|
47
|
+
type: 'rag.retrieved';
|
|
48
|
+
chunks: Array<{
|
|
49
|
+
documentTitle: string;
|
|
50
|
+
score: number;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface AskStreamDeltaEvent {
|
|
55
|
+
type: 'delta';
|
|
56
|
+
/** Token (or token-like fragment) appended to the running answer. */
|
|
57
|
+
content: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface AskStreamToolCallingEvent {
|
|
61
|
+
type: 'tool.calling';
|
|
62
|
+
name: string;
|
|
63
|
+
args: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface AskStreamToolResultEvent {
|
|
67
|
+
type: 'tool.result';
|
|
68
|
+
name: string;
|
|
69
|
+
success: boolean;
|
|
70
|
+
durationMs: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Debug-only message frame describing one LLM chat-completion iteration.
|
|
75
|
+
*
|
|
76
|
+
* Emitted only when the request was made with `debug: true` AND the
|
|
77
|
+
* caller is authenticated as a console JWT user. Safe to ignore from
|
|
78
|
+
* non-debug consumers — the field never appears outside that path.
|
|
79
|
+
*/
|
|
80
|
+
export interface AskStreamLLMDebugEvent {
|
|
81
|
+
type: 'llm.debug';
|
|
82
|
+
/** Zero-based index in the orchestrator's tool loop. */
|
|
83
|
+
iteration: number;
|
|
84
|
+
/** Resolved model id, e.g. `gpt-4.1-mini-2025-04-14`. */
|
|
85
|
+
model: string;
|
|
86
|
+
/** Snapshot of the messages array sent INTO this iteration. */
|
|
87
|
+
messages: Array<{
|
|
88
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
89
|
+
content: string | null;
|
|
90
|
+
name?: string;
|
|
91
|
+
toolCallId?: string;
|
|
92
|
+
toolCalls?: Array<{
|
|
93
|
+
id: string;
|
|
94
|
+
type: 'function';
|
|
95
|
+
function: { name: string; arguments: string };
|
|
96
|
+
}>;
|
|
97
|
+
}>;
|
|
98
|
+
/** What the LLM emitted this iteration (text + tool-call requests). */
|
|
99
|
+
response: {
|
|
100
|
+
content: string;
|
|
101
|
+
finishReason: string;
|
|
102
|
+
toolCalls?: Array<{
|
|
103
|
+
id: string;
|
|
104
|
+
type: 'function';
|
|
105
|
+
function: { name: string; arguments: string };
|
|
106
|
+
}>;
|
|
107
|
+
};
|
|
108
|
+
usage: TokenUsage;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Debug-only frame describing one tool HTTP execution — the actual
|
|
113
|
+
* request EgoX sent to the tenant server and the response it received.
|
|
114
|
+
*
|
|
115
|
+
* Emitted only when the request was made with `debug: true` AND the
|
|
116
|
+
* caller is authenticated as a console JWT user.
|
|
117
|
+
*
|
|
118
|
+
* Sensitive header values (Authorization, X-Egox-Signature,
|
|
119
|
+
* X-Egox-Timestamp, and anything matching /token|secret|key|auth/i) are
|
|
120
|
+
* already redacted to `***` server-side before this frame is written.
|
|
121
|
+
*/
|
|
122
|
+
export interface AskStreamToolDebugEvent {
|
|
123
|
+
type: 'tool.debug';
|
|
124
|
+
name: string;
|
|
125
|
+
durationMs: number;
|
|
126
|
+
success: boolean;
|
|
127
|
+
/** What EgoX sent to the tenant server. */
|
|
128
|
+
request: {
|
|
129
|
+
method: string;
|
|
130
|
+
url: string;
|
|
131
|
+
headers: Record<string, string>;
|
|
132
|
+
body: unknown;
|
|
133
|
+
};
|
|
134
|
+
/** What came back. `statusCode` is null on a network exception. */
|
|
135
|
+
response: {
|
|
136
|
+
statusCode: number | null;
|
|
137
|
+
headers: Record<string, string>;
|
|
138
|
+
body: unknown;
|
|
139
|
+
error?: string;
|
|
140
|
+
};
|
|
141
|
+
/** Total number of attempts including the final one (1 + retries). */
|
|
142
|
+
attempts: number;
|
|
143
|
+
/**
|
|
144
|
+
* Provenance map of which tool-allowlisted headers were actually
|
|
145
|
+
* forwarded and from which source (`'body'` =
|
|
146
|
+
* `AskRequestBody.toolHeaders`, `'inbound'` = inbound HTTP
|
|
147
|
+
* forwarded by `tool.forwardHeaders` allowlist). Header VALUES
|
|
148
|
+
* are NOT included — they're already in `request.headers`
|
|
149
|
+
* (redacted there). Useful for debugging "why did/didn't my
|
|
150
|
+
* header get forwarded?" without leaking secrets a second time.
|
|
151
|
+
* Omitted when no headers were forwarded.
|
|
152
|
+
*/
|
|
153
|
+
forwardedHeaderSources?: Record<string, 'body' | 'inbound'>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface AskStreamDoneEvent {
|
|
157
|
+
type: 'done';
|
|
158
|
+
threadId: string;
|
|
159
|
+
/**
|
|
160
|
+
* Echo of `AskStreamRequestBody.externalThreadId` when one was
|
|
161
|
+
* supplied — same semantics as `AskResponseData.externalThreadId`.
|
|
162
|
+
* Lets streaming consumers correlate the SSE result back to their
|
|
163
|
+
* own conversation id without parsing the final `data` payload
|
|
164
|
+
* separately (Phase 6).
|
|
165
|
+
*/
|
|
166
|
+
externalThreadId?: string;
|
|
167
|
+
intent: Intent;
|
|
168
|
+
toolUsed: string | null;
|
|
169
|
+
ragChunksUsed: number;
|
|
170
|
+
model: string;
|
|
171
|
+
usage: TokenUsage;
|
|
172
|
+
/**
|
|
173
|
+
* Pending high-impact actions awaiting user approval (Path-A, DotCollab #8).
|
|
174
|
+
* Same semantics + shape as `AskResponseData.pendingActions` — surfaced on
|
|
175
|
+
* the stream's terminal event so streaming consumers can render the
|
|
176
|
+
* Approve/Reject card without parsing the final `data` payload separately.
|
|
177
|
+
*/
|
|
178
|
+
pendingActions?: Array<{ approvalId: string; toolName: string; summary: string }>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface AskStreamErrorEvent {
|
|
182
|
+
type: 'error';
|
|
183
|
+
message: string;
|
|
184
|
+
/** Machine-readable error code, e.g. `INVALID_INPUT`, `INTERNAL_SERVER_ERROR`. */
|
|
185
|
+
code?: string;
|
|
186
|
+
}
|