@proteos/component-sdk 0.60.0 → 0.75.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/src/context.tsx CHANGED
@@ -6,21 +6,27 @@ import type {
6
6
  FunctionsClient,
7
7
  KnowledgeClient,
8
8
  MetaClient,
9
+ PageAction,
9
10
  StorageClient,
10
11
  } from '@proteos/sdk'
11
12
  import { createContext, type ReactNode, useMemo } from 'react'
12
13
 
13
14
  import {
15
+ type CloseAgentWindowMessage,
14
16
  type Envelope,
15
17
  isHostMessage,
16
18
  MESSAGE_SOURCE,
17
19
  type ModalResultMessage,
18
20
  type ModalWidth,
19
21
  type NavigateMessage,
22
+ type OpenAgentWindowMessage,
20
23
  type OpenCallMessage,
21
24
  type OpenModalMessage,
22
25
  type OpenPeekMessage,
26
+ type PageActionContext,
27
+ type PageActionOutcome,
23
28
  type PageContext,
29
+ type RunPageActionMessage,
24
30
  } from './protocol'
25
31
 
26
32
  /** Options for {@link RuntimeContextValue.navigate}. */
@@ -45,6 +51,33 @@ export interface OpenModalOptions {
45
51
  height?: number
46
52
  }
47
53
 
54
+ /** What {@link AgentWindowController.open} opens the host's agent window to. */
55
+ export interface OpenAgentWindowOptions {
56
+ /** Resume this session (its agent comes with it). */
57
+ sessionId?: string
58
+ /** Start a fresh session with this agent. Ignored when `sessionId` is set,
59
+ * and when the host surface pins its agent. Without it (and without a
60
+ * session) the window's currently selected agent is used. */
61
+ agentKey?: string
62
+ /** A message to send — into the resumed session, or as the first message
63
+ * of the fresh one. */
64
+ prompt?: string
65
+ /** Context handed to the model alongside `prompt` (what the component knows:
66
+ * the record on screen, a selection …). Read by the model, never shown in
67
+ * the chat; sent only together with a `prompt`. Not for secrets. */
68
+ context?: string
69
+ }
70
+
71
+ /**
72
+ * The host's agent session window (the floating assistant), driven from a
73
+ * component. `open()` posts OPEN_AGENT_WINDOW, `close()` posts
74
+ * CLOSE_AGENT_WINDOW — closing minimizes; the session and its stream live on.
75
+ */
76
+ export interface AgentWindowController {
77
+ open: (options?: OpenAgentWindowOptions) => void
78
+ close: () => void
79
+ }
80
+
48
81
  /**
49
82
  * Manual control over iframe overlay promotion. The runtime already detects
50
83
  * overlays automatically (anything portaled to the iframe's `document.body` —
@@ -130,6 +163,12 @@ export interface RuntimeContextValue extends RuntimeValue {
130
163
  props?: Record<string, unknown>,
131
164
  options?: OpenModalOptions,
132
165
  ) => Promise<unknown>
166
+ /** Open / minimize the host's agent session window (posts OPEN_AGENT_WINDOW
167
+ * / CLOSE_AGENT_WINDOW). */
168
+ agentWindow: AgentWindowController
169
+ /** Run a page action defined inline (posts RUN_PAGE_ACTION); resolves with
170
+ * how its flow ended. */
171
+ runPageAction: (action: PageAction, context?: PageActionContext) => Promise<PageActionOutcome>
133
172
  }
134
173
 
135
174
  export const RuntimeContext = createContext<RuntimeContextValue | null>(null)
@@ -158,30 +197,65 @@ function openCall(conversationBriefId: string): void {
158
197
  window.parent?.postMessage(envelope, '*')
159
198
  }
160
199
 
