@opengeni/react-native 4.5.0 → 4.6.1
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.
|
@@ -25,10 +25,18 @@ export interface SessionRowProps {
|
|
|
25
25
|
onTogglePin?: (() => void) | undefined;
|
|
26
26
|
/** The workspace the chat lives in, when it is not the one on screen (search results). */
|
|
27
27
|
workspaceName?: string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* A word the person must act on (a sub-agent that failed, is stuck, needs
|
|
30
|
+
* them or is paused). It replaces the last-update time and sets the dot's tone.
|
|
31
|
+
*/
|
|
32
|
+
attention?: {
|
|
33
|
+
word: string;
|
|
34
|
+
tone: "failed" | "waiting";
|
|
35
|
+
} | null | undefined;
|
|
28
36
|
now?: Date | undefined;
|
|
29
37
|
}
|
|
30
38
|
/** One recent-session row, as the web home canvas renders it. */
|
|
31
|
-
export declare function SessionRow({ session, models, onPress, onTogglePin, workspaceName, now, }: SessionRowProps): import("react").JSX.Element;
|
|
39
|
+
export declare function SessionRow({ session, models, onPress, onTogglePin, workspaceName, attention, now, }: SessionRowProps): import("react").JSX.Element;
|
|
32
40
|
/** A small-caps section label (web: text-2xs semibold uppercase tracking-wider). */
|
|
33
41
|
export declare function SectionLabel({ children }: {
|
|
34
42
|
children: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/react-native",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.1",
|
|
4
4
|
"description": "React Native and Expo kit for Opengeni agents: the native session timeline, composer adapters, voice dictation, and realtime voice calls (CallKit) on the same SDK controllers as the web.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@opengeni/contracts": "4.
|
|
72
|
-
"@opengeni/react": "4.
|
|
73
|
-
"@opengeni/sdk": "4.
|
|
71
|
+
"@opengeni/contracts": "4.6.1",
|
|
72
|
+
"@opengeni/react": "4.6.1",
|
|
73
|
+
"@opengeni/sdk": "4.6.1",
|
|
74
74
|
"thinking-orbs": "^0.3.1"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
@@ -132,6 +132,11 @@ export interface SessionRowProps {
|
|
|
132
132
|
onTogglePin?: (() => void) | undefined;
|
|
133
133
|
/** The workspace the chat lives in, when it is not the one on screen (search results). */
|
|
134
134
|
workspaceName?: string | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* A word the person must act on (a sub-agent that failed, is stuck, needs
|
|
137
|
+
* them or is paused). It replaces the last-update time and sets the dot's tone.
|
|
138
|
+
*/
|
|
139
|
+
attention?: { word: string; tone: "failed" | "waiting" } | null | undefined;
|
|
135
140
|
now?: Date | undefined;
|
|
136
141
|
}
|
|
137
142
|
|
|
@@ -142,6 +147,7 @@ export function SessionRow({
|
|
|
142
147
|
onPress,
|
|
143
148
|
onTogglePin,
|
|
144
149
|
workspaceName,
|
|
150
|
+
attention,
|
|
145
151
|
now,
|
|
146
152
|
}: SessionRowProps) {
|
|
147
153
|
const theme = useNativeTimelineTheme();
|
|
@@ -150,7 +156,8 @@ export function SessionRow({
|
|
|
150
156
|
const t = useOpenGeniText();
|
|
151
157
|
const rows = useMemo(() => projectClientModelRows(t, [...models]), [t, models]);
|
|
152
158
|
const title = sessionDisplayTitle(session);
|
|
153
|
-
const
|
|
159
|
+
const recent = recentSessionStatus(session);
|
|
160
|
+
const status = attention ? { tone: attention.tone, pulse: false } : recent;
|
|
154
161
|
const model = recentSessionModelPresentation(session.model, rows);
|
|
155
162
|
const repo = sessionRepoLabel(session);
|
|
156
163
|
const meta = [model.label, repo].filter(Boolean).join(" · ");
|
|
@@ -186,6 +193,7 @@ export function SessionRow({
|
|
|
186
193
|
<Pressable
|
|
187
194
|
accessibilityRole="button"
|
|
188
195
|
accessibilityLabel={[title, pinned ? m.pinned : null, workspaceName ?? null]
|
|
196
|
+
.concat(attention ? [attention.word] : [])
|
|
189
197
|
.filter(Boolean)
|
|
190
198
|
.join(", ")}
|
|
191
199
|
accessibilityActions={onTogglePin ? [{ name: "pin", label: pinLabel }] : undefined}
|
|
@@ -241,14 +249,18 @@ export function SessionRow({
|
|
|
241
249
|
{pinned ? <Icon name="pin" size={11} color={c["fg-subtle"]} /> : null}
|
|
242
250
|
<Text
|
|
243
251
|
style={{
|
|
244
|
-
...fontStyle(theme, 400),
|
|
252
|
+
...fontStyle(theme, attention ? 500 : 400),
|
|
245
253
|
fontSize: 11,
|
|
246
254
|
lineHeight: 16,
|
|
247
|
-
color:
|
|
255
|
+
color: attention
|
|
256
|
+
? attention.tone === "failed"
|
|
257
|
+
? c["status-failed"]
|
|
258
|
+
: c["status-waiting"]
|
|
259
|
+
: c["fg-subtle"],
|
|
248
260
|
fontVariant: ["tabular-nums"],
|
|
249
261
|
}}
|
|
250
262
|
>
|
|
251
|
-
{relativeTimeLabel(t, session.updatedAt, now)}
|
|
263
|
+
{attention ? attention.word : relativeTimeLabel(t, session.updatedAt, now)}
|
|
252
264
|
</Text>
|
|
253
265
|
</View>
|
|
254
266
|
</Pressable>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ClientModel, LineageNode, SessionBackgroundCommand } from "@opengeni/sdk";
|
|
2
2
|
import type { UseGoalResult } from "@opengeni/react/session";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
sessionAgentAttention,
|
|
5
|
+
sessionAgentsSignal,
|
|
6
|
+
sessionGoalStateLabel,
|
|
7
|
+
} from "@opengeni/react/session-agents-model";
|
|
4
8
|
import { useOpenGeniText } from "@opengeni/react/messages";
|
|
5
9
|
import { createContext, useContext, useState, type ReactNode } from "react";
|
|
6
10
|
import { ActivityIndicator, Pressable, ScrollView, Text, View, type TextStyle } from "react-native";
|
|
@@ -94,29 +98,17 @@ export function SessionSignals(props: {
|
|
|
94
98
|
<BottomSheet open={open === "agents"} onClose={close} accessibilityLabel={m.agents}>
|
|
95
99
|
<SheetTitle>{m.agents}</SheetTitle>
|
|
96
100
|
<ScrollView style={{ paddingHorizontal: 12 }}>
|
|
101
|
+
{/* Newest first, as the server lists them and the sidebar orders chats. */}
|
|
97
102
|
{props.agents.map((node) => (
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{node.children.map((child) => (
|
|
108
|
-
<View key={child.session.id} style={{ paddingLeft: 18 }}>
|
|
109
|
-
<SessionRow
|
|
110
|
-
session={child.session}
|
|
111
|
-
models={props.models ?? []}
|
|
112
|
-
onPress={() => {
|
|
113
|
-
close();
|
|
114
|
-
props.onOpenSession?.(child.session.id);
|
|
115
|
-
}}
|
|
116
|
-
/>
|
|
117
|
-
</View>
|
|
118
|
-
))}
|
|
119
|
-
</View>
|
|
103
|
+
<AgentNode
|
|
104
|
+
key={node.session.id}
|
|
105
|
+
node={node}
|
|
106
|
+
models={props.models ?? []}
|
|
107
|
+
onOpen={(sessionId) => {
|
|
108
|
+
close();
|
|
109
|
+
props.onOpenSession?.(sessionId);
|
|
110
|
+
}}
|
|
111
|
+
/>
|
|
120
112
|
))}
|
|
121
113
|
</ScrollView>
|
|
122
114
|
</BottomSheet>
|
|
@@ -171,6 +163,80 @@ function Chip(props: {
|
|
|
171
163
|
);
|
|
172
164
|
}
|
|
173
165
|
|
|
166
|
+
/**
|
|
167
|
+
* One sub-agent, as the web agents panel lists it: its status, title, model and
|
|
168
|
+
* last update, or the word to act on (Needs you · 10h, Failed, Stuck, Paused).
|
|
169
|
+
* Its own agents fold under it behind a count, one level deep like the web.
|
|
170
|
+
*/
|
|
171
|
+
function AgentNode(props: {
|
|
172
|
+
node: LineageNode;
|
|
173
|
+
models: readonly ClientModel[];
|
|
174
|
+
onOpen: (sessionId: string) => void;
|
|
175
|
+
nested?: boolean | undefined;
|
|
176
|
+
}) {
|
|
177
|
+
const t = useOpenGeniText();
|
|
178
|
+
const theme = useNativeTimelineTheme();
|
|
179
|
+
const c = theme.colors;
|
|
180
|
+
const [expanded, setExpanded] = useState(false);
|
|
181
|
+
const { session, children } = props.node;
|
|
182
|
+
const paused = session.status !== "cancelled" && session.effectiveControl.state !== "active";
|
|
183
|
+
const attention = sessionAgentAttention(t, session, paused);
|
|
184
|
+
const count = children.length;
|
|
185
|
+
return (
|
|
186
|
+
<View style={props.nested ? { paddingLeft: 18 } : undefined}>
|
|
187
|
+
<SessionRow
|
|
188
|
+
session={session}
|
|
189
|
+
models={props.models}
|
|
190
|
+
attention={attention}
|
|
191
|
+
onPress={() => props.onOpen(session.id)}
|
|
192
|
+
/>
|
|
193
|
+
{count > 0 && !props.nested ? (
|
|
194
|
+
<>
|
|
195
|
+
<Pressable
|
|
196
|
+
accessibilityRole="button"
|
|
197
|
+
accessibilityState={{ expanded }}
|
|
198
|
+
accessibilityLabel={t("counts.agents", { count })}
|
|
199
|
+
onPress={() => setExpanded((value) => !value)}
|
|
200
|
+
hitSlop={{ top: 6, bottom: 6 }}
|
|
201
|
+
style={({ pressed }) => ({
|
|
202
|
+
flexDirection: "row",
|
|
203
|
+
alignItems: "center",
|
|
204
|
+
gap: 4,
|
|
205
|
+
alignSelf: "flex-start",
|
|
206
|
+
marginLeft: 24,
|
|
207
|
+
marginBottom: 6,
|
|
208
|
+
paddingHorizontal: 8,
|
|
209
|
+
paddingVertical: 4,
|
|
210
|
+
borderRadius: theme.radius.md,
|
|
211
|
+
backgroundColor: pressed ? c.hover : "transparent",
|
|
212
|
+
})}
|
|
213
|
+
>
|
|
214
|
+
<Icon
|
|
215
|
+
name={expanded ? "chevron-down" : "chevron-right"}
|
|
216
|
+
size={12}
|
|
217
|
+
color={c["fg-subtle"]}
|
|
218
|
+
/>
|
|
219
|
+
<Text style={{ ...fontStyle(theme, 500), fontSize: 12, color: c["fg-muted"] }}>
|
|
220
|
+
{t("counts.agents", { count })}
|
|
221
|
+
</Text>
|
|
222
|
+
</Pressable>
|
|
223
|
+
{expanded
|
|
224
|
+
? children.map((child) => (
|
|
225
|
+
<AgentNode
|
|
226
|
+
key={child.session.id}
|
|
227
|
+
node={child}
|
|
228
|
+
models={props.models}
|
|
229
|
+
onOpen={props.onOpen}
|
|
230
|
+
nested
|
|
231
|
+
/>
|
|
232
|
+
))
|
|
233
|
+
: null}
|
|
234
|
+
</>
|
|
235
|
+
) : null}
|
|
236
|
+
</View>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
174
240
|
function SheetTitle({ children }: { children: string }) {
|
|
175
241
|
const theme = useNativeTimelineTheme();
|
|
176
242
|
return (
|