@vinaverse/server 0.1.0-alpha.7 → 0.1.0-alpha.9

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.
@@ -73,6 +73,30 @@ interface paths {
73
73
  patch?: never;
74
74
  trace?: never;
75
75
  };
76
+ "/v1/conversations": {
77
+ parameters: {
78
+ query?: never;
79
+ header?: never;
80
+ path?: never;
81
+ cookie?: never;
82
+ };
83
+ /**
84
+ * A person's past conversations with one agent, newest activity first
85
+ * @description v1-draft.21 (VIN-246): the conversations a history screen lists, for one subject and one agent, on one side of the app (`experience_mode`, and for a business `business_scope_id`, as the conversation was bound when it started). Newest activity first; ties by `id`.
86
+ * **Access.** A service key only, never a client secret: the app asks the tenant's backend, which checks the person and calls this. The key needs `conversations:read` (a key without scopes has every scope) and sees its own tenant and environment only.
87
+ * **What is listed.** Only what the tenant's `transcript_retention` still keeps: a conversation past it, a deleted one (`deleteConversation`) or an erased subject's is never listed, nor one where nothing was said (a session opened and left). A subject Vinaverse holds nothing for gets an empty page, the same as one with no conversations, so the answer never says whether a subject exists.
88
+ * **The title** is deterministic and never the person's words: from the conversation's last search intent (`title_source: intent`, for example "Haircut · Los Angeles", in the subject's locale), else the date it started (`title_source: date`). There is no preview of the messages.
89
+ * **Paging.** `next_cursor` is opaque and signed. It is bound to the filters, the key's tenant and environment, and expires after 24 hours: a cursor changed, used with other filters or expired is `400 invalid_request` at `/cursor`, and the caller starts again without it. An outage is `503 unavailable` (retryable), never an empty page: the app does not take it as "no conversations".
90
+ */
91
+ get: operations["listConversations"];
92
+ put?: never;
93
+ post?: never;
94
+ delete?: never;
95
+ options?: never;
96
+ head?: never;
97
+ patch?: never;
98
+ trace?: never;
99
+ };
76
100
  "/v1/conversations/{conversation_id}": {
77
101
  parameters: {
78
102
  query?: never;
@@ -95,6 +119,42 @@ interface paths {
95
119
  get: operations["getConversation"];
96
120
  put?: never;
97
121
  post?: never;
122
+ /**
123
+ * Delete one of a person's conversations, everywhere
124
+ * @description v1-draft.21 (VIN-246): the person deletes a conversation from their history, through the tenant's backend. A service key with `conversations:write`, for its own tenant and environment; `subject_id` must be the conversation's subject.
125
+ * **What it does, before it answers.** - Ends the conversation's open sessions: their sockets get `session.closed` with `reason: deleted` and
126
+ * close with `4403` (a client that does not know `deleted` reads it as `revoked`). Their status ends as
127
+ * `deleted`.
128
+ * - Blanks every copy of the conversation's messages, cards, screening texts and state (and the guided flow's
129
+ * answers), across both sides of the app, and leaves no title or count behind.
130
+ * - Fences late writes: a turn still running, a webhook retry or a worker job that finishes after the delete
131
+ * records nothing for it (a deletion barrier, kept as long as the longest session could run).
132
+ * - Frees its `conversation_key`: a session with the same key afterwards starts a new conversation.
133
+ * **Answers.** `200` with the number of sessions revoked. An unknown id, another tenant's, environment's or subject's, or one already deleted or erased: `404 not_found`, the same answer for each, so it never says whether the conversation exists. Deleting is not erasing the subject (`eraseSubject`): the person's other conversations and memory stay.
134
+ */
135
+ delete: operations["deleteConversation"];
136
+ options?: never;
137
+ head?: never;
138
+ patch?: never;
139
+ trace?: never;
140
+ };
141
+ "/v1/conversations/{conversation_id}/messages": {
142
+ parameters: {
143
+ query?: never;
144
+ header?: never;
145
+ path?: never;
146
+ cookie?: never;
147
+ };
148
+ /**
149
+ * One past conversation, as one ordered timeline of messages and cards
150
+ * @description v1-draft.21 (VIN-246): what a history screen draws when the person opens a past conversation. A service key with `conversations:read`, for its own tenant and environment; `subject_id` must be the conversation's subject.
151
+ * **The timeline.** One list of messages and the cards their turns drew, in the order they happened, each with an `id` that is stable and unique within the conversation. The first page is the newest; within a page, oldest first; `next_cursor` pages toward older items. A message carries `event_id`, the identifier its live event gave it (as `TranscriptItem.id`: an `assistant` message's `turn_id`, a `person` message's `client_event_id`, a `staff` message's `message_id`), so an app merges what it drew live, or a resumed `session.ready.transcript`, into the fetched history by `role` and `event_id` instead of replacing either. An input the runtime never recorded is not in it, as in the transcript.
152
+ * **Cards from history are read-only.** An app draws their actions disabled: a past slot, price or availability is not checked again, so a tap would act on stale data. The person asks again in the conversation, and a fresh turn draws fresh cards.
153
+ * **What is kept.** Only what the tenant's `transcript_retention` still keeps; a conversation past it is `410 conversation_expired`. An unknown id, another tenant's, environment's or subject's, or a deleted or erased one: `404 not_found`, the same answer for each. A cursor changed, used for another conversation or expired (24 hours) is `400 invalid_request` at `/cursor`. An outage is `503 unavailable`, never an empty timeline.
154
+ */
155
+ get: operations["listConversationMessages"];
156
+ put?: never;
157
+ post?: never;
98
158
  delete?: never;
99
159
  options?: never;
100
160
  head?: never;
@@ -144,7 +204,7 @@ interface paths {
144
204
  put?: never;
145
205
  /**
146
206
  * A fresh client secret for an open session
147
- * @description A service key with the `sessions:write` scope gets a new connect secret for an open session, for an app that missed the connect window or connects from another device (whose connection then replaces the open one, with close code 4409). The previous secret no longer authenticates a new connection or an SSE turn. A socket already open stays open and keeps its session: refreshing never drops the person's live connection. To cut it off, revoke the session (`revokeSession`). An ended session is `409 session_closed`.
207
+ * @description A service key with the `sessions:write` scope gets a new connect secret for an open session, for an app that missed the connect window or connects from another device (whose connection then replaces the open one, with close code 4409). The previous secret no longer authenticates a new connection or an SSE turn. A socket already open stays open and keeps its session: refreshing never drops the person's live connection. To cut it off, revoke the session (`revokeSession`). An ended session is `409 session_closed`. With an optional `Idempotency-Key` (declared in v1-draft.22), a retry within 24 hours answers the secret first issued for that key instead of a newer one.
148
208
  */
149
209
  post: operations["refreshClientSecret"];
150
210
  delete?: never;
@@ -1484,10 +1544,10 @@ interface components {
1484
1544
  turns: number;
1485
1545
  handoff_ticket_ids?: string[];
1486
1546
  /**
1487
- * @description Why the session ended. `server_restart` is reserved and never appears here: it never ends a session (`docs/realtime-protocol.md` §2).
1547
+ * @description Why the session ended. `server_restart` is reserved and never appears here: it never ends a session (`docs/realtime-protocol.md` §2). `deleted` (v1-draft.21): its conversation was deleted from history.
1488
1548
  * @enum {string}
1489
1549
  */
1490
- end_reason?: "expired" | "revoked" | "limit_reached" | "idle" | "server_restart" | "user_left";
1550
+ end_reason?: "expired" | "revoked" | "limit_reached" | "idle" | "server_restart" | "user_left" | "deleted";
1491
1551
  /** Format: date-time */
1492
1552
  created_at: string;
1493
1553
  /** Format: date-time */
@@ -1960,6 +2020,83 @@ interface components {
1960
2020
  /** Format: date-time */
1961
2021
  at: string;
1962
2022
  };
2023
+ ConversationPage: {
2024
+ data: components["schemas"]["ConversationSummary"][];
2025
+ next_cursor: string | null;
2026
+ };
2027
+ /** @description v1-draft.21: one past conversation as a history screen lists it. No message text: the title is from the conversation's last search intent or its date, never the person's words. */
2028
+ ConversationSummary: {
2029
+ id: components["schemas"]["ConversationId"];
2030
+ agent: string;
2031
+ experience_mode: components["schemas"]["ExperienceMode"];
2032
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
2033
+ title: string;
2034
+ /**
2035
+ * @description `intent`: the last search intent (service and place); `date`: the day it started
2036
+ * @enum {string}
2037
+ */
2038
+ title_source: "intent" | "date";
2039
+ /** Format: date-time */
2040
+ started_at: string;
2041
+ /** Format: date-time */
2042
+ last_activity_at: string;
2043
+ /** @description the messages its timeline holds (cards not counted) */
2044
+ message_count: number;
2045
+ /**
2046
+ * @description `open`: a session can resume it; `ended`: it can only be read
2047
+ * @enum {string}
2048
+ */
2049
+ state: "open" | "ended";
2050
+ };
2051
+ TimelinePage: {
2052
+ data: components["schemas"]["TimelineItem"][];
2053
+ /** @description the next older page; null at the conversation's start */
2054
+ next_cursor: string | null;
2055
+ };
2056
+ /**
2057
+ * @description v1-draft.21: one item of a past conversation, a message or a card its turn drew. `id` is stable and unique within the conversation; a message's `event_id` is its live event's identifier (`TranscriptItem.id`), the key an app merges live and resumed messages by, with `role`. A card is read-only in history.
2058
+ * Unlike `session.ready.transcript`, the history holds a guardrail's refusals: the person's message a guardrail refused and the fixed line said instead of an answer both carry `refusal: true`, so the app draws them as it drew them live (muted, never offered again). A `proposal` card carries `proposal_outcome`, what became of it.
2059
+ */
2060
+ TimelineItem: {
2061
+ /** @constant */
2062
+ type: "message";
2063
+ id: string;
2064
+ /**
2065
+ * @description a client tolerates a role it does not know, as in `TranscriptItem`
2066
+ * @enum {string}
2067
+ */
2068
+ role: "person" | "assistant" | "staff";
2069
+ text: string;
2070
+ /** Format: date-time */
2071
+ at: string;
2072
+ /** @description absent on a `person` message sent without a `client_event_id` */
2073
+ event_id?: string;
2074
+ turn_id?: string;
2075
+ /** @description `assistant` only, present only when true: the reply stopped before it finished */
2076
+ interrupted?: boolean;
2077
+ /**
2078
+ * @description Present only when true: a guardrail refused this turn. On a `person` message, the text it refused (as recorded, card-like digits masked); on an `assistant` message, the fixed line said instead of an answer.
2079
+ * @constant
2080
+ */
2081
+ refusal?: true;
2082
+ } | {
2083
+ /** @constant */
2084
+ type: "card";
2085
+ id: string;
2086
+ turn_id: string;
2087
+ /** Format: date-time */
2088
+ at: string;
2089
+ card: components["schemas"]["Card"];
2090
+ /**
2091
+ * @description A `proposal` card only, always present on one: the outcome the app reported for it (`ui.action` `confirmed`, `declined`, `failed` or `expired`), or `pending` while none was reported. Draw it as settled; a past proposal is never confirmed from history.
2092
+ * @enum {string}
2093
+ */
2094
+ proposal_outcome?: "pending" | "confirmed" | "declined" | "failed" | "expired";
2095
+ };
2096
+ ConversationDeleted: {
2097
+ conversation_id: components["schemas"]["ConversationId"];
2098
+ sessions_revoked: number;
2099
+ };
1963
2100
  /** @description A time slot the person picked on a `time_slots` card (v1-draft.17, `docs/realtime-protocol.md` §6): the slot's `id`, and the `call_id` of the tool call the card came from (the card's `source.call_id`), so the runtime checks the pick against the evidence it holds for that call. Both are copied from the card; never built by the app. */
1964
2101
  SlotSelection: {
1965
2102
  id: string;
@@ -2256,10 +2393,10 @@ interface components {
2256
2393
  /** @constant */
2257
2394
  type: "session.closed";
2258
2395
  /**
2259
- * @description `replaced`: a newer session of the same conversation was created (close code `4409`)
2396
+ * @description `replaced`: a newer session of the same conversation was created (close code `4409`). `deleted` (v1-draft.21): the person deleted the conversation from their history (`deleteConversation`, close code `4403`); drop it from the app's store and never resume it. A client that does not know `deleted` reads it as `revoked`, as any unknown reason.
2260
2397
  * @enum {string}
2261
2398
  */
2262
- reason: "expired" | "revoked" | "limit_reached" | "idle" | "server_restart" | "replaced";
2399
+ reason: "expired" | "revoked" | "limit_reached" | "idle" | "server_restart" | "replaced" | "deleted";
2263
2400
  } | {
2264
2401
  /** @constant */
2265
2402
  type: "ui.answer.recorded";
@@ -2838,6 +2975,8 @@ interface components {
2838
2975
  };
2839
2976
  parameters: {
2840
2977
  IdempotencyKey: string;
2978
+ /** @description Accepted, not required (declared in v1-draft.22). Scoped to the tenant and environment: the same key and request within 24 hours answers the first success again (`Idempotent-Replayed: true`); the same key with another request is `409 idempotency_conflict`. */
2979
+ OptionalIdempotencyKey: string;
2841
2980
  MediaJobId: string;
2842
2981
  ConversationId: components["schemas"]["ConversationId"];
2843
2982
  SessionId: string;
@@ -2913,6 +3052,39 @@ interface operations {
2913
3052
  503: components["responses"]["Problem"];
2914
3053
  };
2915
3054
  };
3055
+ listConversations: {
3056
+ parameters: {
3057
+ query: {
3058
+ subject_id: components["schemas"]["SubjectId"];
3059
+ agent: string;
3060
+ /** @description the side of the app; left out, the agent's template's */
3061
+ experience_mode?: components["schemas"]["ExperienceMode"];
3062
+ /** @description the business the person acts for; only with `experience_mode=business` */
3063
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
3064
+ limit?: number;
3065
+ cursor?: string;
3066
+ };
3067
+ header?: never;
3068
+ path?: never;
3069
+ cookie?: never;
3070
+ };
3071
+ requestBody?: never;
3072
+ responses: {
3073
+ /** @description Newest activity first. */
3074
+ 200: {
3075
+ headers: {
3076
+ [name: string]: unknown;
3077
+ };
3078
+ content: {
3079
+ "application/json": components["schemas"]["ConversationPage"];
3080
+ };
3081
+ };
3082
+ 400: components["responses"]["Problem"];
3083
+ 401: components["responses"]["Problem"];
3084
+ 403: components["responses"]["Problem"];
3085
+ 503: components["responses"]["Problem"];
3086
+ };
3087
+ };
2916
3088
  getConversation: {
2917
3089
  parameters: {
2918
3090
  query?: never;
@@ -2939,6 +3111,66 @@ interface operations {
2939
3111
  410: components["responses"]["Problem"];
2940
3112
  };
2941
3113
  };
3114
+ deleteConversation: {
3115
+ parameters: {
3116
+ query: {
3117
+ subject_id: components["schemas"]["SubjectId"];
3118
+ };
3119
+ header?: never;
3120
+ path: {
3121
+ conversation_id: components["parameters"]["ConversationId"];
3122
+ };
3123
+ cookie?: never;
3124
+ };
3125
+ requestBody?: never;
3126
+ responses: {
3127
+ /** @description Deleted. */
3128
+ 200: {
3129
+ headers: {
3130
+ [name: string]: unknown;
3131
+ };
3132
+ content: {
3133
+ "application/json": components["schemas"]["ConversationDeleted"];
3134
+ };
3135
+ };
3136
+ 401: components["responses"]["Problem"];
3137
+ 403: components["responses"]["Problem"];
3138
+ 404: components["responses"]["Problem"];
3139
+ 503: components["responses"]["Problem"];
3140
+ };
3141
+ };
3142
+ listConversationMessages: {
3143
+ parameters: {
3144
+ query: {
3145
+ subject_id: components["schemas"]["SubjectId"];
3146
+ limit?: number;
3147
+ cursor?: string;
3148
+ };
3149
+ header?: never;
3150
+ path: {
3151
+ conversation_id: components["parameters"]["ConversationId"];
3152
+ };
3153
+ cookie?: never;
3154
+ };
3155
+ requestBody?: never;
3156
+ responses: {
3157
+ /** @description The newest page first; oldest first within a page. */
3158
+ 200: {
3159
+ headers: {
3160
+ [name: string]: unknown;
3161
+ };
3162
+ content: {
3163
+ "application/json": components["schemas"]["TimelinePage"];
3164
+ };
3165
+ };
3166
+ 400: components["responses"]["Problem"];
3167
+ 401: components["responses"]["Problem"];
3168
+ 403: components["responses"]["Problem"];
3169
+ 404: components["responses"]["Problem"];
3170
+ 410: components["responses"]["Problem"];
3171
+ 503: components["responses"]["Problem"];
3172
+ };
3173
+ };
2942
3174
  getSession: {
2943
3175
  parameters: {
2944
3176
  query?: never;
@@ -2965,7 +3197,10 @@ interface operations {
2965
3197
  revokeSession: {
2966
3198
  parameters: {
2967
3199
  query?: never;
2968
- header?: never;
3200
+ header?: {
3201
+ /** @description Accepted, not required (declared in v1-draft.22). Scoped to the tenant and environment: the same key and request within 24 hours answers the first success again (`Idempotent-Replayed: true`); the same key with another request is `409 idempotency_conflict`. */
3202
+ "Idempotency-Key"?: components["parameters"]["OptionalIdempotencyKey"];
3203
+ };
2969
3204
  path: {
2970
3205
  session_id: components["parameters"]["SessionId"];
2971
3206
  };
@@ -2983,12 +3218,16 @@ interface operations {
2983
3218
  };
2984
3219
  };
2985
3220
  404: components["responses"]["Problem"];
3221
+ 409: components["responses"]["Problem"];
2986
3222
  };
2987
3223
  };
2988
3224
  refreshClientSecret: {
2989
3225
  parameters: {
2990
3226
  query?: never;
2991
- header?: never;
3227
+ header?: {
3228
+ /** @description Accepted, not required (declared in v1-draft.22). Scoped to the tenant and environment: the same key and request within 24 hours answers the first success again (`Idempotent-Replayed: true`); the same key with another request is `409 idempotency_conflict`. */
3229
+ "Idempotency-Key"?: components["parameters"]["OptionalIdempotencyKey"];
3230
+ };
2992
3231
  path: {
2993
3232
  session_id: components["parameters"]["SessionId"];
2994
3233
  };