@ego-z/contracts 0.11.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 +244 -0
- package/src/envelope.d.ts +66 -0
- package/src/index.d.ts +94 -0
- package/src/mcp-connection.d.ts +49 -0
- package/src/mcp-token.d.ts +158 -0
- package/src/personality.d.ts +283 -0
- package/src/rag.d.ts +188 -0
- package/src/search.d.ts +23 -0
- package/src/stream.d.ts +202 -0
- package/src/tenant.d.ts +222 -0
- package/src/thread.d.ts +248 -0
- package/src/tool.d.ts +269 -0
- package/src/user-memory.d.ts +226 -0
package/src/tenant.d.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ego-z/contracts — `/egoz/tenants/*` wire types (project CRUD).
|
|
3
|
+
*
|
|
4
|
+
* `Tenant` is what the Console calls "Project" — same row, two names.
|
|
5
|
+
* The wire shape preserves `snake_case` field names because that's the
|
|
6
|
+
* actual JSON the backend has always emitted and the console has always
|
|
7
|
+
* consumed. Renaming to camelCase here would be a breaking wire change
|
|
8
|
+
* (every API caller would need to update) and is deliberately out of
|
|
9
|
+
* scope for the additive Phase 9 sweep. If/when we ever do that
|
|
10
|
+
* migration, this is the file the major-version bump touches.
|
|
11
|
+
*
|
|
12
|
+
* Drift cleaned up:
|
|
13
|
+
* - Backend `Tenant` used `Date` for `created_at` / `updated_at` /
|
|
14
|
+
* `attestation_signed_at`; wire and console already used ISO
|
|
15
|
+
* strings. Backend `formatTenant` now emits ISO via the same
|
|
16
|
+
* pattern as Tools and RAG.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Locked vocabularies (mirror DB CHECK constraints)
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Compliance tier (mirrors `egoz_tenants.compliance_tier` CHECK
|
|
25
|
+
* constraint, migration 010). Phase 1 services `'standard'` only;
|
|
26
|
+
* the rest are forward-compat for Phase 2.
|
|
27
|
+
*/
|
|
28
|
+
export type ComplianceTier =
|
|
29
|
+
| 'standard'
|
|
30
|
+
| 'pending_review'
|
|
31
|
+
| 'gdpr'
|
|
32
|
+
| 'hipaa'
|
|
33
|
+
| 'enterprise'
|
|
34
|
+
| 'pending_upgrade';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Data residency region (mirrors `egoz_tenants.data_residency_region`
|
|
38
|
+
* CHECK constraint, migration 010). Phase 1 deploys only to
|
|
39
|
+
* `'eu-west'`; the rest are forward-compat.
|
|
40
|
+
*/
|
|
41
|
+
export type DataResidencyRegion =
|
|
42
|
+
| 'us-east'
|
|
43
|
+
| 'us-west'
|
|
44
|
+
| 'eu-west'
|
|
45
|
+
| 'eu-central'
|
|
46
|
+
| 'ap-south'
|
|
47
|
+
| 'ap-east';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Operational tenant status (mirrors `egoz_tenants.status` CHECK
|
|
51
|
+
* constraint). The legacy `is_active` boolean still exists in
|
|
52
|
+
* Phase 1 and is NOT auto-synced with `status` — both fields are
|
|
53
|
+
* independent until Phase 1.5 deprecates `is_active`.
|
|
54
|
+
*/
|
|
55
|
+
export type TenantStatus =
|
|
56
|
+
| 'active'
|
|
57
|
+
| 'pending_review'
|
|
58
|
+
| 'flagged'
|
|
59
|
+
| 'suspended'
|
|
60
|
+
| 'terminated';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Billing plan (Phase 1.5, two-plan model — migration 035). Drives usage
|
|
64
|
+
* quotas (e.g. monthly /ask limit).
|
|
65
|
+
*
|
|
66
|
+
* - `id_ego` — "Id Ego": free, pay-as-you-go via BYOK, capped limits.
|
|
67
|
+
* Default for self-service signup.
|
|
68
|
+
* - `superego` — "Superego": $20/mo, higher (but still capped) limits.
|
|
69
|
+
*/
|
|
70
|
+
export type TenantPlan = 'id_ego' | 'superego';
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Industry classification driving the signup gate (Phase 1.5+).
|
|
74
|
+
* The regulated entries (`'healthcare'`, `'finance'`, `'insurance'`,
|
|
75
|
+
* `'government'`, `'legal'`) auto-route new tenants to
|
|
76
|
+
* `status: 'pending_review'`.
|
|
77
|
+
*/
|
|
78
|
+
export type TenantIndustry =
|
|
79
|
+
| 'saas'
|
|
80
|
+
| 'ecommerce'
|
|
81
|
+
| 'marketing'
|
|
82
|
+
| 'education'
|
|
83
|
+
| 'media'
|
|
84
|
+
| 'travel'
|
|
85
|
+
| 'real_estate'
|
|
86
|
+
| 'productivity'
|
|
87
|
+
| 'other'
|
|
88
|
+
| 'healthcare'
|
|
89
|
+
| 'finance'
|
|
90
|
+
| 'insurance'
|
|
91
|
+
| 'government'
|
|
92
|
+
| 'legal';
|
|
93
|
+
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// TenantWire — the canonical row shape (snake_case on the wire)
|
|
96
|
+
// ============================================================================
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Wire-format tenant row. Returned by every `/egoz/tenants/*` response.
|
|
100
|
+
*
|
|
101
|
+
* **Field naming.** This is the only wire shape in the contracts
|
|
102
|
+
* package that uses `snake_case`. It's preserved verbatim from the
|
|
103
|
+
* legacy backend → JSON path because the Console already consumes
|
|
104
|
+
* `snake_case` here too. Treat the inconsistency as fixed-by-history,
|
|
105
|
+
* not a goal — net change would be breaking, with zero behavioural
|
|
106
|
+
* value.
|
|
107
|
+
*/
|
|
108
|
+
export interface TenantWire {
|
|
109
|
+
id: string;
|
|
110
|
+
name: string;
|
|
111
|
+
/** URL-safe slug, unique per parent (when `parent_tenant_id` is set). */
|
|
112
|
+
slug: string;
|
|
113
|
+
description?: string;
|
|
114
|
+
is_active: boolean;
|
|
115
|
+
/** ISO 8601 timestamp. */
|
|
116
|
+
created_at: string;
|
|
117
|
+
/** ISO 8601 timestamp. */
|
|
118
|
+
updated_at: string;
|
|
119
|
+
|
|
120
|
+
// Phase 1 compliance posture (migration 010) ----------------------
|
|
121
|
+
compliance_tier: ComplianceTier;
|
|
122
|
+
data_residency_region: DataResidencyRegion;
|
|
123
|
+
/**
|
|
124
|
+
* UUID of the parent tenant when this row is a sub-project. `null`
|
|
125
|
+
* for top-level tenants. Sub-projects share their parent's
|
|
126
|
+
* `compliance_tier` for billing purposes (enforced at the service
|
|
127
|
+
* layer, not the DB).
|
|
128
|
+
*/
|
|
129
|
+
parent_tenant_id: string | null;
|
|
130
|
+
industry: TenantIndustry | null;
|
|
131
|
+
/** ISO 8601 timestamp. `null` until the operator signs an attestation. */
|
|
132
|
+
attestation_signed_at: string | null;
|
|
133
|
+
attestation_version: string | null;
|
|
134
|
+
status: TenantStatus;
|
|
135
|
+
/** Billing plan (migrations 023/035). Drives usage quotas. Default 'id_ego'. */
|
|
136
|
+
plan: TenantPlan;
|
|
137
|
+
|
|
138
|
+
// Time-boxed debug mode (migration 037). Populated on the LIST response
|
|
139
|
+
// (joined from tenant_configs); omitted where the query does not join it.
|
|
140
|
+
// `debug_enabled` is resolved server-side as `debug_until > NOW()`.
|
|
141
|
+
debug_enabled?: boolean;
|
|
142
|
+
/** ISO 8601 expiry backing `debug_enabled`; null when off/expired. */
|
|
143
|
+
debug_until?: string | null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Request bodies (what the client SENDS)
|
|
148
|
+
// ============================================================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Wire body of `POST /egoz/tenants`.
|
|
152
|
+
*
|
|
153
|
+
* Notable absences:
|
|
154
|
+
* - `compliance_tier`, `status` — server-derived from `industry`
|
|
155
|
+
* at signup (Phase 1C / Strategy A).
|
|
156
|
+
* Non-regulated industry →
|
|
157
|
+
* `'standard'` + `'active'`;
|
|
158
|
+
* regulated industry (healthcare,
|
|
159
|
+
* finance, insurance, government,
|
|
160
|
+
* legal) → `'pending_review'` on
|
|
161
|
+
* both. Manual tier moves stay an
|
|
162
|
+
* admin operation via
|
|
163
|
+
* `TenantUpdateBody`.
|
|
164
|
+
* - `is_active`, timestamps — server-managed.
|
|
165
|
+
*/
|
|
166
|
+
export interface TenantCreateBody {
|
|
167
|
+
name: string;
|
|
168
|
+
slug?: string;
|
|
169
|
+
description?: string;
|
|
170
|
+
|
|
171
|
+
industry?: TenantIndustry;
|
|
172
|
+
data_residency_region?: DataResidencyRegion;
|
|
173
|
+
parent_tenant_id?: string | null;
|
|
174
|
+
/** ISO 8601 timestamp string the operator submits at signup. */
|
|
175
|
+
attestation_signed_at?: string;
|
|
176
|
+
attestation_version?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Wire body of `PUT /egoz/tenants/:tenantId`. Every field is optional —
|
|
181
|
+
* the backend applies `COALESCE`-style partial updates. `tenantId` is
|
|
182
|
+
* the URL param, not the body.
|
|
183
|
+
*
|
|
184
|
+
* `compliance_tier` and `status` are admin operations; Phase 1 has no
|
|
185
|
+
* role gating on these — Phase 1.5 will introduce admin-only
|
|
186
|
+
* enforcement.
|
|
187
|
+
*/
|
|
188
|
+
export interface TenantUpdateBody {
|
|
189
|
+
name?: string;
|
|
190
|
+
description?: string;
|
|
191
|
+
is_active?: boolean;
|
|
192
|
+
|
|
193
|
+
industry?: TenantIndustry;
|
|
194
|
+
data_residency_region?: DataResidencyRegion;
|
|
195
|
+
parent_tenant_id?: string | null;
|
|
196
|
+
compliance_tier?: ComplianceTier;
|
|
197
|
+
status?: TenantStatus;
|
|
198
|
+
attestation_signed_at?: string;
|
|
199
|
+
attestation_version?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Response data shapes (carried inside `EgozApiResponse.data`)
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
export interface TenantListResponseData {
|
|
207
|
+
tenants: TenantWire[];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface TenantGetResponseData {
|
|
211
|
+
tenant: TenantWire;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Returned by `POST /egoz/tenants`. Wrapping the row in `tenant`
|
|
216
|
+
* (rather than returning it raw) matches the rest of the create
|
|
217
|
+
* surfaces and keeps room for additive metadata (creation source,
|
|
218
|
+
* downstream side effects, …) without a major version bump.
|
|
219
|
+
*/
|
|
220
|
+
export interface TenantCreatedResponseData {
|
|
221
|
+
tenant: TenantWire;
|
|
222
|
+
}
|
package/src/thread.d.ts
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ego-z/contracts — `/egoz/threads/*` and
|
|
3
|
+
* `/egoz/tenants/:tenantId/threads/*` wire types.
|
|
4
|
+
*
|
|
5
|
+
* The conversation memory surface. `Thread` rows are produced by every
|
|
6
|
+
* `/ask` turn (via `ThreadService.getOrCreateThread`) and read back
|
|
7
|
+
* via the admin threads list / detail routes.
|
|
8
|
+
*
|
|
9
|
+
* Phase 6's `externalThreadId` already lives in `AskRequestBody` /
|
|
10
|
+
* `AskResponseData` / `AskStreamDoneEvent` (in `ask.d.ts` /
|
|
11
|
+
* `stream.d.ts`). This file lifts the FULL `Thread` and `Message`
|
|
12
|
+
* row shapes — what the threads-admin endpoints return — into the
|
|
13
|
+
* contracts package so the console mirror can't drift.
|
|
14
|
+
*
|
|
15
|
+
* Drift cleaned up:
|
|
16
|
+
* - Backend `Thread` and `Message` used `Date` for `createdAt` /
|
|
17
|
+
* `updatedAt`; wire and console already used ISO strings.
|
|
18
|
+
* `formatThread` and `formatMessage` now emit ISO to match.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { Intent } from './envelope';
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Locked vocabularies
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
/** Role of a message in the conversation turn. */
|
|
28
|
+
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Why a turn was stamped with `failedRecovery: true` by the
|
|
32
|
+
* orchestrator. Mirrors the CHECK constraint on
|
|
33
|
+
* `egoz_messages.failure_reason` (migration 014, Phase 5 / Layer 5).
|
|
34
|
+
* Adding a new entry requires a migration + orchestrator change in
|
|
35
|
+
* lockstep — the audit field exists to be queryable, not free-form.
|
|
36
|
+
*/
|
|
37
|
+
export type MessageFailureReason =
|
|
38
|
+
| 'tool_retry_storm'
|
|
39
|
+
| 'iteration_cap'
|
|
40
|
+
| 'max_calls_per_turn'
|
|
41
|
+
| 'unrecoverable_error';
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Supporting shapes
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Tool-call request emitted by an `assistant` message. Shape matches
|
|
49
|
+
* the OpenAI Chat Completions tool-call envelope verbatim — that's
|
|
50
|
+
* what the orchestrator persists. `arguments` is a JSON string the
|
|
51
|
+
* caller must `JSON.parse` if they want the structured value;
|
|
52
|
+
* EgoZ doesn't decode it on the wire because it's already
|
|
53
|
+
* round-tripped through the LLM as text.
|
|
54
|
+
*/
|
|
55
|
+
export interface ToolCallWire {
|
|
56
|
+
id: string;
|
|
57
|
+
type: 'function';
|
|
58
|
+
function: {
|
|
59
|
+
name: string;
|
|
60
|
+
arguments: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// ThreadWire — the canonical row shape
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Wire-format thread row. Returned by every threads-admin response and
|
|
70
|
+
* embedded in `ThreadWithMessagesWire`.
|
|
71
|
+
*
|
|
72
|
+
* `externalThreadId` is populated when the caller supplied one on the
|
|
73
|
+
* `/ask` that minted the row (Phase 6); `null` for legacy threads and
|
|
74
|
+
* for any caller that uses only the EgoZ UUID path.
|
|
75
|
+
*/
|
|
76
|
+
export interface ThreadWire {
|
|
77
|
+
id: string;
|
|
78
|
+
tenantId: string;
|
|
79
|
+
externalUserId: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* Consumer-supplied conversation identifier (Phase 6). `null` for
|
|
82
|
+
* threads created before the column existed and for any caller
|
|
83
|
+
* that didn't supply one. Uniqueness is enforced per
|
|
84
|
+
* `(tenantId, externalThreadId)` among non-NULL rows by the
|
|
85
|
+
* `idx_egoz_threads_tenant_ext` partial unique index — see
|
|
86
|
+
* migration 017.
|
|
87
|
+
*/
|
|
88
|
+
externalThreadId: string | null;
|
|
89
|
+
title: string | null;
|
|
90
|
+
metadata: Record<string, unknown>;
|
|
91
|
+
isActive: boolean;
|
|
92
|
+
/** ISO 8601 timestamp. */
|
|
93
|
+
createdAt: string;
|
|
94
|
+
/** ISO 8601 timestamp. */
|
|
95
|
+
updatedAt: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Thread row plus aggregate stats. Returned by the admin threads list
|
|
100
|
+
* endpoint so the operator-facing table can sort by activity without
|
|
101
|
+
* an N+1 fetch.
|
|
102
|
+
*/
|
|
103
|
+
export interface ThreadWithStatsWire extends ThreadWire {
|
|
104
|
+
messageCount: number;
|
|
105
|
+
totalTokens: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// MessageWire — the canonical message-row shape
|
|
110
|
+
// ============================================================================
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Wire-format message row. Carries the full per-turn audit trail —
|
|
114
|
+
* the LLM iteration's prompt/completion token split, the model id,
|
|
115
|
+
* the intent classification, the RAG context that was injected, and
|
|
116
|
+
* the Phase 5 failure-recovery flags.
|
|
117
|
+
*
|
|
118
|
+
* `toolCalls` is populated only on `role: 'assistant'` rows that
|
|
119
|
+
* requested a tool. `toolCallId` + `toolName` are populated only on
|
|
120
|
+
* `role: 'tool'` result rows.
|
|
121
|
+
*/
|
|
122
|
+
export interface MessageWire {
|
|
123
|
+
id: string;
|
|
124
|
+
threadId: string;
|
|
125
|
+
tenantId: string;
|
|
126
|
+
role: MessageRole;
|
|
127
|
+
content: string | null;
|
|
128
|
+
toolCalls: ToolCallWire[] | null;
|
|
129
|
+
toolCallId: string | null;
|
|
130
|
+
toolName: string | null;
|
|
131
|
+
intent: Intent | null;
|
|
132
|
+
ragContext: Record<string, unknown> | null;
|
|
133
|
+
promptTokens: number | null;
|
|
134
|
+
completionTokens: number | null;
|
|
135
|
+
totalTokens: number | null;
|
|
136
|
+
model: string | null;
|
|
137
|
+
/** Echo of `AskRequestBody.metadata` for audit. */
|
|
138
|
+
metadata: Record<string, unknown> | null;
|
|
139
|
+
/**
|
|
140
|
+
* `true` when this row's `content` was deliberately dropped under
|
|
141
|
+
* no-store (metadata-only) persistence — see
|
|
142
|
+
* `AskRequestBody.noStore` and the tenant's `persistMessageContent`
|
|
143
|
+
* setting (#5). Distinguishes an intentional NULL (the conversation
|
|
144
|
+
* text was never stored) from an incidental empty turn. Always
|
|
145
|
+
* `false` for tenants that persist content normally.
|
|
146
|
+
*/
|
|
147
|
+
contentRedacted: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* `true` when this turn triggered a Phase 5 tool-retry-storm
|
|
150
|
+
* backstop (dedup ≥ MAX_DUPLICATE_CALLS_BEFORE_FLAG / per-tool
|
|
151
|
+
* cap / outer iteration cap) or ended on an unrecoverable error
|
|
152
|
+
* class. Always `false` for non-assistant rows. Phase 5 /
|
|
153
|
+
* Layer 5 — drives the Tool Health "bad turns" filter.
|
|
154
|
+
*/
|
|
155
|
+
failedRecovery: boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Dominant cause when `failedRecovery === true`. `null`
|
|
158
|
+
* otherwise. See `MessageFailureReason` for the locked
|
|
159
|
+
* vocabulary.
|
|
160
|
+
*/
|
|
161
|
+
failureReason: MessageFailureReason | null;
|
|
162
|
+
/**
|
|
163
|
+
* Manual operator incident flag on this turn — the CURRENT state
|
|
164
|
+
* (latest by `flaggedAt`; at most one `open` at a time). `null`/absent
|
|
165
|
+
* when the turn was never flagged. Additive (v0.5.2); populated only by
|
|
166
|
+
* the thread-detail read path, never on the /ask hot path. See
|
|
167
|
+
* `MessageIncidentWire`.
|
|
168
|
+
*/
|
|
169
|
+
incident?: MessageIncidentWire | null;
|
|
170
|
+
/** ISO 8601 timestamp. */
|
|
171
|
+
createdAt: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Returned by the thread-detail endpoint. The full conversation —
|
|
176
|
+
* row + every message in chronological order.
|
|
177
|
+
*/
|
|
178
|
+
export interface ThreadWithMessagesWire {
|
|
179
|
+
thread: ThreadWire;
|
|
180
|
+
messages: MessageWire[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ============================================================================
|
|
184
|
+
// Response data shapes (carried inside `EgozApiResponse.data`)
|
|
185
|
+
// ============================================================================
|
|
186
|
+
|
|
187
|
+
export interface ThreadListResponseData {
|
|
188
|
+
threads: ThreadWithStatsWire[];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface ThreadGetResponseData extends ThreadWithMessagesWire {}
|
|
192
|
+
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// Message incidents — manual operator flagging of a turn
|
|
195
|
+
//
|
|
196
|
+
// The manual counterpart to the auto-set `failedRecovery`/`failureReason`
|
|
197
|
+
// "bad turn" flags: an operator reviewing a conversation can flag a single
|
|
198
|
+
// turn as an incident (with a reason + optional note), then later resolve it.
|
|
199
|
+
// Metadata only — never message content. Stored in `egoz_message_incidents`
|
|
200
|
+
// (migration 040); at most one `open` incident per message.
|
|
201
|
+
// ============================================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Why an operator flagged a turn. Locked vocabulary — mirrors the
|
|
205
|
+
* migration-040 CHECK constraint; adding a value requires a migration + this
|
|
206
|
+
* type in lockstep so the UI, filter SQL and DB can't drift.
|
|
207
|
+
*/
|
|
208
|
+
export type MessageIncidentReason =
|
|
209
|
+
| 'wrong_answer'
|
|
210
|
+
| 'hallucination'
|
|
211
|
+
| 'tool_failure'
|
|
212
|
+
| 'unsafe_content'
|
|
213
|
+
| 'policy_violation'
|
|
214
|
+
| 'other';
|
|
215
|
+
|
|
216
|
+
/** Incident lifecycle. `open` on flag; `resolved` once an operator clears it. */
|
|
217
|
+
export type MessageIncidentStatus = 'open' | 'resolved';
|
|
218
|
+
|
|
219
|
+
/** A manual incident flag raised on a single message/turn. Metadata only. */
|
|
220
|
+
export interface MessageIncidentWire {
|
|
221
|
+
id: string;
|
|
222
|
+
tenantId: string;
|
|
223
|
+
threadId: string;
|
|
224
|
+
messageId: string;
|
|
225
|
+
reason: MessageIncidentReason;
|
|
226
|
+
/** Optional free-text note from the operator who flagged. */
|
|
227
|
+
note: string | null;
|
|
228
|
+
status: MessageIncidentStatus;
|
|
229
|
+
/** User id who flagged (from the validated session), when known. */
|
|
230
|
+
flaggedBy: string | null;
|
|
231
|
+
/** ISO 8601 timestamp. */
|
|
232
|
+
flaggedAt: string;
|
|
233
|
+
/** User id who resolved; `null` while open. */
|
|
234
|
+
resolvedBy: string | null;
|
|
235
|
+
/** ISO 8601 timestamp; `null` while open. */
|
|
236
|
+
resolvedAt: string | null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Body for `POST …/threads/:threadId/messages/:messageId/incident` (flag). */
|
|
240
|
+
export interface FlagMessageIncidentBody {
|
|
241
|
+
reason: MessageIncidentReason;
|
|
242
|
+
note?: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Response data for both the flag and resolve endpoints. */
|
|
246
|
+
export interface MessageIncidentResponseData {
|
|
247
|
+
incident: MessageIncidentWire;
|
|
248
|
+
}
|