200
+ /** Post OPEN_AGENT_WINDOW — only the fields that were given ride the wire. */
201
+ function openAgentWindow(options?: OpenAgentWindowOptions): void {
202
+ const envelope: Envelope<OpenAgentWindowMessage> = {
203
+ source: MESSAGE_SOURCE,
204
+ type: 'OPEN_AGENT_WINDOW',
205
+ ...(options?.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
206
+ ...(options?.agentKey !== undefined ? { agentKey: options.agentKey } : {}),
207
+ ...(options?.prompt !== undefined ? { prompt: options.prompt } : {}),
208
+ ...(options?.context !== undefined ? { context: options.context } : {}),
209
+ }
210
+ window.parent?.postMessage(envelope, '*')
211
+ }
212
+
213
+ /** Post CLOSE_AGENT_WINDOW — minimize the host's agent window. */
214
+ function closeAgentWindow(): void {
215
+ const envelope: Envelope<CloseAgentWindowMessage> = {
216
+ source: MESSAGE_SOURCE,
217
+ type: 'CLOSE_AGENT_WINDOW',
218
+ }
219
+ window.parent?.postMessage(envelope, '*')
220
+ }
221
+
222
+ const agentWindow: AgentWindowController = { open: openAgentWindow, close: closeAgentWindow }
223
+
161
224
  /** Navigate full-page (default) or into a peek panel (`{ peek: true }`). */
162
225
  function navigate(to: string, options?: NavigateOptions): void {
163
226
  if (options?.peek) postOpenPeek(to)
164
227
  else postNavigate(to)
165
228
  }
166
229
 
167
- // ── Component modals ────────────────────────────────────────────────────────
168
- // One module-level listener + a pending map, rather than a listener per call:
169
- // the SDK is an import-mapped singleton, so this is per-iframe state.
230
+ // ── Host requests (component modals, page actions) ──────────────────────────
231
+ // One module-level listener + a pending map per request kind, rather than a
232
+ // listener per call: the SDK is an import-mapped singleton, so this is
233
+ // per-iframe state.
170
234
 
171
235
  const pendingModals = new Map<string, (result: unknown) => void>()
172
- let modalListenerAttached = false
236
+ const pendingPageActions = new Map<string, (outcome: PageActionOutcome) => void>()
237
+ let replyListenerAttached = false
173
238
 
174
- function ensureModalListener(): void {
175
- if (modalListenerAttached) return
176
- modalListenerAttached = true
239
+ function ensureReplyListener(): void {
240
+ if (replyListenerAttached) return
241
+ replyListenerAttached = true
177
242
  window.addEventListener('message', (event: MessageEvent) => {
178
243
  const data: unknown = event.data
179
- if (!isHostMessage(data) || data.type !== 'MODAL_CLOSED') return
180
- const resolve = pendingModals.get(data.requestId)
181
- // An unknown requestId is someone else's modal (or a stale reply) — drop it.
182
- if (!resolve) return
183
- pendingModals.delete(data.requestId)
184
- resolve(data.result)
244
+ if (!isHostMessage(data)) return
245
+ // An unknown requestId is someone else's request (or a stale reply) — drop it.
246
+ if (data.type === 'MODAL_CLOSED') {
247
+ const resolve = pendingModals.get(data.requestId)
248
+ if (!resolve) return
249
+ pendingModals.delete(data.requestId)
250
+ resolve(data.result)
251
+ return
252
+ }
253
+ if (data.type === 'PAGE_ACTION_SETTLED') {
254
+ const resolve = pendingPageActions.get(data.requestId)
255
+ if (!resolve) return
256
+ pendingPageActions.delete(data.requestId)
257
+ resolve(data.outcome)
258
+ }
185
259
  })
186
260
  }
187
261
 
@@ -224,7 +298,7 @@ function newRequestId(): string {
224
298
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
225
299
  return crypto.randomUUID()
226
300
  }
227
- return `modal_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`
301
+ return `request_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`
228
302
  }
229
303
 
230
304
  /** Post OPEN_MODAL and resolve when the host answers MODAL_CLOSED. */
@@ -233,7 +307,7 @@ function openModal(
233
307
  props?: Record<string, unknown>,
234
308
  options?: OpenModalOptions,
235
309
  ): Promise<unknown> {
236
- ensureModalListener()
310
+ ensureReplyListener()
237
311
  const requestId = newRequestId()
238
312
  const envelope: Envelope<OpenModalMessage> = {
239
313
  source: MESSAGE_SOURCE,
@@ -255,6 +329,32 @@ function openModal(
255
329
  })
256
330
  }
257
331
 
332
+ /** Post RUN_PAGE_ACTION and resolve when the host answers PAGE_ACTION_SETTLED.
333
+ * The host's dialogs take focus, so it goes back to the pressed control
334
+ * afterwards — as for a modal. */
335
+ function runPageAction(
336
+ action: PageAction,
337
+ context?: PageActionContext,
338
+ ): Promise<PageActionOutcome> {
339
+ ensureReplyListener()
340
+ const requestId = newRequestId()
341
+ const envelope: Envelope<RunPageActionMessage> = {
342
+ source: MESSAGE_SOURCE,
343
+ type: 'RUN_PAGE_ACTION',
344
+ requestId,
345
+ action,
346
+ ...(context !== undefined ? { context } : {}),
347
+ }
348
+ const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null
349
+ return new Promise<PageActionOutcome>((resolve) => {
350
+ pendingPageActions.set(requestId, (outcome) => {
351
+ restoreFocus(opener)
352
+ resolve(outcome)
353
+ })
354
+ window.parent?.postMessage(envelope, '*')
355
+ })
356
+ }
357
+
258
358
  /** Post MODAL_RESULT — the component inside a host modal closing with a value. */
259
359
  export function postModalResult(requestId: string, result?: unknown): void {
260
360
  const envelope: Envelope<ModalResultMessage> = {
@@ -278,7 +378,7 @@ export function RuntimeProvider({ value, children }: { value: RuntimeValue; chil
278
378
  // props and pageCtx are all set once), so memoizing on its identity recreates
279
379
  // the context only when the runtime genuinely re-inits.
280
380
  const ctx = useMemo<RuntimeContextValue>(
281
- () => ({ ...value, navigate, openCall, openModal }),
381
+ () => ({ ...value, navigate, openCall, openModal, agentWindow, runPageAction }),
282
382
  [value],
283
383
  )
284
384
  return <RuntimeContext.Provider value={ctx}>{children}</RuntimeContext.Provider>
@@ -4,17 +4,24 @@ import { afterEach, describe, expect, it, vi } from 'vitest'
4
4
 
5
5
  import { RuntimeProvider, type RuntimeValue } from './context'
6
6
  import {
7
+ useAgentWindow,
7
8
  useApiBaseUrl,
8
9
  useComponentModal,
9
10
  useModalHost,
10
11
  useNavigate,
11
12
  useOverlayExpansion,
13
+ usePageAction,
12
14
  usePageContext,
13
15
  useProps,
14
16
  useRuntime,
15
17
  useSdk,
16
18
  } from './hooks'
17
- import { type Envelope, MESSAGE_SOURCE, type ModalClosedMessage } from './protocol'
19
+ import {
20
+ type Envelope,
21
+ MESSAGE_SOURCE,
22
+ type ModalClosedMessage,
23
+ type PageActionSettledMessage,
24
+ } from './protocol'
18
25
 
19
26
  // A stable stand-in for the injected SDK — the hooks only pass it through.
20
27
  const sdk = {} as RuntimeValue['sdk']
@@ -23,7 +30,7 @@ function makeValue(overrides: Partial<RuntimeValue> = {}): RuntimeValue {
23
30
  return {
24
31
  sdk,
25
32
  props: { title: 'Hello' },
26
- pageCtx: { record: { id: 'rec_1', name: 'ACME' }, entity: { slug: 'company' } },
33
+ pageCtx: { record: { id: 'rec_1', name: 'ACME' }, entity: { slug: 'company' }, mode: 'view' },
27
34
  apiBaseUrl: 'https://api.test',
28
35
  getToken: () => 'tok_123',
29
36
  ...overrides,
@@ -56,11 +63,12 @@ describe('runtime hooks', () => {
56
63
  expect(result.current.props.title).toBe('Hello')
57
64
  expect(result.current.ctx.record).toEqual({ id: 'rec_1', name: 'ACME' })
58
65
  expect(result.current.ctx.entity?.slug).toBe('company')
66
+ expect(result.current.ctx.mode).toBe('view')
59
67
  expect(result.current.base).toBe('https://api.test')
60
68
  })
61
69
 
62
70
  it('usePageContext().record is undefined when the page has no bound record', () => {
63
- const value = makeValue({ pageCtx: { entity: { slug: 'dashboard' } } })
71
+ const value = makeValue({ pageCtx: { entity: { slug: 'dashboard' }, mode: 'view' } })
64
72
  const { result } = renderHook(() => usePageContext(), { wrapper: wrapper(value) })
65
73
  expect(result.current.record).toBeUndefined()
66
74
  })
@@ -75,6 +83,52 @@ describe('runtime hooks', () => {
75
83
  )
76
84
  })
77
85
 
86
+ it('useAgentWindow posts OPEN_AGENT_WINDOW with only the fields given, and CLOSE_AGENT_WINDOW', () => {
87
+ const post = vi.spyOn(window.parent, 'postMessage').mockImplementation(() => {})
88
+ const { result } = renderHook(() => useAgentWindow(), { wrapper: wrapper(makeValue()) })
89
+
90
+ result.current.open()
91
+ expect(post).toHaveBeenLastCalledWith(
92
+ { source: MESSAGE_SOURCE, type: 'OPEN_AGENT_WINDOW' },
93
+ '*',
94
+ )
95
+
96
+ result.current.open({ sessionId: 'sess_1', prompt: 'Summarize this' })
97
+ expect(post).toHaveBeenLastCalledWith(
98
+ {
99
+ source: MESSAGE_SOURCE,
100
+ type: 'OPEN_AGENT_WINDOW',
101
+ sessionId: 'sess_1',
102
+ prompt: 'Summarize this',
103
+ },
104
+ '*',
105
+ )
106
+
107
+ result.current.open({ agentKey: 'sales-bot' })
108
+ expect(post).toHaveBeenLastCalledWith(
109
+ { source: MESSAGE_SOURCE, type: 'OPEN_AGENT_WINDOW', agentKey: 'sales-bot' },
110
+ '*',
111
+ )
112
+
113
+ result.current.open({ agentKey: 'sales-bot', prompt: 'Follow up', context: 'Deal #7' })
114
+ expect(post).toHaveBeenLastCalledWith(
115
+ {
116
+ source: MESSAGE_SOURCE,
117
+ type: 'OPEN_AGENT_WINDOW',
118
+ agentKey: 'sales-bot',
119
+ prompt: 'Follow up',
120
+ context: 'Deal #7',
121
+ },
122
+ '*',
123
+ )
124
+
125
+ result.current.close()
126
+ expect(post).toHaveBeenLastCalledWith(
127
+ { source: MESSAGE_SOURCE, type: 'CLOSE_AGENT_WINDOW' },
128
+ '*',
129
+ )
130
+ })
131
+
78
132
  it('useOverlayExpansion drives the shell controller', () => {
79
133
  const overlay = { expand: vi.fn(), collapse: vi.fn(), isExpanded: () => true }
80
134
  const { result } = renderHook(() => useOverlayExpansion(), {
@@ -153,6 +207,65 @@ describe('runtime hooks', () => {
153
207
  opener.remove()
154
208
  })
155
209
 
210
+ it('usePageAction posts RUN_PAGE_ACTION and resolves with the matching outcome', async () => {
211
+ const post = vi.spyOn(window.parent, 'postMessage').mockImplementation(() => {})
212
+ const { result } = renderHook(() => usePageAction(), { wrapper: wrapper(makeValue()) })
213
+ const action = {
214
+ kind: 'intent' as const,
215
+ intent: 'update_record' as const,
216
+ entity: 'deal',
217
+ label: 'Update deal',
218
+ icon: 'Sparkles',
219
+ prompt: 'Apply what was agreed',
220
+ }
221
+
222
+ const pending = result.current(action, {
223
+ scope: { notes: 'Signed' },
224
+ records: [{ entitySlug: 'deal', recordId: 'deal_1' }],
225
+ })
226
+ const [payload] = post.mock.calls.at(-1) as [Record<string, unknown>]
227
+ expect(payload).toMatchObject({
228
+ source: MESSAGE_SOURCE,
229
+ type: 'RUN_PAGE_ACTION',
230
+ action,
231
+ context: {
232
+ scope: { notes: 'Signed' },
233
+ records: [{ entitySlug: 'deal', recordId: 'deal_1' }],
234
+ },
235
+ })
236
+
237
+ const reply = (requestId: string): Envelope<PageActionSettledMessage> => ({
238
+ source: MESSAGE_SOURCE,
239
+ type: 'PAGE_ACTION_SETTLED',
240
+ requestId,
241
+ outcome: {
242
+ status: 'done',
243
+ kind: 'intent',
244
+ mode: 'update',
245
+ entitySlug: 'deal',
246
+ recordId: 'deal_1',
247
+ title: 'Acme renewal',
248
+ },
249
+ })
250
+ // Another request's reply — and a modal's with our id — must not resolve ours.
251
+ window.dispatchEvent(new MessageEvent('message', { data: reply('someone-else') }))
252
+ window.dispatchEvent(
253
+ new MessageEvent('message', {
254
+ data: { source: MESSAGE_SOURCE, type: 'MODAL_CLOSED', requestId: payload.requestId },
255
+ }),
256
+ )
257
+ window.dispatchEvent(new MessageEvent('message', { data: reply(payload.requestId as string) }))
258
+ await expect(pending).resolves.toMatchObject({ status: 'done', recordId: 'deal_1' })
259
+ })
260
+
261
+ it('usePageAction leaves out a context it was not given', () => {
262
+ const post = vi.spyOn(window.parent, 'postMessage').mockImplementation(() => {})
263
+ const { result } = renderHook(() => usePageAction(), { wrapper: wrapper(makeValue()) })
264
+ void result.current({ kind: 'link', url: 'https://example.com', label: 'Open', icon: 'Link' })
265
+ const [payload] = post.mock.calls.at(-1) as [Record<string, unknown>]
266
+ expect(payload).not.toHaveProperty('context')
267
+ })
268
+
156
269
  it('useComponentModal carries the width and height the opener asked for', () => {
157
270
  const post = vi.spyOn(window.parent, 'postMessage').mockImplementation(() => {})
158
271
  const { result } = renderHook(() => useComponentModal(), { wrapper: wrapper(makeValue()) })
package/src/hooks.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import type { PageAction } from '@proteos/sdk'
1
2
  import { useCallback, useContext, useEffect, useMemo, useState } from 'react'
2
3
 
3
4
  import {
5
+ type AgentWindowController,
4
6
  type ComponentSdk,
5
7
  type NavigateOptions,
6
8
  type OpenModalOptions,
@@ -9,7 +11,7 @@ import {
9
11
  RuntimeContext,
10
12
  type RuntimeContextValue,
11
13
  } from './context'
12
- import type { PageContext } from './protocol'
14
+ import type { PageActionContext, PageActionOutcome, PageContext } from './protocol'
13
15
 
14
16
  /**
15
17
  * Low-level escape hatch: the whole runtime context (sdk, props, pageCtx,
@@ -40,9 +42,13 @@ export function useProps<T extends Record<string, unknown> = Record<string, unkn
40
42
  }
41
43
 
42
44
  /**
43
- * The full page context: host `record`, `entity`, and URL `params`. The
44
- * `record` is a snapshot taken at mount (`undefined` on record-less platform
45
- * pages) — fetch via `useSdk().data` for anything that must stay fresh.
45
+ * The full page context: host `record`, `entity`, URL `params`, the viewer as
46
+ * `current_user` (absent on public pages) and the page `mode`
47
+ * (`'view' | 'create' | 'edit'` — what the viewer is doing with the record).
48
+ * The `record` is a snapshot taken at mount (`undefined` on record-less
49
+ * platform pages) — fetch via `useSdk().data` for anything that must stay
50
+ * fresh. `mode` is a snapshot too: the host remounts the frame when the page
51
+ * switches between view and edit.
46
52
  */
47
53
  export function usePageContext(): PageContext {
48
54
  return useRuntime().pageCtx
@@ -70,6 +76,26 @@ export function useOpenCall(): (conversationBriefId: string) => void {
70
76
  return useRuntime().openCall
71
77
  }
72
78
 
79
+ /**
80
+ * Open or minimize the HOST's agent session window (the floating assistant)
81
+ * from a component — the iframe cannot render it itself.
82
+ *
83
+ * ```ts
84
+ * const agentWindow = useAgentWindow()
85
+ * agentWindow.open() // just open it
86
+ * agentWindow.open({ sessionId }) // resume a session
87
+ * agentWindow.open({ agentKey: 'sales-bot', prompt }) // fresh session, prompt sent
88
+ * agentWindow.close() // minimize (session lives on)
89
+ * ```
90
+ *
91
+ * `sessionId` wins over `agentKey` (the session already has an agent); a
92
+ * `prompt` goes into whichever session the window lands on. Ignored on public
93
+ * pages, and by preview hosts.
94
+ */
95
+ export function useAgentWindow(): AgentWindowController {
96
+ return useRuntime().agentWindow
97
+ }
98
+
73
99
  /** The API origin SDK calls resolve against (for building raw asset URLs). */
74
100
  export function useApiBaseUrl(): string {
75
101
  return useRuntime().apiBaseUrl
@@ -135,6 +161,45 @@ export function useComponentModal(): (
135
161
  return useRuntime().openModal
136
162
  }
137
163
 
164
+ /**
165
+ * Run a page action from a component's own button — the very `PageAction` a
166
+ * page or list toolbar carries, defined inline. The HOST runs it exactly as a
167
+ * toolbar press: `action` / `workflow` open the invoke dialog, `intent`
168
+ * prepares a record proposal for review, `agent` opens the agent window,
169
+ * `link` opens a new tab. Resolves once that flow is over.
170
+ *
171
+ * ```ts
172
+ * const runPageAction = usePageAction()
173
+ * const outcome = await runPageAction(
174
+ * {
175
+ * kind: 'intent',
176
+ * intent: 'update_record',
177
+ * entity: 'deal',
178
+ * label: 'Update deal',
179
+ * icon: 'Sparkles',
180
+ * prompt: 'Apply what was agreed',
181
+ * context: '{{ notes }}',
182
+ * },
183
+ * { scope: { notes }, records: [{ entitySlug: 'deal', recordId: deal.id }] },
184
+ * )
185
+ * if (outcome.status === 'done' && outcome.kind === 'intent') refetch()
186
+ * ```
187
+ *
188
+ * The action's Liquid templates render against the page scope (`record`,
189
+ * `entity`, `params`, `mode`, `current_user`) with `context.scope` merged over
190
+ * it; `context.records` says what it acts on (default: the page record). See
191
+ * {@link PageActionContext} and {@link PageActionOutcome}. `visible_when`
192
+ * still applies — an action whose rule does not match resolves
193
+ * `unavailable: hidden` without opening anything. One page action at a time;
194
+ * public pages and previews resolve `unavailable: unsupported`.
195
+ */
196
+ export function usePageAction(): (
197
+ action: PageAction,
198
+ context?: PageActionContext,
199
+ ) => Promise<PageActionOutcome> {
200
+ return useRuntime().runPageAction
201
+ }
202
+
138
203
  export interface ModalHost {
139
204
  /** True when this component is rendered as the content of a host modal. */
140
205
  isInModal: boolean
package/src/index.ts CHANGED
@@ -8,8 +8,10 @@
8
8
  import './global'
9
9
 
10
10
  export type {
11
+ AgentWindowController,
11
12
  ComponentSdk,
12
13
  NavigateOptions,
14
+ OpenAgentWindowOptions,
13
15
  OpenModalOptions,
14
16
  OverlayController,
15
17
  RuntimeContextValue,
@@ -18,6 +20,7 @@ export type {
18
20
  export { RuntimeProvider } from './context'
19
21
  export type { FillViewportOptions, HostLocation, ModalHost } from './hooks'
20
22
  export {
23
+ useAgentWindow,
21
24
  useApiBaseUrl,
22
25
  useAuthToken,
23
26
  useComponentModal,
@@ -27,6 +30,7 @@ export {
27
30
  useNavigate,
28
31
  useOpenCall,
29
32
  useOverlayExpansion,
33
+ usePageAction,
30
34
  usePageContext,
31
35
  useProps,
32
36
  useRuntime,
@@ -34,6 +38,7 @@ export {
34
38
  } from './hooks'
35
39
  export {
36
40
  type AuthRefreshMessage,
41
+ type CloseAgentWindowMessage,
37
42
  COMPONENT_OVERLAY_Z_INDEX,
38
43
  type DataInvalidateMessage,
39
44
  type Envelope,
@@ -48,14 +53,22 @@ export {
48
53
  type ModalResultMessage,
49
54
  type ModalWidth,
50
55
  type NavigateMessage,
56
+ type OpenAgentWindowMessage,
51
57
  type OpenCallMessage,
52
58
  type OpenModalMessage,
53
59
  type OpenPeekMessage,
54
60
  type OverlayRect,
55
61
  type OverlayRectMessage,
56
62
  type OverlayStateMessage,
63
+ type PageActionContext,
64
+ type PageActionOutcome,
65
+ type PageActionRecord,
66
+ type PageActionSettledMessage,
57
67
  type PageContext,
68
+ type PageMode,
58
69
  type ReadyMessage,
59
70
  type ResizeMessage,
71
+ type RunPageActionMessage,
60
72
  type RuntimeMessage,
73
+ type TriggerPhase,
61
74
  } from './protocol'