@smooai/smooth-operator 1.19.0 → 1.21.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.
@@ -67,7 +67,7 @@ export interface CreateConversationSessionRequest {
67
67
  */
68
68
  browserFingerprint?: string;
69
69
  /**
70
- * Client render capabilities for this session. Known value: `identity_form` the client can render a structured identity-intake form, so the server may emit `identity_intake_required` mid-turn. Text-only channels (SMS, voice) omit this and the server degrades intake to conversational turn-by-turn collection. Unknown values are ignored (forward-compatible).
70
+ * Client render capabilities for this session a per-kind list gating the Rich Interactions the server may emit mid-turn (`interaction_required`). Each interaction kind declares the capability that gates it (e.g. kind `identity_intake` → capability `identity_form`); future kinds add their own values (`date_picker`, `file_upload`, …). Text-only channels (SMS, voice) omit this and the server degrades each kind to its conversational fallback. Unknown values are ignored (forward-compatible).
71
71
  */
72
72
  supports?: string[];
73
73
  /**
@@ -380,17 +380,17 @@ export interface GeneralAgentResponse {
380
380
  suggestedNextActions: string[];
381
381
  }
382
382
 
383
- // ── from actions/submit-identity-intake.schema.json ──
383
+ // ── from actions/submit-interaction.schema.json ──
384
384
  /**
385
- * Fields sent by the client to submit (or decline) identity intake.
385
+ * Fields sent by the client to submit (or decline) a parked interaction.
386
386
  */
387
- export interface SubmitIdentityIntakeRequest {
387
+ export interface SubmitInteractionRequest {
388
388
  /**
389
389
  * Action discriminator.
390
390
  */
391
- action: 'submit_identity_intake';
391
+ action: 'submit_interaction';
392
392
  /**
393
- * Must match the `requestId` from the `identity_intake_required` event being responded to.
393
+ * Must match the `requestId` from the `interaction_required` event being responded to.
394
394
  */
395
395
  requestId: string;
396
396
  /**
@@ -398,33 +398,28 @@ export interface SubmitIdentityIntakeRequest {
398
398
  */
399
399
  sessionId: string;
400
400
  /**
401
- * The visitor's identity values. Required unless `declined` is true. Only the fields requested by the `identity_intake_required` event are meaningful; the server validates required-ness against that request.
401
+ * Must match the `interactionId` from the `interaction_required` event, so a stale submit can never resolve a newer park.
402
402
  */
403
- values?: {
404
- /**
405
- * The visitor's display name.
406
- */
407
- name?: string;
408
- /**
409
- * The visitor's email address (validated server-side).
410
- */
411
- email?: string;
412
- /**
413
- * The visitor's phone number (normalized server-side to E.164).
414
- */
415
- phone?: string;
416
- };
403
+ interactionId: string;
404
+ /**
405
+ * Optional interaction kind, for cross-checking; the server already knows the parked interaction's kind. When present and mismatched, the submit is rejected.
406
+ */
407
+ kind?: string;
408
+ /**
409
+ * Kind-specific submitted values. Required unless `declined` is true. Shape per `interactions/<kind>.schema.json#/$defs/Values` (e.g. identity_intake's `{ name?, email?, phone? }`). Validated server-side by the kind's validator.
410
+ */
411
+ values?: {};
417
412
  /**
418
- * True when the visitor refused to share their details. The turn resumes with a declined payload so the agent can proceed gracefully. When true, `values` is ignored.
413
+ * True when the visitor refused the interaction. The turn resumes with a declined payload so the agent can proceed gracefully. When true, `values` is ignored.
419
414
  */
420
415
  declined?: boolean;
421
416
  }
422
417
 
423
- // ── from actions/submit-identity-intake.schema.json ──
418
+ // ── from actions/submit-interaction.schema.json ──
424
419
  /**
425
- * No dedicated response event for `submit_identity_intake`. Valid values (or a decline) are acked with an `immediate_response` and the parked turn resumes its normal streaming sequence. Invalid values emit `identity_intake_invalid` (the turn stays parked). This schema is provided for documentation completeness only.
420
+ * No dedicated response event for `submit_interaction`. Valid values (or a decline) are acked with an `immediate_response` and the parked turn resumes its normal streaming sequence. Invalid values emit `interaction_invalid` (the turn stays parked). This schema is provided for documentation completeness only.
426
421
  */
427
- export interface SubmitIdentityIntakeResponse {
422
+ export interface SubmitInteractionResponse {
428
423
  [k: string]: unknown;
429
424
  }
430
425
 
@@ -864,7 +859,7 @@ export interface ActionEnvelope {
864
859
  | 'get_conversation_messages'
865
860
  | 'confirm_tool_action'
866
861
  | 'verify_otp'
867
- | 'submit_identity_intake'
862
+ | 'submit_interaction'
868
863
  | 'ping';
869
864
  /**
870
865
  * Client-generated correlation ID. Will be echoed back on all related server events. Should be unique per in-flight request. If omitted the server may generate one, but correlating responses becomes the client's problem.
@@ -1030,17 +1025,50 @@ export interface EventualResponse {
1030
1025
  timestamp?: number;
1031
1026
  }
1032
1027
 
1033
- // ── from events/identity-intake-invalid.schema.json ──
1028
+ // ── from events/immediate-response.schema.json ──
1034
1029
  /**
1035
- * Event: `identity_intake_invalid`. Emitted when a `submit_identity_intake` action carried values that failed server-side validation (missing required field, malformed email, unparseable phone). The turn REMAINS parked the client should re-render the intake form with the per-field errors and let the visitor resubmit. Mirrors `otp_invalid`: invalid input is a retryable state, never a terminal `error` event.
1030
+ * Event: `immediate_response`. Sent by the server synchronously upon receiving any action, to acknowledge that the request was accepted and processing has begun. For streaming actions (`send_message`) this always precedes `stream_chunk` / `stream_token` events and the final `eventual_response`. For non-streaming actions (e.g. `get_session`, `create_conversation_session`) this also carries the complete response payload in `data`.
1036
1031
  */
1037
- export interface IdentityIntakeInvalid {
1032
+ export interface ImmediateResponse {
1038
1033
  /**
1039
1034
  * Event type discriminator.
1040
1035
  */
1041
- type: 'identity_intake_invalid';
1036
+ type: 'immediate_response';
1042
1037
  /**
1043
- * Echoes the `requestId` of the parked turn (same correlation as the `identity_intake_required` event).
1038
+ * Echoes the `requestId` from the originating action.
1039
+ */
1040
+ requestId?: string;
1041
+ /**
1042
+ * HTTP-like status. 202 = accepted and processing; 200 = synchronous success (non-streaming responses).
1043
+ */
1044
+ status?: number;
1045
+ /**
1046
+ * Human-readable status description (e.g. `Processing your request...`).
1047
+ */
1048
+ message?: string;
1049
+ /**
1050
+ * Action-specific response payload. For `create_conversation_session` and `get_session`, this is the session descriptor. For `get_conversation_messages`, this is the message page. For streaming `send_message`, this is typically empty or contains only a minimal ack.
1051
+ */
1052
+ data: {
1053
+ [k: string]: unknown;
1054
+ };
1055
+ /**
1056
+ * Unix epoch milliseconds when the event was emitted.
1057
+ */
1058
+ timestamp?: number;
1059
+ }
1060
+
1061
+ // ── from events/interaction-invalid.schema.json ──
1062
+ /**
1063
+ * Event: `interaction_invalid`. Emitted when a `submit_interaction` action carried values that failed the kind's server-side validation. The turn REMAINS parked — the client should re-render the interaction card with the per-field errors and let the visitor resubmit. Mirrors `otp_invalid`: invalid input is a retryable state, never a terminal `error` event.
1064
+ */
1065
+ export interface InteractionInvalid {
1066
+ /**
1067
+ * Event type discriminator.
1068
+ */
1069
+ type: 'interaction_invalid';
1070
+ /**
1071
+ * Echoes the `requestId` of the parked turn (same correlation as the `interaction_required` event).
1044
1072
  */
1045
1073
  requestId?: string;
1046
1074
  /**
@@ -1048,7 +1076,7 @@ export interface IdentityIntakeInvalid {
1048
1076
  */
1049
1077
  data: {
1050
1078
  /**
1051
- * The request ID this intake belongs to.
1079
+ * The request ID this interaction belongs to.
1052
1080
  */
1053
1081
  requestId: string;
1054
1082
  /**
@@ -1056,16 +1084,24 @@ export interface IdentityIntakeInvalid {
1056
1084
  */
1057
1085
  data: {
1058
1086
  /**
1059
- * One entry per failed field.
1087
+ * The interaction instance the rejected submit targeted.
1088
+ */
1089
+ interactionId: string;
1090
+ /**
1091
+ * The interaction kind (e.g. `identity_intake`).
1092
+ */
1093
+ kind: string;
1094
+ /**
1095
+ * One entry per failed field. `field` is a kind-specific field key (identity_intake: `name` | `email` | `phone`).
1060
1096
  *
1061
1097
  * @minItems 1
1062
1098
  */
1063
1099
  errors: [
1064
1100
  {
1065
1101
  /**
1066
- * The field that failed validation.
1102
+ * The kind-specific field that failed validation.
1067
1103
  */
1068
- field: 'name' | 'email' | 'phone';
1104
+ field: string;
1069
1105
  /**
1070
1106
  * Human-readable validation message for this field.
1071
1107
  */
@@ -1073,9 +1109,9 @@ export interface IdentityIntakeInvalid {
1073
1109
  },
1074
1110
  ...{
1075
1111
  /**
1076
- * The field that failed validation.
1112
+ * The kind-specific field that failed validation.
1077
1113
  */
1078
- field: 'name' | 'email' | 'phone';
1114
+ field: string;
1079
1115
  /**
1080
1116
  * Human-readable validation message for this field.
1081
1117
  */
@@ -1083,7 +1119,7 @@ export interface IdentityIntakeInvalid {
1083
1119
  }[],
1084
1120
  ];
1085
1121
  /**
1086
- * Human-readable summary suitable for a form-level error line.
1122
+ * Human-readable summary suitable for a card-level error line.
1087
1123
  */
1088
1124
  message: string;
1089
1125
  };
@@ -1094,68 +1130,45 @@ export interface IdentityIntakeInvalid {
1094
1130
  timestamp?: number;
1095
1131
  }
1096
1132
 
1097
- // ── from events/identity-intake-required.schema.json ──
1133
+ // ── from events/interaction-required.schema.json ──
1098
1134
  /**
1099
- * Event: `identity_intake_required`. Emitted mid-turn when the agent requests structured identity/lead intake (name / email / phone) and the session declared the `identity_form` capability at `create_conversation_session`. The turn is parked until the client replies with a `submit_identity_intake` action carrying the same `requestId` (values or `declined: true`). Sessions that did not declare `identity_form` never receive this event — the server degrades to conversational, turn-by-turn collection instead.
1135
+ * Event: `interaction_required`. The Rich Interactions envelope: emitted mid-turn when the agent requests a structured interaction (identity intake, a date picker, choice chips, …) and the session declared the interaction kind's render capability in `supports` at `create_conversation_session`. The turn is parked until the client replies with a `submit_interaction` action carrying the same `requestId` + `interactionId` (values or `declined: true`). Sessions without the capability never receive this event — the server degrades that kind to its conversational fallback instead. `kind` selects the client card and the server validator; `spec` is the kind-specific payload whose shape is defined by `interactions/<kind>.schema.json` (e.g. `interactions/identity-intake.schema.json#/$defs/Spec`).
1100
1136
  */
1101
- export interface IdentityIntakeRequired {
1137
+ export interface InteractionRequired {
1102
1138
  /**
1103
1139
  * Event type discriminator.
1104
1140
  */
1105
- type: 'identity_intake_required';
1141
+ type: 'interaction_required';
1106
1142
  /**
1107
- * Echoes the `requestId` from the originating `send_message` action. Must be included in the `submit_identity_intake` reply.
1143
+ * Echoes the `requestId` from the originating `send_message` action. Must be included in the `submit_interaction` reply.
1108
1144
  */
1109
1145
  requestId?: string;
1110
1146
  /**
1111
- * Intake prompt details.
1147
+ * Interaction prompt details.
1112
1148
  */
1113
1149
  data: {
1114
1150
  /**
1115
- * The request ID this intake belongs to.
1151
+ * The request ID this interaction belongs to.
1116
1152
  */
1117
1153
  requestId: string;
1118
1154
  /**
1119
- * The fields the agent wants and why.
1155
+ * The interaction the client should render.
1120
1156
  */
1121
1157
  data: {
1122
1158
  /**
1123
- * The identity fields to collect, in display order.
1124
- *
1125
- * @minItems 1
1159
+ * Server-generated ID for this specific interaction instance. Must be echoed on the `submit_interaction` reply so a stale submit can never resolve a newer park.
1126
1160
  */
1127
- fields: [
1128
- {
1129
- /**
1130
- * Which identity field to collect.
1131
- */
1132
- key: 'name' | 'email' | 'phone';
1133
- /**
1134
- * Whether the visitor must provide this field to submit.
1135
- */
1136
- required: boolean;
1137
- /**
1138
- * Optional display label overriding the client's default for this field.
1139
- */
1140
- label?: string;
1141
- },
1142
- ...{
1143
- /**
1144
- * Which identity field to collect.
1145
- */
1146
- key: 'name' | 'email' | 'phone';
1147
- /**
1148
- * Whether the visitor must provide this field to submit.
1149
- */
1150
- required: boolean;
1151
- /**
1152
- * Optional display label overriding the client's default for this field.
1153
- */
1154
- label?: string;
1155
- }[],
1156
- ];
1161
+ interactionId: string;
1162
+ /**
1163
+ * The interaction kind (e.g. `identity_intake`). Selects the client's card component and the server's validator. The kind catalog lives in `spec/interactions/`.
1164
+ */
1165
+ kind: string;
1157
1166
  /**
1158
- * Human-readable reason the agent needs these details, suitable for the form header (e.g. `to send you the quote`).
1167
+ * Kind-specific render spec. Shape per `interactions/<kind>.schema.json#/$defs/Spec` (e.g. identity_intake's `{ fields: [...] }`).
1168
+ */
1169
+ spec: {};
1170
+ /**
1171
+ * Human-readable reason the agent raised this interaction, suitable for the card header (e.g. `to send you the quote`).
1159
1172
  */
1160
1173
  reason: string;
1161
1174
  };
@@ -1166,39 +1179,6 @@ export interface IdentityIntakeRequired {
1166
1179
  timestamp?: number;
1167
1180
  }
1168
1181
 
1169
- // ── from events/immediate-response.schema.json ──
1170
- /**
1171
- * Event: `immediate_response`. Sent by the server synchronously upon receiving any action, to acknowledge that the request was accepted and processing has begun. For streaming actions (`send_message`) this always precedes `stream_chunk` / `stream_token` events and the final `eventual_response`. For non-streaming actions (e.g. `get_session`, `create_conversation_session`) this also carries the complete response payload in `data`.
1172
- */
1173
- export interface ImmediateResponse {
1174
- /**
1175
- * Event type discriminator.
1176
- */
1177
- type: 'immediate_response';
1178
- /**
1179
- * Echoes the `requestId` from the originating action.
1180
- */
1181
- requestId?: string;
1182
- /**
1183
- * HTTP-like status. 202 = accepted and processing; 200 = synchronous success (non-streaming responses).
1184
- */
1185
- status?: number;
1186
- /**
1187
- * Human-readable status description (e.g. `Processing your request...`).
1188
- */
1189
- message?: string;
1190
- /**
1191
- * Action-specific response payload. For `create_conversation_session` and `get_session`, this is the session descriptor. For `get_conversation_messages`, this is the message page. For streaming `send_message`, this is typically empty or contains only a minimal ack.
1192
- */
1193
- data: {
1194
- [k: string]: unknown;
1195
- };
1196
- /**
1197
- * Unix epoch milliseconds when the event was emitted.
1198
- */
1199
- timestamp?: number;
1200
- }
1201
-
1202
1182
  // ── from events/keepalive.schema.json ──
1203
1183
  /**
1204
1184
  * Event: `keepalive`. Sent periodically by the server during long-running agent turns (typically every 30 seconds) to prevent AWS API Gateway's 10-minute idle connection timeout from closing the WebSocket while the backend is still computing. Clients should acknowledge receipt by updating their last-seen timestamp, but no reply action is needed. Distinct from `ping`/`pong` which are client-initiated.
@@ -1606,3 +1586,90 @@ export interface WriteConfirmationRequired {
1606
1586
  */
1607
1587
  timestamp?: number;
1608
1588
  }
1589
+
1590
+ // ── from interactions/identity-intake.schema.json ──
1591
+ /**
1592
+ * The `spec` carried on `interaction_required` for kind `identity_intake`: which fields to collect.
1593
+ */
1594
+ export interface IdentityIntakeSpec {
1595
+ /**
1596
+ * The identity fields to collect, in display order.
1597
+ *
1598
+ * @minItems 1
1599
+ */
1600
+ fields: [
1601
+ {
1602
+ /**
1603
+ * Which identity field to collect.
1604
+ */
1605
+ key: 'name' | 'email' | 'phone';
1606
+ /**
1607
+ * Whether the visitor must provide this field to submit.
1608
+ */
1609
+ required: boolean;
1610
+ /**
1611
+ * Optional display label overriding the client's default for this field.
1612
+ */
1613
+ label?: string;
1614
+ },
1615
+ ...{
1616
+ /**
1617
+ * Which identity field to collect.
1618
+ */
1619
+ key: 'name' | 'email' | 'phone';
1620
+ /**
1621
+ * Whether the visitor must provide this field to submit.
1622
+ */
1623
+ required: boolean;
1624
+ /**
1625
+ * Optional display label overriding the client's default for this field.
1626
+ */
1627
+ label?: string;
1628
+ }[],
1629
+ ];
1630
+ }
1631
+
1632
+ // ── from interactions/identity-intake.schema.json ──
1633
+ /**
1634
+ * The `values` a client submits via `submit_interaction` for kind `identity_intake`. Validated server-side: required fields present, email shape, phone normalized to E.164.
1635
+ */
1636
+ export interface IdentityIntakeValues {
1637
+ /**
1638
+ * The visitor's display name.
1639
+ */
1640
+ name?: string;
1641
+ /**
1642
+ * The visitor's email address (validated server-side).
1643
+ */
1644
+ email?: string;
1645
+ /**
1646
+ * The visitor's phone number (normalized server-side to E.164).
1647
+ */
1648
+ phone?: string;
1649
+ }
1650
+
1651
+ // ── from interactions/identity-intake.schema.json ──
1652
+ /**
1653
+ * The canonical validated payload the parked turn resumes with (identical on the form and conversational paths). On success the server also attaches the identity to the session (metadata `userName` / `contactEmail` / `contactPhone` — the same keys the OTP contact seam reads).
1654
+ */
1655
+ export interface IdentityIntakePayload {
1656
+ /**
1657
+ * How the interaction resolved.
1658
+ */
1659
+ status: 'submitted' | 'declined' | 'no_response';
1660
+ /**
1661
+ * Present when `status` is `submitted`: the validated, normalized values.
1662
+ */
1663
+ values?: {
1664
+ name?: string;
1665
+ email?: string;
1666
+ /**
1667
+ * E.164-normalized (`+15551234567`).
1668
+ */
1669
+ phone?: string;
1670
+ };
1671
+ /**
1672
+ * Guidance for the agent when `status` is `declined` / `no_response`.
1673
+ */
1674
+ message?: string;
1675
+ }
package/src/types.ts CHANGED
@@ -21,9 +21,9 @@ import type {
21
21
  GetMessagesResponse,
22
22
  GetSessionRequest,
23
23
  GetSessionResponse,
24
- IdentityIntakeInvalid,
25
- IdentityIntakeRequired,
26
24
  ImmediateResponse,
25
+ InteractionInvalid,
26
+ InteractionRequired,
27
27
  Keepalive,
28
28
  OtpInvalid,
29
29
  OtpSent,
@@ -35,7 +35,7 @@ import type {
35
35
  SendMessageResponse,
36
36
  StreamChunk,
37
37
  StreamToken,
38
- SubmitIdentityIntakeRequest,
38
+ SubmitInteractionRequest,
39
39
  VerifyOtpRequest,
40
40
  WriteConfirmationRequired,
41
41
  } from './generated/types.js';
@@ -58,7 +58,7 @@ export const ACTION_TYPES = [
58
58
  'get_conversation_messages',
59
59
  'confirm_tool_action',
60
60
  'verify_otp',
61
- 'submit_identity_intake',
61
+ 'submit_interaction',
62
62
  'ping',
63
63
  ] as const;
64
64
  export type ActionType = (typeof ACTION_TYPES)[number];
@@ -75,8 +75,8 @@ export const EVENT_TYPES = [
75
75
  'otp_sent',
76
76
  'otp_verified',
77
77
  'otp_invalid',
78
- 'identity_intake_required',
79
- 'identity_intake_invalid',
78
+ 'interaction_required',
79
+ 'interaction_invalid',
80
80
  'error',
81
81
  'pong',
82
82
  ] as const;
@@ -95,7 +95,7 @@ export type ClientAction =
95
95
  | GetMessagesRequest
96
96
  | ConfirmToolActionRequest
97
97
  | VerifyOtpRequest
98
- | SubmitIdentityIntakeRequest
98
+ | SubmitInteractionRequest
99
99
  | PingRequest;
100
100
 
101
101
  // ───────────────────────────── Server events ───────────────────────────────
@@ -115,8 +115,8 @@ export type ServerEvent =
115
115
  | OtpSent
116
116
  | OtpVerified
117
117
  | OtpInvalid
118
- | IdentityIntakeRequired
119
- | IdentityIntakeInvalid
118
+ | InteractionRequired
119
+ | InteractionInvalid
120
120
  | GeneratedErrorEvent
121
121
  | Pong;
122
122
 
@@ -134,8 +134,8 @@ export interface ServerEventByType {
134
134
  otp_sent: OtpSent;
135
135
  otp_verified: OtpVerified;
136
136
  otp_invalid: OtpInvalid;
137
- identity_intake_required: IdentityIntakeRequired;
138
- identity_intake_invalid: IdentityIntakeInvalid;
137
+ interaction_required: InteractionRequired;
138
+ interaction_invalid: InteractionInvalid;
139
139
  error: GeneratedErrorEvent;
140
140
  pong: Pong;
141
141
  }
@@ -148,7 +148,7 @@ export interface ClientActionByType {
148
148
  get_conversation_messages: GetMessagesRequest;
149
149
  confirm_tool_action: ConfirmToolActionRequest;
150
150
  verify_otp: VerifyOtpRequest;
151
- submit_identity_intake: SubmitIdentityIntakeRequest;
151
+ submit_interaction: SubmitInteractionRequest;
152
152
  ping: PingRequest;
153
153
  }
154
154
 
package/src/validate.ts CHANGED
@@ -47,8 +47,8 @@ const EVENT_SCHEMA_FILE: Record<EventType, string> = {
47
47
  otp_sent: 'events/otp-sent.schema.json',
48
48
  otp_verified: 'events/otp-verified.schema.json',
49
49
  otp_invalid: 'events/otp-invalid.schema.json',
50
- identity_intake_required: 'events/identity-intake-required.schema.json',
51
- identity_intake_invalid: 'events/identity-intake-invalid.schema.json',
50
+ interaction_required: 'events/interaction-required.schema.json',
51
+ interaction_invalid: 'events/interaction-invalid.schema.json',
52
52
  error: 'events/error.schema.json',
53
53
  pong: 'events/pong.schema.json',
54
54
  };
@@ -61,7 +61,7 @@ const ACTION_SCHEMA_REF: Record<ActionType, string> = {
61
61
  get_conversation_messages: 'actions/get-messages.schema.json#/$defs/Request',
62
62
  confirm_tool_action: 'actions/confirm-tool-action.schema.json#/$defs/Request',
63
63
  verify_otp: 'actions/verify-otp.schema.json#/$defs/Request',
64
- submit_identity_intake: 'actions/submit-identity-intake.schema.json#/$defs/Request',
64
+ submit_interaction: 'actions/submit-interaction.schema.json#/$defs/Request',
65
65
  ping: 'actions/ping.schema.json#/$defs/Request',
66
66
  };
67
67
 
@@ -87,7 +87,7 @@ export class ProtocolValidator {
87
87
 
88
88
  const validator = new ProtocolValidator(ajv);
89
89
 
90
- for (const sub of ['', 'actions', 'events', 'domain']) {
90
+ for (const sub of ['', 'actions', 'events', 'domain', 'interactions']) {
91
91
  const dir = sub ? join(specDir, sub) : specDir;
92
92
  const entries = await readdir(dir, { withFileTypes: true });
93
93
  for (const e of entries) {