@opengeni/react-native 1.4.5-canary.37615713321001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +74 -0
- package/dist/adapters.d.ts +53 -0
- package/dist/adapters.js +3 -0
- package/dist/adapters.js.map +1 -0
- package/dist/attachments.d.ts +75 -0
- package/dist/chunk-3VSZAQ7G.js +391 -0
- package/dist/chunk-3VSZAQ7G.js.map +1 -0
- package/dist/chunk-5ZVK7WKA.js +88 -0
- package/dist/chunk-5ZVK7WKA.js.map +1 -0
- package/dist/chunk-EEDIMY3L.js +240 -0
- package/dist/chunk-EEDIMY3L.js.map +1 -0
- package/dist/chunk-M23SDI4R.js +83 -0
- package/dist/chunk-M23SDI4R.js.map +1 -0
- package/dist/chunk-PHJBSAR3.js +2006 -0
- package/dist/chunk-PHJBSAR3.js.map +1 -0
- package/dist/environment.d.ts +19 -0
- package/dist/expo.d.ts +25 -0
- package/dist/expo.js +267 -0
- package/dist/expo.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +3345 -0
- package/dist/index.js.map +1 -0
- package/dist/presentation.d.ts +262 -0
- package/dist/read-acknowledgement.d.ts +39 -0
- package/dist/realtime/call-events.d.ts +11 -0
- package/dist/realtime/call-view.d.ts +26 -0
- package/dist/realtime/expo-call.d.ts +11 -0
- package/dist/realtime/native-call.d.ts +104 -0
- package/dist/realtime/native-realtime.d.ts +35 -0
- package/dist/realtime/use-native-session-realtime.d.ts +25 -0
- package/dist/session-view.d.ts +87 -0
- package/dist/timeline/activity.d.ts +34 -0
- package/dist/timeline/composer.d.ts +86 -0
- package/dist/timeline/controls.d.ts +27 -0
- package/dist/timeline/decisions.d.ts +29 -0
- package/dist/timeline/feedback.d.ts +26 -0
- package/dist/timeline/icon-nodes.generated.d.ts +738 -0
- package/dist/timeline/icon.d.ts +11 -0
- package/dist/timeline/index.d.ts +32 -0
- package/dist/timeline/index.js +5419 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/markdown.d.ts +11 -0
- package/dist/timeline/markdown.js +415 -0
- package/dist/timeline/markdown.js.map +1 -0
- package/dist/timeline/message-attachments.d.ts +13 -0
- package/dist/timeline/message-timeline.d.ts +36 -0
- package/dist/timeline/model-picker.d.ts +17 -0
- package/dist/timeline/primitives.d.ts +85 -0
- package/dist/timeline/queue-dock.d.ts +19 -0
- package/dist/timeline/session-actions.d.ts +34 -0
- package/dist/timeline/session-list.d.ts +50 -0
- package/dist/timeline/session-screen.d.ts +35 -0
- package/dist/timeline/session-signals.d.ts +37 -0
- package/dist/timeline/sheet.d.ts +14 -0
- package/dist/timeline/theme.d.ts +58 -0
- package/dist/timeline/thinking-orb.d.ts +13 -0
- package/dist/timeline/turn.d.ts +80 -0
- package/dist/ui/attention.d.ts +14 -0
- package/dist/ui/cards.d.ts +21 -0
- package/dist/ui/composer.d.ts +21 -0
- package/dist/ui/format.d.ts +13 -0
- package/dist/ui/icons.d.ts +9 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +1757 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/steps-sheet.d.ts +10 -0
- package/dist/ui/theme.d.ts +63 -0
- package/dist/ui/timeline.d.ts +48 -0
- package/dist/ui/web-tokens.gen.d.ts +90 -0
- package/dist/use-native-session.d.ts +40 -0
- package/dist/view-model.d.ts +52 -0
- package/dist/voice-input.d.ts +102 -0
- package/dist/webrtc.d.ts +9 -0
- package/dist/webrtc.js +19 -0
- package/dist/webrtc.js.map +1 -0
- package/expo-module.config.json +7 -0
- package/ios/OpenGeniCall.podspec +22 -0
- package/ios/OpenGeniCallAppDelegateSubscriber.swift +29 -0
- package/ios/OpenGeniCallCenter.swift +189 -0
- package/ios/OpenGeniCallModule.swift +64 -0
- package/package.json +93 -0
- package/src/adapters.ts +150 -0
- package/src/attachments.ts +396 -0
- package/src/environment.tsx +214 -0
- package/src/expo.ts +295 -0
- package/src/index.ts +98 -0
- package/src/presentation.ts +285 -0
- package/src/read-acknowledgement.ts +72 -0
- package/src/realtime/call-events.ts +41 -0
- package/src/realtime/call-view.tsx +220 -0
- package/src/realtime/expo-call.ts +49 -0
- package/src/realtime/native-call.ts +266 -0
- package/src/realtime/native-realtime.ts +115 -0
- package/src/realtime/use-native-session-realtime.ts +29 -0
- package/src/session-view.tsx +2251 -0
- package/src/timeline/activity.tsx +736 -0
- package/src/timeline/composer.tsx +686 -0
- package/src/timeline/controls.tsx +151 -0
- package/src/timeline/decisions.tsx +651 -0
- package/src/timeline/feedback.tsx +251 -0
- package/src/timeline/icon-nodes.generated.ts +1830 -0
- package/src/timeline/icon.tsx +44 -0
- package/src/timeline/index.ts +67 -0
- package/src/timeline/markdown.tsx +510 -0
- package/src/timeline/message-attachments.tsx +155 -0
- package/src/timeline/message-timeline.tsx +1042 -0
- package/src/timeline/model-picker.tsx +450 -0
- package/src/timeline/primitives.tsx +561 -0
- package/src/timeline/queue-dock.tsx +331 -0
- package/src/timeline/session-actions.tsx +379 -0
- package/src/timeline/session-list.tsx +338 -0
- package/src/timeline/session-screen.tsx +488 -0
- package/src/timeline/session-signals.tsx +312 -0
- package/src/timeline/sheet.tsx +153 -0
- package/src/timeline/theme.tsx +128 -0
- package/src/timeline/thinking-orb.tsx +93 -0
- package/src/timeline/turn.tsx +569 -0
- package/src/ui/attention.tsx +220 -0
- package/src/ui/cards.tsx +267 -0
- package/src/ui/composer.tsx +296 -0
- package/src/ui/format.ts +86 -0
- package/src/ui/icons.tsx +131 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/steps-sheet.tsx +71 -0
- package/src/ui/theme.ts +261 -0
- package/src/ui/timeline.tsx +837 -0
- package/src/ui/web-tokens.gen.ts +94 -0
- package/src/use-native-session.ts +219 -0
- package/src/view-model.ts +485 -0
- package/src/voice-input.ts +382 -0
- package/src/webrtc.ts +30 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import type { HumanInputAnswer, HumanInputQuestion, SessionStatus } from "@opengeni/sdk";
|
|
2
|
+
import type { ActivityItem, TimelineItem } from "@opengeni/react/session";
|
|
3
|
+
import { DEFAULT_OPENGENI_NATIVE_LABELS, type OpenGeniNativeLabels } from "./presentation";
|
|
4
|
+
|
|
5
|
+
export function nativeKnowledgeOutcomeLabel(
|
|
6
|
+
item: Extract<TimelineItem, { kind: "knowledge" }>,
|
|
7
|
+
labels: OpenGeniNativeLabels,
|
|
8
|
+
): string {
|
|
9
|
+
return (labels.knowledgeOutcome ?? DEFAULT_OPENGENI_NATIVE_LABELS.knowledgeOutcome)[item.outcome];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type NativeSessionStatusTone = "neutral" | "working" | "attention" | "failed" | "complete";
|
|
13
|
+
|
|
14
|
+
export interface NativeActivityPresentation {
|
|
15
|
+
title: string;
|
|
16
|
+
preview: string;
|
|
17
|
+
status: string | null;
|
|
18
|
+
detail: string | null;
|
|
19
|
+
expandedByDefault: boolean;
|
|
20
|
+
tone: "neutral" | "running" | "failed";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function nativeSessionStatusTone(status: SessionStatus | null): NativeSessionStatusTone {
|
|
24
|
+
switch (status) {
|
|
25
|
+
case "queued":
|
|
26
|
+
case "running":
|
|
27
|
+
case "recovering":
|
|
28
|
+
case "waiting_capacity":
|
|
29
|
+
return "working";
|
|
30
|
+
case "requires_action":
|
|
31
|
+
return "attention";
|
|
32
|
+
case "failed":
|
|
33
|
+
return "failed";
|
|
34
|
+
case "cancelled":
|
|
35
|
+
return "complete";
|
|
36
|
+
default:
|
|
37
|
+
return "neutral";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function boundedJson(value: unknown, maximum = 1_200): string {
|
|
42
|
+
let serialized: string;
|
|
43
|
+
try {
|
|
44
|
+
serialized = JSON.stringify(value, null, 2) ?? "";
|
|
45
|
+
} catch {
|
|
46
|
+
serialized = String(value);
|
|
47
|
+
}
|
|
48
|
+
return serialized.length <= maximum ? serialized : `${serialized.slice(0, maximum)}…`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function plainTextContent(value: string): string {
|
|
52
|
+
return value
|
|
53
|
+
.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1")
|
|
54
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
|
|
55
|
+
.replace(/^\s{0,3}(?:#{1,6}|>|[-+])\s+/gm, "")
|
|
56
|
+
.replace(/\*\*|__|~~|`/g, "")
|
|
57
|
+
.replace(/(^|\s)[*_](?=\S)/g, "$1")
|
|
58
|
+
.replace(/(?<=\S)[*_](?=\s|$|[.,!?;:])/g, "")
|
|
59
|
+
.trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizedPreview(value: string, maximum = 140): string {
|
|
63
|
+
const normalized = plainTextContent(value).replace(/\s+/g, " ").trim();
|
|
64
|
+
if (!normalized) return "";
|
|
65
|
+
return normalized.length <= maximum ? normalized : `${normalized.slice(0, maximum - 1)}…`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function recordPreview(value: object): string {
|
|
69
|
+
for (const key of ["summary", "message", "title", "name", "status", "text", "query", "cmd"]) {
|
|
70
|
+
const candidate: unknown = Reflect.get(value, key);
|
|
71
|
+
if (typeof candidate === "string") {
|
|
72
|
+
const preview = normalizedPreview(candidate);
|
|
73
|
+
if (preview) return preview;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const keys = Object.keys(value);
|
|
77
|
+
return keys.length > 0 ? keys.slice(0, 4).join(", ") : "";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function inspectableValuePreview(value: unknown): string {
|
|
81
|
+
if (typeof value === "string") return normalizedPreview(value);
|
|
82
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
83
|
+
if (Array.isArray(value)) return value.length === 1 ? "1 item" : `${value.length} items`;
|
|
84
|
+
if (value && typeof value === "object") return recordPreview(value);
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function nativeToolDisplayName(name: string): string {
|
|
89
|
+
const boundary = name.indexOf("__");
|
|
90
|
+
const leaf = boundary >= 0 ? name.slice(boundary + 2) : name;
|
|
91
|
+
const phrase = leaf.replace(/[_-]+/g, " ").trim();
|
|
92
|
+
return phrase ? phrase.charAt(0).toLocaleUpperCase() + phrase.slice(1) : name;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function activityStatus(
|
|
96
|
+
item: Extract<ActivityItem, { status: "running" | "complete" | "failed" | "cancelled" }>,
|
|
97
|
+
labels: OpenGeniNativeLabels,
|
|
98
|
+
): {
|
|
99
|
+
status: string | null;
|
|
100
|
+
fallbackStatus: string;
|
|
101
|
+
expandedByDefault: boolean;
|
|
102
|
+
tone: NativeActivityPresentation["tone"];
|
|
103
|
+
} {
|
|
104
|
+
const fallbackStatus = nativeTimelineStatusLabel(item.status, labels);
|
|
105
|
+
return {
|
|
106
|
+
status: item.status === "complete" ? null : fallbackStatus,
|
|
107
|
+
fallbackStatus,
|
|
108
|
+
expandedByDefault: item.status === "failed",
|
|
109
|
+
tone: item.status === "running" ? "running" : item.status === "failed" ? "failed" : "neutral",
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function nativeActivityPresentation(
|
|
114
|
+
item: ActivityItem,
|
|
115
|
+
labels: OpenGeniNativeLabels,
|
|
116
|
+
): NativeActivityPresentation {
|
|
117
|
+
switch (item.kind) {
|
|
118
|
+
case "agent-message":
|
|
119
|
+
return {
|
|
120
|
+
title: labels.assistant,
|
|
121
|
+
preview: normalizedPreview(item.text),
|
|
122
|
+
status: item.streaming ? labels.statusRunning : null,
|
|
123
|
+
detail: plainTextContent(item.text) || null,
|
|
124
|
+
expandedByDefault: false,
|
|
125
|
+
tone: item.streaming ? "running" : "neutral",
|
|
126
|
+
};
|
|
127
|
+
case "reasoning":
|
|
128
|
+
return {
|
|
129
|
+
title: item.streaming ? labels.thinking : labels.thought,
|
|
130
|
+
preview: normalizedPreview(item.text),
|
|
131
|
+
status: item.streaming ? labels.statusRunning : null,
|
|
132
|
+
detail: plainTextContent(item.text) || null,
|
|
133
|
+
expandedByDefault: false,
|
|
134
|
+
tone: item.streaming ? "running" : "neutral",
|
|
135
|
+
};
|
|
136
|
+
case "tool-call": {
|
|
137
|
+
const outputPreview = inspectableValuePreview(item.output);
|
|
138
|
+
const argumentPreview = inspectableValuePreview(item.arguments);
|
|
139
|
+
const status = activityStatus(item, labels);
|
|
140
|
+
return {
|
|
141
|
+
title: nativeToolDisplayName(item.name),
|
|
142
|
+
preview: outputPreview || argumentPreview || status.fallbackStatus,
|
|
143
|
+
detail: boundedJson({
|
|
144
|
+
input: item.arguments,
|
|
145
|
+
...(item.output !== undefined ? { result: item.output } : {}),
|
|
146
|
+
...(item.truncation ? { truncation: item.truncation } : {}),
|
|
147
|
+
}),
|
|
148
|
+
status: status.status,
|
|
149
|
+
expandedByDefault: status.expandedByDefault,
|
|
150
|
+
tone: status.tone,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
case "worker": {
|
|
154
|
+
const status = activityStatus(item, labels);
|
|
155
|
+
return {
|
|
156
|
+
title: labels.worker,
|
|
157
|
+
preview:
|
|
158
|
+
normalizedPreview(item.prompt ?? item.failure?.message ?? "") || status.fallbackStatus,
|
|
159
|
+
detail: item.failure
|
|
160
|
+
? boundedJson(item.failure)
|
|
161
|
+
: item.prompt?.trim() || item.workerSessionId || null,
|
|
162
|
+
status: status.status,
|
|
163
|
+
expandedByDefault: status.expandedByDefault,
|
|
164
|
+
tone: status.tone,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
case "sandbox": {
|
|
168
|
+
const status = activityStatus(item, labels);
|
|
169
|
+
return {
|
|
170
|
+
title: nativeToolDisplayName(item.name || labels.sandbox),
|
|
171
|
+
preview:
|
|
172
|
+
inspectableValuePreview(item.output) ||
|
|
173
|
+
inspectableValuePreview(item.command) ||
|
|
174
|
+
status.fallbackStatus,
|
|
175
|
+
detail: boundedJson({
|
|
176
|
+
...(item.command ? { command: item.command } : {}),
|
|
177
|
+
...(item.output ? { output: item.output } : {}),
|
|
178
|
+
...(item.origin ? { origin: item.origin } : {}),
|
|
179
|
+
}),
|
|
180
|
+
status: status.status,
|
|
181
|
+
expandedByDefault: status.expandedByDefault,
|
|
182
|
+
tone: status.tone,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
case "startup-phase": {
|
|
186
|
+
const status = activityStatus(item, labels);
|
|
187
|
+
return {
|
|
188
|
+
title: nativeToolDisplayName(item.phase),
|
|
189
|
+
preview: item.outcome ? nativeToolDisplayName(item.outcome) : status.fallbackStatus,
|
|
190
|
+
detail:
|
|
191
|
+
item.durationMs == null
|
|
192
|
+
? null
|
|
193
|
+
: `${Math.max(0, Math.round(item.durationMs / 100) / 10)}s`,
|
|
194
|
+
status: status.status,
|
|
195
|
+
expandedByDefault: status.expandedByDefault,
|
|
196
|
+
tone: status.tone,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
case "knowledge":
|
|
200
|
+
return {
|
|
201
|
+
title: nativeKnowledgeOutcomeLabel(item, labels),
|
|
202
|
+
preview: item.filename ?? "",
|
|
203
|
+
status: null,
|
|
204
|
+
detail: item.filename ?? null,
|
|
205
|
+
expandedByDefault: false,
|
|
206
|
+
tone: item.status === "failed" ? "failed" : "neutral",
|
|
207
|
+
};
|
|
208
|
+
case "memory":
|
|
209
|
+
return {
|
|
210
|
+
title: nativeMemoryActionLabel(item, labels),
|
|
211
|
+
preview: normalizedPreview(item.replacementPreview ?? item.preview),
|
|
212
|
+
status: null,
|
|
213
|
+
detail: item.replacementPreview
|
|
214
|
+
? boundedJson({ before: item.preview, after: item.replacementPreview })
|
|
215
|
+
: item.preview,
|
|
216
|
+
expandedByDefault: false,
|
|
217
|
+
tone: "neutral",
|
|
218
|
+
};
|
|
219
|
+
case "fleet-decision": {
|
|
220
|
+
const summary = nativeFleetDecisionSummary(item, labels);
|
|
221
|
+
return {
|
|
222
|
+
title: labels.fleetDecision,
|
|
223
|
+
preview: summary,
|
|
224
|
+
status: null,
|
|
225
|
+
detail: boundedJson({
|
|
226
|
+
outcome: item.actualOutcome,
|
|
227
|
+
reason: item.actualReason,
|
|
228
|
+
admission: item.admissionOutcome,
|
|
229
|
+
candidates: item.candidateCount,
|
|
230
|
+
}),
|
|
231
|
+
expandedByDefault: false,
|
|
232
|
+
tone: item.actualOutcome === "waiting" ? "running" : "neutral",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function formatLabel(template: string, values: Readonly<Record<string, string | number>>): string {
|
|
239
|
+
return Object.entries(values).reduce(
|
|
240
|
+
(formatted, [key, value]) => formatted.split(`{${key}}`).join(String(value)),
|
|
241
|
+
template,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function formatNativeRelativeTime(
|
|
246
|
+
iso: string,
|
|
247
|
+
labels: Pick<
|
|
248
|
+
OpenGeniNativeLabels,
|
|
249
|
+
"relativeNow" | "relativeSeconds" | "relativeMinutes" | "relativeHours" | "relativeDays"
|
|
250
|
+
>,
|
|
251
|
+
now: Date = new Date(),
|
|
252
|
+
): string {
|
|
253
|
+
const then = new Date(iso).getTime();
|
|
254
|
+
if (Number.isNaN(then)) return "";
|
|
255
|
+
|
|
256
|
+
const seconds = Math.max(0, Math.floor((now.getTime() - then) / 1_000));
|
|
257
|
+
if (seconds < 10) return labels.relativeNow;
|
|
258
|
+
if (seconds < 60) return formatLabel(labels.relativeSeconds, { value: seconds });
|
|
259
|
+
|
|
260
|
+
const minutes = Math.floor(seconds / 60);
|
|
261
|
+
if (minutes < 60) return formatLabel(labels.relativeMinutes, { value: minutes });
|
|
262
|
+
|
|
263
|
+
const hours = Math.floor(minutes / 60);
|
|
264
|
+
if (hours < 24) return formatLabel(labels.relativeHours, { value: hours });
|
|
265
|
+
|
|
266
|
+
const days = Math.floor(hours / 24);
|
|
267
|
+
if (days < 14) return formatLabel(labels.relativeDays, { value: days });
|
|
268
|
+
// oxlint-disable-next-line architecture/no-unsafe-date-format -- Timeline age intentionally matches OpenGeni's device-local relative-time formatter; this is not an organization-domain date.
|
|
269
|
+
return new Date(iso).toLocaleDateString();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function nativeTimelineStatusLabel(
|
|
273
|
+
status: "running" | "complete" | "failed" | "cancelled",
|
|
274
|
+
labels: OpenGeniNativeLabels,
|
|
275
|
+
): string {
|
|
276
|
+
switch (status) {
|
|
277
|
+
case "running":
|
|
278
|
+
return labels.statusRunning;
|
|
279
|
+
case "complete":
|
|
280
|
+
return labels.statusComplete;
|
|
281
|
+
case "failed":
|
|
282
|
+
return labels.statusFailed;
|
|
283
|
+
case "cancelled":
|
|
284
|
+
return labels.statusCancelled;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function nativeGoalActionLabel(
|
|
289
|
+
action: Extract<TimelineItem, { kind: "goal" }>["action"],
|
|
290
|
+
labels: OpenGeniNativeLabels,
|
|
291
|
+
): string {
|
|
292
|
+
return labels.goalAction[action];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function nativeHumanInputRequestPreview(
|
|
296
|
+
requests: readonly {
|
|
297
|
+
questions: readonly Pick<HumanInputQuestion, "label" | "prompt">[];
|
|
298
|
+
}[],
|
|
299
|
+
): string {
|
|
300
|
+
return requests
|
|
301
|
+
.flatMap((request) =>
|
|
302
|
+
request.questions.map((question) => question.label?.trim() || question.prompt.trim()),
|
|
303
|
+
)
|
|
304
|
+
.filter((label) => label.length > 0)
|
|
305
|
+
.join(" · ");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function nativeHumanInputSummary(
|
|
309
|
+
item: Extract<TimelineItem, { kind: "human-input" }>,
|
|
310
|
+
labels: OpenGeniNativeLabels,
|
|
311
|
+
): string {
|
|
312
|
+
const questions = item.questions
|
|
313
|
+
.map((question) => (question.label ? `${question.label}: ${question.prompt}` : question.prompt))
|
|
314
|
+
.join("\n");
|
|
315
|
+
const outcome = labels.humanInputOutcome[item.response.outcome];
|
|
316
|
+
const answers = item.answers
|
|
317
|
+
.map(
|
|
318
|
+
(answer) =>
|
|
319
|
+
`${answer.label}: ${answer.values.join(", ") || labels.humanInputOutcome.answered}`,
|
|
320
|
+
)
|
|
321
|
+
.join("\n");
|
|
322
|
+
|
|
323
|
+
return [questions, answers ? `${outcome}: ${answers}` : outcome].filter(Boolean).join("\n");
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function nativeContextCompactionPhaseLabel(
|
|
327
|
+
phase: Extract<TimelineItem, { kind: "context-compaction" }>["phase"],
|
|
328
|
+
labels: OpenGeniNativeLabels,
|
|
329
|
+
): string {
|
|
330
|
+
return labels.contextCompactionPhase[phase];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function nativeMemoryActionLabel(
|
|
334
|
+
item: Extract<TimelineItem, { kind: "memory" }>,
|
|
335
|
+
labels: OpenGeniNativeLabels,
|
|
336
|
+
): string {
|
|
337
|
+
if (item.variant === "saved") return labels.memoryAction.saved;
|
|
338
|
+
if (item.replacementPreview) return labels.memoryAction.corrected;
|
|
339
|
+
return item.action === "updated" ? labels.memoryAction.updated : labels.memoryAction.archived;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function nativeFleetDecisionSummary(
|
|
343
|
+
item: Extract<TimelineItem, { kind: "fleet-decision" }>,
|
|
344
|
+
labels: OpenGeniNativeLabels,
|
|
345
|
+
): string {
|
|
346
|
+
const outcome =
|
|
347
|
+
item.actualOutcome === "selected" && item.actualCandidateKey
|
|
348
|
+
? formatLabel(labels.fleetOutcome.selected, { candidate: item.actualCandidateKey })
|
|
349
|
+
: item.actualOutcome === "waiting"
|
|
350
|
+
? labels.fleetOutcome.waiting
|
|
351
|
+
: labels.fleetOutcome.none;
|
|
352
|
+
const reason = (() => {
|
|
353
|
+
switch (item.actualReason) {
|
|
354
|
+
case "lease_reused":
|
|
355
|
+
return labels.fleetReason.leaseReused;
|
|
356
|
+
case "pin":
|
|
357
|
+
return labels.fleetReason.pin;
|
|
358
|
+
case "rotation":
|
|
359
|
+
return labels.fleetReason.rotation;
|
|
360
|
+
case "active":
|
|
361
|
+
return labels.fleetReason.active;
|
|
362
|
+
case "all_capped":
|
|
363
|
+
return labels.fleetReason.allCapped;
|
|
364
|
+
case "none":
|
|
365
|
+
return labels.fleetReason.none;
|
|
366
|
+
}
|
|
367
|
+
})();
|
|
368
|
+
return `${outcome} · ${reason}`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function timelineAccessibilityLabel(
|
|
372
|
+
item: TimelineItem,
|
|
373
|
+
labels: OpenGeniNativeLabels,
|
|
374
|
+
): string {
|
|
375
|
+
switch (item.kind) {
|
|
376
|
+
case "user-message":
|
|
377
|
+
return `${labels.user}: ${item.text}`;
|
|
378
|
+
case "human-input":
|
|
379
|
+
return `${labels.humanInputAsked}: ${nativeHumanInputSummary(item, labels)}`;
|
|
380
|
+
case "agent-message":
|
|
381
|
+
return `${labels.assistant}: ${item.text}`;
|
|
382
|
+
case "reasoning":
|
|
383
|
+
return `${labels.reasoning}: ${item.text}`;
|
|
384
|
+
case "tool-call":
|
|
385
|
+
return `${labels.tool} ${item.name}, ${nativeTimelineStatusLabel(item.status, labels)}`;
|
|
386
|
+
case "worker":
|
|
387
|
+
return `${labels.worker}, ${nativeTimelineStatusLabel(item.status, labels)}${item.prompt ? `: ${item.prompt}` : ""}`;
|
|
388
|
+
case "sandbox":
|
|
389
|
+
return `${labels.sandbox} ${item.name}, ${nativeTimelineStatusLabel(item.status, labels)}`;
|
|
390
|
+
case "startup-phase":
|
|
391
|
+
return `${labels.activity}, ${nativeTimelineStatusLabel(item.status, labels)}`;
|
|
392
|
+
case "session-status":
|
|
393
|
+
return nativeSessionStatusLabel(item.status, labels);
|
|
394
|
+
case "goal":
|
|
395
|
+
return `${nativeGoalActionLabel(item.action, labels)}${item.text ? `: ${item.text}` : ""}`;
|
|
396
|
+
case "notice":
|
|
397
|
+
return item.text;
|
|
398
|
+
case "context-compaction":
|
|
399
|
+
return nativeContextCompactionPhaseLabel(item.phase, labels);
|
|
400
|
+
case "machine-input-batch":
|
|
401
|
+
return formatLabel(labels.machineUpdates, { value: item.members.length });
|
|
402
|
+
case "auth-needed":
|
|
403
|
+
return formatLabel(labels.connectionRequired, { provider: item.providerDomain });
|
|
404
|
+
case "knowledge":
|
|
405
|
+
return `${nativeKnowledgeOutcomeLabel(item, labels)}${item.filename ? `: ${item.filename}` : ""}`;
|
|
406
|
+
case "memory":
|
|
407
|
+
return `${nativeMemoryActionLabel(item, labels)}: ${item.replacementPreview ?? item.preview}`;
|
|
408
|
+
case "fleet-decision":
|
|
409
|
+
return `${labels.fleetDecision}: ${nativeFleetDecisionSummary(item, labels)}`;
|
|
410
|
+
case "turn-end":
|
|
411
|
+
return `${labels.turn}, ${nativeTimelineStatusLabel(item.outcome, labels)}`;
|
|
412
|
+
case "worker-completion":
|
|
413
|
+
return item.text;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function nativeSessionStatusLabel(
|
|
418
|
+
status: SessionStatus,
|
|
419
|
+
labels: OpenGeniNativeLabels,
|
|
420
|
+
): string {
|
|
421
|
+
switch (status) {
|
|
422
|
+
case "queued":
|
|
423
|
+
return labels.statusQueued;
|
|
424
|
+
case "running":
|
|
425
|
+
return labels.statusRunning;
|
|
426
|
+
case "recovering":
|
|
427
|
+
return labels.statusRecovering;
|
|
428
|
+
case "waiting_capacity":
|
|
429
|
+
return labels.statusWaitingCapacity;
|
|
430
|
+
case "idle":
|
|
431
|
+
return labels.statusIdle;
|
|
432
|
+
case "requires_action":
|
|
433
|
+
return labels.statusRequiresAction;
|
|
434
|
+
case "failed":
|
|
435
|
+
return labels.statusFailed;
|
|
436
|
+
case "cancelled":
|
|
437
|
+
return labels.statusCancelled;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export function validateHumanInputAnswers(
|
|
442
|
+
questions: readonly HumanInputQuestion[],
|
|
443
|
+
drafts: Readonly<Record<string, NativeHumanInputDraft>>,
|
|
444
|
+
): { answers: HumanInputAnswer[]; valid: boolean } {
|
|
445
|
+
const answers: HumanInputAnswer[] = [];
|
|
446
|
+
let valid = true;
|
|
447
|
+
|
|
448
|
+
for (const question of questions) {
|
|
449
|
+
const draft = drafts[question.id] ?? emptyHumanInputDraft();
|
|
450
|
+
const values =
|
|
451
|
+
question.kind === "text"
|
|
452
|
+
? draft.values.filter((value) => value.trim().length > 0)
|
|
453
|
+
: draft.values;
|
|
454
|
+
const other = draft.otherSelected ? draft.other.trim() : "";
|
|
455
|
+
const supplied = values.length + (other.length > 0 ? 1 : 0);
|
|
456
|
+
|
|
457
|
+
if (question.kind !== "text" && draft.otherSelected && other.length === 0) valid = false;
|
|
458
|
+
if (question.required && supplied === 0) valid = false;
|
|
459
|
+
if (question.kind !== "text") {
|
|
460
|
+
const minimum = question.validation?.minSelections;
|
|
461
|
+
const maximum = question.kind === "single_select" ? 1 : question.validation?.maxSelections;
|
|
462
|
+
if (minimum != null && supplied < minimum) valid = false;
|
|
463
|
+
if (maximum != null && supplied > maximum) valid = false;
|
|
464
|
+
}
|
|
465
|
+
if (supplied > 0) {
|
|
466
|
+
answers.push({
|
|
467
|
+
questionId: question.id,
|
|
468
|
+
values,
|
|
469
|
+
...(other ? { other } : {}),
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return { answers, valid };
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export interface NativeHumanInputDraft {
|
|
478
|
+
values: string[];
|
|
479
|
+
other: string;
|
|
480
|
+
otherSelected: boolean;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export function emptyHumanInputDraft(): NativeHumanInputDraft {
|
|
484
|
+
return { values: [], other: "", otherSelected: false };
|
|
485
|
+
}
|