@datalayer/agent-runtimes 1.5.24 → 1.5.26
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/dist-embed/datalayer-app-main.js +60 -60
- package/lib/apps/plugins/pap-sign-in/signIn.d.ts +3 -89
- package/lib/apps/plugins/pap-sign-in/signIn.js +5 -142
- package/lib/chat/messages/ChatMessageList.js +3 -1
- package/lib/portable/conversation.d.ts +3 -0
- package/lib/portable/conversation.js +15 -1
- package/lib/portable/direct.d.ts +100 -0
- package/lib/portable/direct.js +172 -0
- package/lib/portable/displays.d.ts +109 -0
- package/lib/portable/displays.js +261 -0
- package/lib/portable/fixtures.js +2 -0
- package/lib/portable/index.d.ts +6 -1
- package/lib/portable/index.js +9 -0
- package/lib/portable/protectedInput.d.ts +93 -0
- package/lib/portable/protectedInput.js +186 -0
- package/lib/portable/signIn.d.ts +96 -0
- package/lib/portable/signIn.js +148 -0
- package/lib/portable/signInStatus.d.ts +37 -0
- package/lib/portable/signInStatus.js +74 -0
- package/lib/portable/views.d.ts +22 -0
- package/lib/runtimes/__tests__/fixtures/accounting-agent-card.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The protocol displays a run's tool results carry, read strictly for any
|
|
3
|
+
* renderer (MOBILE M-037, REACTOR_UI RU-1): the page's half of a tool result
|
|
4
|
+
* — `_meta["reactor.ui/display"]`, as the runtime's AG-UI stream sends it
|
|
5
|
+
* beside the model's view — decoded into what a card draws.
|
|
6
|
+
*
|
|
7
|
+
* - **Sign in at a company** (`…pap.sign-in+json`, and a plain `pap_sign_in`
|
|
8
|
+
* or a business's `pact_sign_in` answer): Direct, Device or Mediated, its
|
|
9
|
+
* page (`https` only), its code, until when, what it needs.
|
|
10
|
+
* - **An operation to confirm** (`…pap.confirm+json`): the company's words
|
|
11
|
+
* verbatim, its terms, the revision and the one it replaced, what it does
|
|
12
|
+
* (a Rules class; `buy` when money moves — a purchase), whether only the
|
|
13
|
+
* person may decide. It is answered where approvals are, never here: the
|
|
14
|
+
* approval it stands for is named (`approvalId`).
|
|
15
|
+
* - **What a confirmed operation came to** (`…pap.outcome+json`).
|
|
16
|
+
* - **What a company answered** (`…pap.replies+json`): each reply with who
|
|
17
|
+
* wrote it there (its agent or one of its people), who answers now and
|
|
18
|
+
* where the conversation stands — participation.
|
|
19
|
+
* - **A handoff** (`pap_handoff`'s answer): handed to the company's people,
|
|
20
|
+
* or why not.
|
|
21
|
+
*
|
|
22
|
+
* Anything else — an unknown type, a known one whose data does not read — is
|
|
23
|
+
* `unknown`: its type, version and model-safe text, nothing drawn from its
|
|
24
|
+
* data (diagnosable and safe). Typed decoding fails closed.
|
|
25
|
+
*
|
|
26
|
+
* @module portable/displays
|
|
27
|
+
*/
|
|
28
|
+
import { type PapSignInWaiting } from './signIn';
|
|
29
|
+
export declare const PAP_SIGN_IN_TYPE = "application/vnd.datalayer.pap.sign-in+json";
|
|
30
|
+
export declare const PAP_CONFIRM_TYPE = "application/vnd.datalayer.pap.confirm+json";
|
|
31
|
+
export declare const PAP_OUTCOME_TYPE = "application/vnd.datalayer.pap.outcome+json";
|
|
32
|
+
export declare const PAP_REPLIES_TYPE = "application/vnd.datalayer.pap.replies+json";
|
|
33
|
+
/** Where a tool result carries its display for the page. */
|
|
34
|
+
export declare const DISPLAY_META_KEY = "reactor.ui/display";
|
|
35
|
+
/** What confirming an operation does, as an application's Rules class it. */
|
|
36
|
+
export type ActionClass = 'read' | 'write' | 'send' | 'buy' | 'delete' | 'publish';
|
|
37
|
+
export type ProtocolDisplay = ({
|
|
38
|
+
kind: 'sign-in';
|
|
39
|
+
id: string;
|
|
40
|
+
} & PapSignInWaiting) | {
|
|
41
|
+
kind: 'sign-in-refused';
|
|
42
|
+
id: string;
|
|
43
|
+
why: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'confirm';
|
|
46
|
+
id: string;
|
|
47
|
+
/** The approval it stands for: answered where approvals are. */
|
|
48
|
+
approvalId: string;
|
|
49
|
+
company: string;
|
|
50
|
+
summary: string;
|
|
51
|
+
terms: Record<string, unknown>;
|
|
52
|
+
operationRef: string;
|
|
53
|
+
revision: number;
|
|
54
|
+
does: ActionClass | null;
|
|
55
|
+
signedIn: boolean | null;
|
|
56
|
+
expiresAt: string;
|
|
57
|
+
was: {
|
|
58
|
+
revision: number;
|
|
59
|
+
terms: Record<string, unknown>;
|
|
60
|
+
} | null;
|
|
61
|
+
onlyThePerson: boolean;
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'outcome';
|
|
64
|
+
id: string;
|
|
65
|
+
company: string;
|
|
66
|
+
summary: string;
|
|
67
|
+
operationRef: string;
|
|
68
|
+
revision: number;
|
|
69
|
+
state: 'in_progress' | 'succeeded' | 'failed' | 'cancelled' | 'expired';
|
|
70
|
+
result: string;
|
|
71
|
+
approvedBy: 'user' | 'standing_permission' | null;
|
|
72
|
+
} | {
|
|
73
|
+
kind: 'replies';
|
|
74
|
+
id: string;
|
|
75
|
+
company: string;
|
|
76
|
+
conversation: string;
|
|
77
|
+
replies: {
|
|
78
|
+
sender: 'agent' | 'human';
|
|
79
|
+
text: string;
|
|
80
|
+
}[];
|
|
81
|
+
status: 'working' | 'idle' | 'queued' | 'closed' | null;
|
|
82
|
+
responder: 'agent' | 'human' | null;
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'handoff';
|
|
85
|
+
id: string;
|
|
86
|
+
handed: boolean;
|
|
87
|
+
responder: 'agent' | 'human' | null;
|
|
88
|
+
note: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'unknown';
|
|
91
|
+
id: string;
|
|
92
|
+
type: string;
|
|
93
|
+
version: number;
|
|
94
|
+
text: string;
|
|
95
|
+
};
|
|
96
|
+
/** A display's wire (`{type, version, id, text, data}`) decoded, or `unknown` with its text. */
|
|
97
|
+
export declare function protocolDisplayOf(wire: unknown): ProtocolDisplay | null;
|
|
98
|
+
/** `pap_handoff`, as the gateway names it with or without a prefix. */
|
|
99
|
+
export declare const PAP_HANDOFF_TOOL: RegExp;
|
|
100
|
+
/**
|
|
101
|
+
* The protocol display of a tool's result, or `null` for one that has none:
|
|
102
|
+
* its embedded display first; else a plain `pap_sign_in`/`pact_sign_in`
|
|
103
|
+
* answer or a `pap_handoff` answer, read by the tool's name.
|
|
104
|
+
*/
|
|
105
|
+
export declare function displayOfToolResult(toolName: string, result: unknown, id?: string): ProtocolDisplay | null;
|
|
106
|
+
/** What each display says in one line, for a screen reader and a collapsed row. */
|
|
107
|
+
export declare function displayLine(display: ProtocolDisplay): string;
|
|
108
|
+
/** Who wrote a reply, said apart from the person's words and the agent's summaries (PAP-7.8-01). */
|
|
109
|
+
export declare const replyAuthor: (company: string, sender: "agent" | "human") => string;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The protocol displays a run's tool results carry, read strictly for any
|
|
7
|
+
* renderer (MOBILE M-037, REACTOR_UI RU-1): the page's half of a tool result
|
|
8
|
+
* — `_meta["reactor.ui/display"]`, as the runtime's AG-UI stream sends it
|
|
9
|
+
* beside the model's view — decoded into what a card draws.
|
|
10
|
+
*
|
|
11
|
+
* - **Sign in at a company** (`…pap.sign-in+json`, and a plain `pap_sign_in`
|
|
12
|
+
* or a business's `pact_sign_in` answer): Direct, Device or Mediated, its
|
|
13
|
+
* page (`https` only), its code, until when, what it needs.
|
|
14
|
+
* - **An operation to confirm** (`…pap.confirm+json`): the company's words
|
|
15
|
+
* verbatim, its terms, the revision and the one it replaced, what it does
|
|
16
|
+
* (a Rules class; `buy` when money moves — a purchase), whether only the
|
|
17
|
+
* person may decide. It is answered where approvals are, never here: the
|
|
18
|
+
* approval it stands for is named (`approvalId`).
|
|
19
|
+
* - **What a confirmed operation came to** (`…pap.outcome+json`).
|
|
20
|
+
* - **What a company answered** (`…pap.replies+json`): each reply with who
|
|
21
|
+
* wrote it there (its agent or one of its people), who answers now and
|
|
22
|
+
* where the conversation stands — participation.
|
|
23
|
+
* - **A handoff** (`pap_handoff`'s answer): handed to the company's people,
|
|
24
|
+
* or why not.
|
|
25
|
+
*
|
|
26
|
+
* Anything else — an unknown type, a known one whose data does not read — is
|
|
27
|
+
* `unknown`: its type, version and model-safe text, nothing drawn from its
|
|
28
|
+
* data (diagnosable and safe). Typed decoding fails closed.
|
|
29
|
+
*
|
|
30
|
+
* @module portable/displays
|
|
31
|
+
*/
|
|
32
|
+
import { isPapSignInTool, readPapSignIn, } from './signIn';
|
|
33
|
+
export const PAP_SIGN_IN_TYPE = 'application/vnd.datalayer.pap.sign-in+json';
|
|
34
|
+
export const PAP_CONFIRM_TYPE = 'application/vnd.datalayer.pap.confirm+json';
|
|
35
|
+
export const PAP_OUTCOME_TYPE = 'application/vnd.datalayer.pap.outcome+json';
|
|
36
|
+
export const PAP_REPLIES_TYPE = 'application/vnd.datalayer.pap.replies+json';
|
|
37
|
+
/** Where a tool result carries its display for the page. */
|
|
38
|
+
export const DISPLAY_META_KEY = 'reactor.ui/display';
|
|
39
|
+
const record = (value) => value && typeof value === 'object' && !Array.isArray(value)
|
|
40
|
+
? value
|
|
41
|
+
: null;
|
|
42
|
+
const text = (value) => typeof value === 'string' ? value : '';
|
|
43
|
+
const words = (value) => text(value).trim();
|
|
44
|
+
const count = (value) => typeof value === 'number' && Number.isInteger(value) && value >= 1
|
|
45
|
+
? value
|
|
46
|
+
: 0;
|
|
47
|
+
const ACTIONS = [
|
|
48
|
+
'read',
|
|
49
|
+
'write',
|
|
50
|
+
'send',
|
|
51
|
+
'buy',
|
|
52
|
+
'delete',
|
|
53
|
+
'publish',
|
|
54
|
+
];
|
|
55
|
+
const OUTCOMES = [
|
|
56
|
+
'in_progress',
|
|
57
|
+
'succeeded',
|
|
58
|
+
'failed',
|
|
59
|
+
'cancelled',
|
|
60
|
+
'expired',
|
|
61
|
+
];
|
|
62
|
+
const STATUSES = ['working', 'idle', 'queued', 'closed'];
|
|
63
|
+
const who = (value) => value === 'agent' || value === 'human' ? value : null;
|
|
64
|
+
/** A display's wire (`{type, version, id, text, data}`) decoded, or `unknown` with its text. */
|
|
65
|
+
export function protocolDisplayOf(wire) {
|
|
66
|
+
const shown = record(wire);
|
|
67
|
+
if (!shown || !text(shown.type)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const id = text(shown.id);
|
|
71
|
+
const data = record(shown.data) ?? {};
|
|
72
|
+
const unknown = {
|
|
73
|
+
kind: 'unknown',
|
|
74
|
+
id,
|
|
75
|
+
type: text(shown.type),
|
|
76
|
+
version: typeof shown.version === 'number' ? shown.version : 0,
|
|
77
|
+
text: text(shown.text),
|
|
78
|
+
};
|
|
79
|
+
switch (shown.type) {
|
|
80
|
+
case PAP_SIGN_IN_TYPE: {
|
|
81
|
+
const read = readPapSignIn({ status: 'waiting_for_the_person', ...data });
|
|
82
|
+
if (!read)
|
|
83
|
+
return unknown;
|
|
84
|
+
return 'refused' in read
|
|
85
|
+
? { kind: 'sign-in-refused', id, why: read.refused }
|
|
86
|
+
: { kind: 'sign-in', id, ...read };
|
|
87
|
+
}
|
|
88
|
+
case PAP_CONFIRM_TYPE: {
|
|
89
|
+
const company = words(data.company);
|
|
90
|
+
const summary = text(data.summary);
|
|
91
|
+
const operationRef = words(data.operation_ref);
|
|
92
|
+
const revision = count(data.revision);
|
|
93
|
+
const terms = record(data.terms);
|
|
94
|
+
const was = record(data.was);
|
|
95
|
+
const wasRevision = was ? count(was.revision) : 0;
|
|
96
|
+
if (!company ||
|
|
97
|
+
!summary.trim() ||
|
|
98
|
+
!operationRef ||
|
|
99
|
+
!revision ||
|
|
100
|
+
!terms ||
|
|
101
|
+
!id.endsWith('-confirm')) {
|
|
102
|
+
return unknown;
|
|
103
|
+
}
|
|
104
|
+
if (was && (!wasRevision || wasRevision >= revision)) {
|
|
105
|
+
return unknown;
|
|
106
|
+
}
|
|
107
|
+
const does = data.does === null || data.does === undefined
|
|
108
|
+
? null
|
|
109
|
+
: ACTIONS.find(a => a === data.does);
|
|
110
|
+
if (does === undefined)
|
|
111
|
+
return unknown;
|
|
112
|
+
const session = record(data.session);
|
|
113
|
+
return {
|
|
114
|
+
kind: 'confirm',
|
|
115
|
+
id,
|
|
116
|
+
approvalId: id.slice(0, -'-confirm'.length),
|
|
117
|
+
company,
|
|
118
|
+
summary,
|
|
119
|
+
terms,
|
|
120
|
+
operationRef,
|
|
121
|
+
revision,
|
|
122
|
+
does,
|
|
123
|
+
signedIn: session && typeof session.signed_in === 'boolean'
|
|
124
|
+
? session.signed_in
|
|
125
|
+
: null,
|
|
126
|
+
expiresAt: text(data.expires_at),
|
|
127
|
+
was: was
|
|
128
|
+
? { revision: wasRevision, terms: record(was.terms) ?? {} }
|
|
129
|
+
: null,
|
|
130
|
+
onlyThePerson: data.only_the_person === true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
case PAP_OUTCOME_TYPE: {
|
|
134
|
+
const state = OUTCOMES.find(s => s === data.state);
|
|
135
|
+
const company = words(data.company);
|
|
136
|
+
const summary = text(data.summary);
|
|
137
|
+
const result = text(data.result);
|
|
138
|
+
if (!state ||
|
|
139
|
+
!company ||
|
|
140
|
+
!summary.trim() ||
|
|
141
|
+
!words(data.operation_ref) ||
|
|
142
|
+
!count(data.revision)) {
|
|
143
|
+
return unknown;
|
|
144
|
+
}
|
|
145
|
+
// Final, it says what it came to in the company's words; in progress, nothing yet.
|
|
146
|
+
if ((state === 'in_progress') !== !result.trim())
|
|
147
|
+
return unknown;
|
|
148
|
+
return {
|
|
149
|
+
kind: 'outcome',
|
|
150
|
+
id,
|
|
151
|
+
company,
|
|
152
|
+
summary,
|
|
153
|
+
operationRef: words(data.operation_ref),
|
|
154
|
+
revision: count(data.revision),
|
|
155
|
+
state,
|
|
156
|
+
result,
|
|
157
|
+
approvedBy: data.approved_by === 'user' ||
|
|
158
|
+
data.approved_by === 'standing_permission'
|
|
159
|
+
? data.approved_by
|
|
160
|
+
: null,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
case PAP_REPLIES_TYPE: {
|
|
164
|
+
const company = words(data.company);
|
|
165
|
+
const conversation = text(data.conversation);
|
|
166
|
+
const replies = Array.isArray(data.replies)
|
|
167
|
+
? data.replies.map(record).map(reply => ({
|
|
168
|
+
sender: who(reply?.sender),
|
|
169
|
+
text: text(reply?.text),
|
|
170
|
+
}))
|
|
171
|
+
: [];
|
|
172
|
+
if (!company ||
|
|
173
|
+
!/^[A-Za-z0-9_-]{1,256}$/.test(conversation) ||
|
|
174
|
+
!replies.length ||
|
|
175
|
+
replies.some(reply => !reply.sender || !reply.text.trim())) {
|
|
176
|
+
return unknown;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
kind: 'replies',
|
|
180
|
+
id,
|
|
181
|
+
company,
|
|
182
|
+
conversation,
|
|
183
|
+
replies: replies,
|
|
184
|
+
status: STATUSES.find(s => s === data.status) ?? null,
|
|
185
|
+
responder: who(data.responder),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
default:
|
|
189
|
+
return unknown;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** `pap_handoff`, as the gateway names it with or without a prefix. */
|
|
193
|
+
export const PAP_HANDOFF_TOOL = /(^|[_.:\-/])pap_handoff$/;
|
|
194
|
+
/**
|
|
195
|
+
* The protocol display of a tool's result, or `null` for one that has none:
|
|
196
|
+
* its embedded display first; else a plain `pap_sign_in`/`pact_sign_in`
|
|
197
|
+
* answer or a `pap_handoff` answer, read by the tool's name.
|
|
198
|
+
*/
|
|
199
|
+
export function displayOfToolResult(toolName, result, id = '') {
|
|
200
|
+
const answer = record(result);
|
|
201
|
+
const embedded = record(answer?._meta)?.[DISPLAY_META_KEY];
|
|
202
|
+
if (embedded !== undefined) {
|
|
203
|
+
return protocolDisplayOf(embedded);
|
|
204
|
+
}
|
|
205
|
+
if (isPapSignInTool(toolName)) {
|
|
206
|
+
const read = readPapSignIn(result);
|
|
207
|
+
if (!read)
|
|
208
|
+
return null;
|
|
209
|
+
return 'refused' in read
|
|
210
|
+
? { kind: 'sign-in-refused', id, why: read.refused }
|
|
211
|
+
: { kind: 'sign-in', id, ...read };
|
|
212
|
+
}
|
|
213
|
+
if (PAP_HANDOFF_TOOL.test(toolName) && answer) {
|
|
214
|
+
const status = text(answer.status);
|
|
215
|
+
if (!status)
|
|
216
|
+
return null;
|
|
217
|
+
return {
|
|
218
|
+
kind: 'handoff',
|
|
219
|
+
id,
|
|
220
|
+
handed: status !== 'closed' && status !== 'direct_conversation_open',
|
|
221
|
+
responder: who(answer.responder),
|
|
222
|
+
note: text(answer.note),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
/** What each display says in one line, for a screen reader and a collapsed row. */
|
|
228
|
+
export function displayLine(display) {
|
|
229
|
+
switch (display.kind) {
|
|
230
|
+
case 'sign-in':
|
|
231
|
+
return display.mode === 'mediated'
|
|
232
|
+
? `Sign in through ${display.host}`
|
|
233
|
+
: `Sign in at ${display.company || display.host}`;
|
|
234
|
+
case 'sign-in-refused':
|
|
235
|
+
return display.why;
|
|
236
|
+
case 'confirm':
|
|
237
|
+
return `${display.company} asks you to confirm: ${display.summary} (version ${display.revision})`;
|
|
238
|
+
case 'outcome':
|
|
239
|
+
return display.state === 'in_progress'
|
|
240
|
+
? `Still in progress at ${display.company}: ${display.summary}`
|
|
241
|
+
: `${OUTCOME_LEADS[display.state]} ${display.company}: ${display.result}`;
|
|
242
|
+
case 'replies':
|
|
243
|
+
return `${display.company} answered${display.responder === 'human' ? ': one of its people is answering' : ''}`;
|
|
244
|
+
case 'handoff':
|
|
245
|
+
return display.handed
|
|
246
|
+
? `Handed to ${display.responder === 'human' ? 'one of the company’s people' : 'the company'}`
|
|
247
|
+
: display.note || 'Nothing was handed over.';
|
|
248
|
+
case 'unknown':
|
|
249
|
+
return display.text || `A display this app cannot draw (${display.type})`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const OUTCOME_LEADS = {
|
|
253
|
+
succeeded: 'Done at',
|
|
254
|
+
failed: 'Failed at',
|
|
255
|
+
cancelled: 'Cancelled at',
|
|
256
|
+
expired: 'Expired at',
|
|
257
|
+
};
|
|
258
|
+
/** Who wrote a reply, said apart from the person's words and the agent's summaries (PAP-7.8-01). */
|
|
259
|
+
export const replyAuthor = (company, sender) => sender === 'human'
|
|
260
|
+
? `${company}, one of its people`
|
|
261
|
+
: `${company}, its agent`;
|
package/lib/portable/fixtures.js
CHANGED
|
@@ -32,6 +32,7 @@ export function conversationFixture() {
|
|
|
32
32
|
status: 'complete',
|
|
33
33
|
result: 'Shipped on Monday.',
|
|
34
34
|
error: '',
|
|
35
|
+
display: null,
|
|
35
36
|
},
|
|
36
37
|
{
|
|
37
38
|
kind: 'tool',
|
|
@@ -41,6 +42,7 @@ export function conversationFixture() {
|
|
|
41
42
|
status: 'error',
|
|
42
43
|
result: '',
|
|
43
44
|
error: 'Refused by its rule.',
|
|
45
|
+
display: null,
|
|
44
46
|
},
|
|
45
47
|
{
|
|
46
48
|
kind: 'step',
|
package/lib/portable/index.d.ts
CHANGED
|
@@ -13,7 +13,12 @@ export { ASKED_FOR_TAG, askedOf, RUN_END_WORDS } from './records';
|
|
|
13
13
|
export { messagesOfThread, openThread, snapshotOfStream, THREAD_WORDS, } from './thread';
|
|
14
14
|
export { CUT_MARK, DIAGNOSTIC_LIMIT, emptyConversation, formFieldsOf, ITEM_LIMIT, MESSAGE_TEXT_LIMIT, questionOf, questionWords, reduceConversation, TOOL_TEXT_LIMIT, withError, withPrompt, withTurnEnded, type ConversationItem, type ConversationQuestion, type ConversationState, type TurnEnd, } from './conversation';
|
|
15
15
|
export { PRESENCE_LINES, presenceOfConversation, presenceState, presenceToolOf, type PresenceState, type PresenceTool, } from './presence';
|
|
16
|
-
export { ANSWER_BELOW, ANSWER_COMPLETE, composerOf, droppedWords, ENDED_WORDS, messageLabel, OPENING_WORDS, presenceLine, showsQuestion, stepLine, TOOL_STATUS_WORDS, toolLabel, type ComposerProps, type ComposerState, type ConversationViewProps, type ErrorItem, type ErrorRowProps, type MessageItem, type MessageRowProps, type PresenceLineProps, type QuestionCardProps, type StepItem, type StepRowProps, type ToolItem, type ToolRowProps, type TurnEndItem, type TurnEndRowProps, } from './views';
|
|
16
|
+
export { ANSWER_BELOW, ANSWER_COMPLETE, composerOf, droppedWords, ENDED_WORDS, messageLabel, OPENING_WORDS, presenceLine, showsQuestion, stepLine, TOOL_STATUS_WORDS, toolLabel, type ComposerProps, type ComposerState, type ConversationViewProps, type ErrorItem, type ErrorRowProps, type MessageItem, type MessageRowProps, type PresenceLineProps, type ProtocolDisplayProps, type QuestionCardProps, type StepItem, type StepRowProps, type ToolItem, type ToolRowProps, type TurnEndItem, type TurnEndRowProps, } from './views';
|
|
17
17
|
export { conversationFixture } from './fixtures';
|
|
18
|
+
export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor, type ActionClass, type ProtocolDisplay, } from './displays';
|
|
19
|
+
export { isPapSignInTool, PAP_SIGN_IN_WORDS, readPapSignIn, safeSignInUrl, type PapSignInWaiting, } from './signIn';
|
|
20
|
+
export { DIRECT_MAX, DIRECT_WORDS, directAnswerOf, directAuthor, directClient, openDirect, withDirectAnswer, type DirectAnswer, type DirectClient, type DirectClientOptions, type DirectLine, type DirectOpen, type DirectReply, type DirectTarget, } from './direct';
|
|
21
|
+
export { SIGN_IN_POLL_MS, SIGN_IN_STATUS_PATH, signInStandsOf, signInStatusClient, type SignInStands, } from './signInStatus';
|
|
22
|
+
export { emptyFields, fieldProblems, MAX_VALUE_LENGTH, PROTECTED_INPUT_WORDS, protectedInputClient, protectedRequestOf, ProtectedRequestGone, sentWords, submitBody, submitWords, ticketComplete, ticketOfPage, type ProtectedField, type ProtectedRequest, } from './protectedInput';
|
|
18
23
|
export { agentRunClient, agentRuntimesUrlOf, appSessionsClient, RuntimeRefusal, type AgentRunClient, type AgentTurn, type AppSessionsClient, type RuntimeClientOptions, type SessionStart, type StreamOptions, } from './sessions';
|
|
19
24
|
export type { ChatMessage } from '../types/messages';
|
package/lib/portable/index.js
CHANGED
|
@@ -24,5 +24,14 @@ export { PRESENCE_LINES, presenceOfConversation, presenceState, presenceToolOf,
|
|
|
24
24
|
// One contract for every renderer of a conversation's components.
|
|
25
25
|
export { ANSWER_BELOW, ANSWER_COMPLETE, composerOf, droppedWords, ENDED_WORDS, messageLabel, OPENING_WORDS, presenceLine, showsQuestion, stepLine, TOOL_STATUS_WORDS, toolLabel, } from './views';
|
|
26
26
|
export { conversationFixture } from './fixtures';
|
|
27
|
+
// The protocol displays a run's tool results carry (MOBILE M-037).
|
|
28
|
+
export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor, } from './displays';
|
|
29
|
+
export { isPapSignInTool, PAP_SIGN_IN_WORDS, readPapSignIn, safeSignInUrl, } from './signIn';
|
|
30
|
+
// A Direct Conversation the person types in themselves (PAP_DATALAYER P-08, MOBILE M-038).
|
|
31
|
+
export { DIRECT_MAX, DIRECT_WORDS, directAnswerOf, directAuthor, directClient, openDirect, withDirectAnswer, } from './direct';
|
|
32
|
+
// How a sign-in under way stands, asked by the person's own client (MOBILE M-039).
|
|
33
|
+
export { SIGN_IN_POLL_MS, SIGN_IN_STATUS_PATH, signInStandsOf, signInStatusClient, } from './signInStatus';
|
|
34
|
+
// What a company asks the person to type in a mediated sign-in, sent with its one-use ticket (MOBILE M-039).
|
|
35
|
+
export { emptyFields, fieldProblems, MAX_VALUE_LENGTH, PROTECTED_INPUT_WORDS, protectedInputClient, protectedRequestOf, ProtectedRequestGone, sentWords, submitBody, submitWords, ticketComplete, ticketOfPage, } from './protectedInput';
|
|
27
36
|
// The runtime's routes a native client drives.
|
|
28
37
|
export { agentRunClient, agentRuntimesUrlOf, appSessionsClient, RuntimeRefusal, } from './sessions';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mediated sign-in (PAP_DATALAYER P-03, MOBILE M-039): a personal agent signs
|
|
3
|
+
* the person in at a company that asks for what only the person knows — a
|
|
4
|
+
* name and a password, or a code the company sent them. The person types it
|
|
5
|
+
* on a page of their own Datalayer client, signed in to Datalayer; it goes
|
|
6
|
+
* to IAM with the one-use protected ticket the sign-in named
|
|
7
|
+
* (`/pap/my/protected/{ticket}`), which passes it to the company once. The
|
|
8
|
+
* agent never sees it. The Studio's `/pap/sign-in` and Datalayer Mobile use
|
|
9
|
+
* this one module.
|
|
10
|
+
*
|
|
11
|
+
* Pure but for the given `fetch`: nothing typed is kept — not in an address,
|
|
12
|
+
* not in storage, not in an error.
|
|
13
|
+
*
|
|
14
|
+
* @module portable/protectedInput
|
|
15
|
+
*/
|
|
16
|
+
/** One thing the company asks the person to type. */
|
|
17
|
+
export type ProtectedField = {
|
|
18
|
+
name: string;
|
|
19
|
+
label: string;
|
|
20
|
+
/** Typed as a password: hidden, never filled in by the browser. */
|
|
21
|
+
secret: boolean;
|
|
22
|
+
};
|
|
23
|
+
/** What the company asks, of whom, until when. */
|
|
24
|
+
export type ProtectedRequest = {
|
|
25
|
+
companyName: string;
|
|
26
|
+
/** The company's own domain: what the person can check. */
|
|
27
|
+
companyDomain: string;
|
|
28
|
+
purpose: 'credentials' | 'one_time_code';
|
|
29
|
+
fields: ProtectedField[];
|
|
30
|
+
/** Where the company sent its code, when it did. */
|
|
31
|
+
sentTo: string | null;
|
|
32
|
+
expiresAt: string;
|
|
33
|
+
};
|
|
34
|
+
/** What IAM keeps of one field, at most. */
|
|
35
|
+
export declare const MAX_VALUE_LENGTH = 1024;
|
|
36
|
+
/** What the page says (checked against the vocabulary). */
|
|
37
|
+
export declare const PROTECTED_INPUT_WORDS: {
|
|
38
|
+
readonly title: (company: string) => string;
|
|
39
|
+
readonly intro: (company: string) => string;
|
|
40
|
+
readonly asks: "Who asks";
|
|
41
|
+
readonly where: "Where";
|
|
42
|
+
readonly whereHint: "The company’s address: the part you can check.";
|
|
43
|
+
readonly sentCode: (company: string, sentTo: string) => string;
|
|
44
|
+
readonly sentCodeSomewhere: (company: string) => string;
|
|
45
|
+
readonly code: "Code";
|
|
46
|
+
readonly signIn: (company: string) => string;
|
|
47
|
+
readonly sendCode: "Send the code";
|
|
48
|
+
readonly sending: "Sending…";
|
|
49
|
+
readonly fillEvery: "Fill in every field.";
|
|
50
|
+
readonly tooLong: (label: string) => string;
|
|
51
|
+
readonly done: "Done. Go back to your conversation: the agent continues once it checks.";
|
|
52
|
+
readonly expires: (at: string) => string;
|
|
53
|
+
readonly reading: "Reading the request…";
|
|
54
|
+
readonly gone: "This request is unknown, already answered or expired. Ask your personal agent to start again.";
|
|
55
|
+
readonly incomplete: "This link is incomplete: it names no request. Start again from your personal agent.";
|
|
56
|
+
readonly signedOut: "Sign in to Datalayer first.";
|
|
57
|
+
};
|
|
58
|
+
/** Whether a link names a request. */
|
|
59
|
+
export declare const ticketComplete: (ticket: string) => boolean;
|
|
60
|
+
/** Raised when IAM does not know the request (unknown, answered or expired): the page says only that. */
|
|
61
|
+
export declare class ProtectedRequestGone extends Error {
|
|
62
|
+
constructor();
|
|
63
|
+
}
|
|
64
|
+
/** IAM's answer read whole, or refused with a sentence: no default. */
|
|
65
|
+
export declare function protectedRequestOf(raw: unknown): ProtectedRequest;
|
|
66
|
+
/** The fields still empty, by name: the form is sent only when there is none. */
|
|
67
|
+
export declare const emptyFields: (request: Pick<ProtectedRequest, "fields">, values: Record<string, string>) => string[];
|
|
68
|
+
/** What keeps the form from being sent, in sentences; none when it can be. Never what was typed. */
|
|
69
|
+
export declare function fieldProblems(request: Pick<ProtectedRequest, 'fields'>, values: Record<string, string>): string[];
|
|
70
|
+
/** The words on the one button. */
|
|
71
|
+
export declare const submitWords: (request: Pick<ProtectedRequest, "purpose" | "companyName">) => string;
|
|
72
|
+
/** What the code page says of where the code went. */
|
|
73
|
+
export declare const sentWords: (request: Pick<ProtectedRequest, "companyName" | "sentTo">) => string;
|
|
74
|
+
/**
|
|
75
|
+
* The body sent: exactly the fields asked, none empty, as typed. A code is
|
|
76
|
+
* sent without its spaces; a password, exactly as typed.
|
|
77
|
+
*/
|
|
78
|
+
export declare function submitBody(request: Pick<ProtectedRequest, 'fields' | 'purpose'>, values: Record<string, string>): {
|
|
79
|
+
values: Record<string, string>;
|
|
80
|
+
};
|
|
81
|
+
/** The ticket a mediated sign-in page names (`…?ticket=`), or `''`. */
|
|
82
|
+
export declare function ticketOfPage(open: string): string;
|
|
83
|
+
/** IAM's protected-input routes, with the person's own sign-in. */
|
|
84
|
+
export declare function protectedInputClient({ iamUrl, getAccessToken, fetch: fetcher, }: {
|
|
85
|
+
iamUrl: string;
|
|
86
|
+
getAccessToken: () => string | undefined;
|
|
87
|
+
fetch: typeof fetch;
|
|
88
|
+
}): {
|
|
89
|
+
/** What the company asks; reading it does not use the request up. */
|
|
90
|
+
read: (ticket: string) => Promise<ProtectedRequest>;
|
|
91
|
+
/** What the person typed, sent once to IAM. */
|
|
92
|
+
send: (ticket: string, request: Pick<ProtectedRequest, "fields" | "purpose">, values: Record<string, string>) => Promise<void>;
|
|
93
|
+
};
|