@opengeni/react 0.36.0 → 0.37.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/README.md +4 -0
- package/dist/{chunk-J2RVJ6JX.js → chunk-4IJCL7YO.js} +13 -2
- package/dist/chunk-4IJCL7YO.js.map +1 -0
- package/dist/{chunk-OKKMZDQF.js → chunk-FSPDND3P.js} +2 -2
- package/dist/{chunk-FT2TXNGZ.js → chunk-HJ4OQVGW.js} +174 -14
- package/dist/chunk-HJ4OQVGW.js.map +1 -0
- package/dist/{chunk-PVW56EVR.js → chunk-IP22SLO6.js} +447 -13
- package/dist/chunk-IP22SLO6.js.map +1 -0
- package/dist/{chunk-U255M5EZ.js → chunk-SJKT4TKW.js} +39 -6
- package/dist/chunk-SJKT4TKW.js.map +1 -0
- package/dist/{chunk-XT7JF2EH.js → chunk-UCZPNXV3.js} +96 -17
- package/dist/chunk-UCZPNXV3.js.map +1 -0
- package/dist/components/chat-composer.d.ts +3 -1
- package/dist/components/model-policy-picker.d.ts +78 -0
- package/dist/components/session-chrome.d.ts +1 -1
- package/dist/composer.d.ts +2 -0
- package/dist/composer.js +17 -3
- package/dist/hooks/use-composer.d.ts +9 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +30 -9
- package/dist/index.js.map +1 -1
- package/dist/model-policy.d.ts +12 -4
- package/dist/model-policy.js +5 -1
- package/dist/session-ui.js +2 -2
- package/dist/session.js +3 -3
- package/dist/timeline/types.d.ts +5 -0
- package/package.json +2 -2
- package/src/components/chat-composer.tsx +8 -3
- package/src/components/composer.tsx +17 -1
- package/src/components/copy-button.tsx +13 -6
- package/src/components/model-picker.tsx +2 -2
- package/src/components/model-policy-picker.tsx +582 -0
- package/src/components/session-chrome.tsx +138 -14
- package/src/composer.ts +13 -0
- package/src/hooks/use-composer.ts +213 -16
- package/src/index.ts +15 -0
- package/src/model-policy.ts +69 -14
- package/src/timeline/projection.ts +21 -1
- package/src/timeline/types.ts +5 -0
- package/dist/chunk-FT2TXNGZ.js.map +0 -1
- package/dist/chunk-J2RVJ6JX.js.map +0 -1
- package/dist/chunk-PVW56EVR.js.map +0 -1
- package/dist/chunk-U255M5EZ.js.map +0 -1
- package/dist/chunk-XT7JF2EH.js.map +0 -1
- /package/dist/{chunk-OKKMZDQF.js.map → chunk-FSPDND3P.js.map} +0 -0
|
@@ -7,7 +7,7 @@ var BILLING_CLASS_ORDER = [
|
|
|
7
7
|
var BILLING_CLASS_LABELS = {
|
|
8
8
|
opengeni_credits: "OpenGeni",
|
|
9
9
|
codex_subscription: "Codex",
|
|
10
|
-
byok: "
|
|
10
|
+
byok: "Your Gateway"
|
|
11
11
|
};
|
|
12
12
|
var AVAILABILITY_REASON_LABELS = {
|
|
13
13
|
missing_credential: "Credentials required",
|
|
@@ -19,6 +19,12 @@ var AVAILABILITY_REASON_LABELS = {
|
|
|
19
19
|
unsupported: "Unsupported"
|
|
20
20
|
};
|
|
21
21
|
function billingClassForModel(model) {
|
|
22
|
+
if (model.source === "codex") {
|
|
23
|
+
return "codex_subscription";
|
|
24
|
+
}
|
|
25
|
+
if (model.source === "workspace_gateway") {
|
|
26
|
+
return "byok";
|
|
27
|
+
}
|
|
22
28
|
if (model.credentialSource?.kind === "connected_subscription") {
|
|
23
29
|
return "codex_subscription";
|
|
24
30
|
}
|
|
@@ -47,7 +53,7 @@ function effortOptionsForModel(model) {
|
|
|
47
53
|
if (!efforts || efforts.length === 0) {
|
|
48
54
|
return ["low"];
|
|
49
55
|
}
|
|
50
|
-
const order = ["none", "minimal", "low", "medium", "high", "xhigh"];
|
|
56
|
+
const order = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
51
57
|
return order.filter((effort) => efforts.includes(effort));
|
|
52
58
|
}
|
|
53
59
|
function defaultEffortForModel(model) {
|
|
@@ -78,6 +84,12 @@ function labelLatencyMode(mode) {
|
|
|
78
84
|
}
|
|
79
85
|
return "Standard";
|
|
80
86
|
}
|
|
87
|
+
function labelReasoningEffort(effort) {
|
|
88
|
+
if (effort === "xhigh") {
|
|
89
|
+
return "Extra high";
|
|
90
|
+
}
|
|
91
|
+
return effort.slice(0, 1).toUpperCase() + effort.slice(1);
|
|
92
|
+
}
|
|
81
93
|
function payerSummaryForModel(model) {
|
|
82
94
|
const billing = model.billing;
|
|
83
95
|
if (!billing) {
|
|
@@ -90,7 +102,7 @@ function payerSummaryForModel(model) {
|
|
|
90
102
|
return "Codex subscription \xB7 external billing";
|
|
91
103
|
}
|
|
92
104
|
if (billing.upstreamPayer === "workspace") {
|
|
93
|
-
return "
|
|
105
|
+
return "Billed to your AI Gateway";
|
|
94
106
|
}
|
|
95
107
|
return "Deployment route \xB7 external billing";
|
|
96
108
|
}
|
|
@@ -103,7 +115,7 @@ function advancedSourceSummary(model) {
|
|
|
103
115
|
return "Connected Codex subscription";
|
|
104
116
|
}
|
|
105
117
|
if (source.kind === "workspace_connection") {
|
|
106
|
-
return "Workspace
|
|
118
|
+
return "Workspace AI Gateway";
|
|
107
119
|
}
|
|
108
120
|
if (source.kind === "deployment") {
|
|
109
121
|
return source.mechanism === "azure_ad_bearer" ? "Deployment Azure identity" : "Deployment API key";
|
|
@@ -111,7 +123,10 @@ function advancedSourceSummary(model) {
|
|
|
111
123
|
return null;
|
|
112
124
|
}
|
|
113
125
|
function projectPickerRows(models) {
|
|
114
|
-
return models.
|
|
126
|
+
return models.filter((catalog) => {
|
|
127
|
+
const billingClass = billingClassForModel(catalog);
|
|
128
|
+
return billingClass === "opengeni_credits" || catalog.credentialReadiness.status === "ready";
|
|
129
|
+
}).map((catalog) => {
|
|
115
130
|
const billingClass = billingClassForModel(catalog);
|
|
116
131
|
return {
|
|
117
132
|
id: catalog.id,
|
|
@@ -126,6 +141,22 @@ function projectPickerRows(models) {
|
|
|
126
141
|
};
|
|
127
142
|
});
|
|
128
143
|
}
|
|
144
|
+
function projectClientModelRows(models) {
|
|
145
|
+
return models.map((catalog) => {
|
|
146
|
+
const billingClass = billingClassForModel(catalog);
|
|
147
|
+
return {
|
|
148
|
+
id: catalog.id,
|
|
149
|
+
label: catalog.label,
|
|
150
|
+
billingClass,
|
|
151
|
+
billingClassLabel: billingClassLabel(billingClass),
|
|
152
|
+
selectable: true,
|
|
153
|
+
unavailableReason: null,
|
|
154
|
+
provider: catalog.provider,
|
|
155
|
+
providerLabel: catalog.providerLabel,
|
|
156
|
+
catalog
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
}
|
|
129
160
|
function sortPickerRows(rows) {
|
|
130
161
|
return [...rows].sort((left, right) => {
|
|
131
162
|
const classDelta = BILLING_CLASS_ORDER.indexOf(left.billingClass) - BILLING_CLASS_ORDER.indexOf(right.billingClass);
|
|
@@ -168,11 +199,13 @@ export {
|
|
|
168
199
|
coerceReasoningEffortForModel,
|
|
169
200
|
runnableLatencyModesForModel,
|
|
170
201
|
labelLatencyMode,
|
|
202
|
+
labelReasoningEffort,
|
|
171
203
|
payerSummaryForModel,
|
|
172
204
|
advancedSourceSummary,
|
|
173
205
|
projectPickerRows,
|
|
206
|
+
projectClientModelRows,
|
|
174
207
|
sortPickerRows,
|
|
175
208
|
findPickerRow,
|
|
176
209
|
groupPickerRowsByBillingClass
|
|
177
210
|
};
|
|
178
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-SJKT4TKW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/model-policy.ts"],"sourcesContent":["import type { ClientModel, ReasoningEffort, WorkspaceModelCatalogModel } from \"@opengeni/sdk\";\n\nexport type PickerBillingClass = \"opengeni_credits\" | \"codex_subscription\" | \"byok\";\n\nexport type PickerModelRow<TCatalog extends ClientModel = WorkspaceModelCatalogModel> = {\n id: string;\n label: string;\n billingClass: PickerBillingClass;\n billingClassLabel: string;\n selectable: boolean;\n unavailableReason: string | null;\n provider: string;\n providerLabel: string;\n catalog: TCatalog;\n};\n\nexport type LatencyModeId = \"standard\" | \"priority\" | \"fast\";\n\nconst BILLING_CLASS_ORDER: PickerBillingClass[] = [\n \"opengeni_credits\",\n \"codex_subscription\",\n \"byok\",\n];\n\nconst BILLING_CLASS_LABELS: Record<PickerBillingClass, string> = {\n opengeni_credits: \"OpenGeni\",\n codex_subscription: \"Codex\",\n byok: \"Your Gateway\",\n};\n\nconst AVAILABILITY_REASON_LABELS: Record<string, string> = {\n missing_credential: \"Credentials required\",\n needs_reauth: \"Reconnect required\",\n credential_not_ready: \"Credential not ready\",\n not_entitled: \"Not entitled\",\n provider_unhealthy: \"Provider unavailable\",\n policy_blocked: \"Blocked by workspace policy\",\n unsupported: \"Unsupported\",\n};\n\nexport function billingClassForModel(model: ClientModel): PickerBillingClass {\n if (model.source === \"codex\") {\n return \"codex_subscription\";\n }\n if (model.source === \"workspace_gateway\") {\n return \"byok\";\n }\n if (model.credentialSource?.kind === \"connected_subscription\") {\n return \"codex_subscription\";\n }\n if (model.credentialSource?.kind === \"workspace_connection\") {\n return \"byok\";\n }\n if (model.billing?.upstreamPayer === \"connected_subscription\") {\n return \"codex_subscription\";\n }\n if (model.billing?.upstreamPayer === \"workspace\") {\n return \"byok\";\n }\n return \"opengeni_credits\";\n}\n\nexport function billingClassLabel(billingClass: PickerBillingClass): string {\n return BILLING_CLASS_LABELS[billingClass];\n}\n\nexport function availabilityReasonLabel(\n reason: WorkspaceModelCatalogModel[\"availability\"][\"reason\"],\n): string | null {\n if (!reason) {\n return null;\n }\n return AVAILABILITY_REASON_LABELS[reason] ?? \"Unavailable\";\n}\n\nexport function effortOptionsForModel(model: ClientModel): ReasoningEffort[] {\n const efforts = model.capabilities?.reasoning.efforts;\n if (!efforts || efforts.length === 0) {\n return [\"low\"];\n }\n const order: ReasoningEffort[] = [\"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n return order.filter((effort) => efforts.includes(effort));\n}\n\nexport function defaultEffortForModel(model: ClientModel): ReasoningEffort {\n const options = effortOptionsForModel(model);\n const configured = model.capabilities?.reasoning.defaultEffort;\n if (configured && options.includes(configured)) {\n return configured;\n }\n return options[0] ?? \"low\";\n}\n\nexport function coerceReasoningEffortForModel(\n model: ClientModel,\n effort: ReasoningEffort,\n): ReasoningEffort {\n const options = effortOptionsForModel(model);\n if (options.includes(effort)) {\n return effort;\n }\n return defaultEffortForModel(model);\n}\n\nexport function runnableLatencyModesForModel(model: ClientModel): LatencyModeId[] {\n const modes = model.capabilities?.latencyModes ?? [];\n return modes.filter((mode) => mode.runnable).map((mode) => mode.id);\n}\n\nexport function labelLatencyMode(mode: LatencyModeId): string {\n if (mode === \"fast\") {\n return \"Fast\";\n }\n if (mode === \"priority\") {\n return \"Priority\";\n }\n return \"Standard\";\n}\n\nexport function labelReasoningEffort(effort: ReasoningEffort): string {\n if (effort === \"xhigh\") {\n return \"Extra high\";\n }\n return effort.slice(0, 1).toUpperCase() + effort.slice(1);\n}\n\nexport function payerSummaryForModel(model: ClientModel): string {\n const billing = model.billing;\n if (!billing) {\n return \"Route unknown\";\n }\n if (billing.metering === \"opengeni_credits\") {\n return \"OpenGeni credits · automatic managed route\";\n }\n if (billing.upstreamPayer === \"connected_subscription\") {\n return \"Codex subscription · external billing\";\n }\n if (billing.upstreamPayer === \"workspace\") {\n return \"Billed to your AI Gateway\";\n }\n return \"Deployment route · external billing\";\n}\n\nexport function advancedSourceSummary(model: ClientModel): string | null {\n const source = model.credentialSource;\n if (!source) {\n return null;\n }\n if (source.kind === \"connected_subscription\") {\n return \"Connected Codex subscription\";\n }\n if (source.kind === \"workspace_connection\") {\n return \"Workspace AI Gateway\";\n }\n if (source.kind === \"deployment\") {\n return source.mechanism === \"azure_ad_bearer\"\n ? \"Deployment Azure identity\"\n : \"Deployment API key\";\n }\n return null;\n}\n\nexport function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerModelRow[] {\n return models\n .filter((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return billingClass === \"opengeni_credits\" || catalog.credentialReadiness.status === \"ready\";\n })\n .map((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return {\n id: catalog.id,\n label: catalog.label,\n billingClass,\n billingClassLabel: billingClassLabel(billingClass),\n selectable: catalog.availability.selectable,\n unavailableReason: catalog.availability.selectable\n ? null\n : availabilityReasonLabel(catalog.availability.reason),\n provider: catalog.provider,\n providerLabel: catalog.providerLabel,\n catalog,\n };\n });\n}\n\n/** Project the lightweight client-config model list into the same picker contract. */\nexport function projectClientModelRows(models: ClientModel[]): PickerModelRow<ClientModel>[] {\n return models.map((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return {\n id: catalog.id,\n label: catalog.label,\n billingClass,\n billingClassLabel: billingClassLabel(billingClass),\n selectable: true,\n unavailableReason: null,\n provider: catalog.provider,\n providerLabel: catalog.providerLabel,\n catalog,\n };\n });\n}\n\nexport function sortPickerRows<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): PickerModelRow<TCatalog>[] {\n return [...rows].sort((left, right) => {\n const classDelta =\n BILLING_CLASS_ORDER.indexOf(left.billingClass) -\n BILLING_CLASS_ORDER.indexOf(right.billingClass);\n if (classDelta !== 0) {\n return classDelta;\n }\n if (left.selectable !== right.selectable) {\n return left.selectable ? -1 : 1;\n }\n return left.label.localeCompare(right.label);\n });\n}\n\nexport function findPickerRow<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n modelId: string,\n): PickerModelRow<TCatalog> | null {\n return rows.find((row) => row.id === modelId) ?? null;\n}\n\nexport function groupPickerRowsByBillingClass(\n rows: PickerModelRow[],\n): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}> {\n const sorted = sortPickerRows(rows);\n const groups: Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n }> = [];\n for (const row of sorted) {\n const existing = groups.find((group) => group.billingClass === row.billingClass);\n if (existing) {\n existing.rows.push(row);\n continue;\n }\n groups.push({\n billingClass: row.billingClass,\n label: row.billingClassLabel,\n rows: [row],\n });\n }\n return groups;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
groupTimeline,
|
|
4
4
|
mcpToolLeaf,
|
|
5
5
|
toolDisplayName
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4IJCL7YO.js";
|
|
7
7
|
import {
|
|
8
8
|
Tooltip,
|
|
9
9
|
TooltipContent,
|
|
@@ -68,6 +68,7 @@ function QueueSurfaceFallback() {
|
|
|
68
68
|
|
|
69
69
|
// src/components/session-chrome.tsx
|
|
70
70
|
import {
|
|
71
|
+
AudioLinesIcon,
|
|
71
72
|
ArrowDownIcon,
|
|
72
73
|
ArrowUpIcon,
|
|
73
74
|
BotIcon,
|
|
@@ -101,6 +102,23 @@ var GOAL_LABEL = {
|
|
|
101
102
|
invariant_broken: "Needs attention",
|
|
102
103
|
completed: "Done"
|
|
103
104
|
};
|
|
105
|
+
function queuedTurnPresentation(turn) {
|
|
106
|
+
const realtimeDelegation = objectValue(turn.metadata.realtimeDelegation);
|
|
107
|
+
const inputTranscript = realtimeDelegation?.inputTranscript;
|
|
108
|
+
if (typeof inputTranscript === "string" && inputTranscript.trim()) {
|
|
109
|
+
return { kind: "realtime_voice", text: inputTranscript.trim() };
|
|
110
|
+
}
|
|
111
|
+
if (objectValue(turn.metadata.realtimeTailFlush)) {
|
|
112
|
+
return { kind: "realtime_voice_handoff", text: "Remaining voice context" };
|
|
113
|
+
}
|
|
114
|
+
return { kind: "prompt", text: turn.prompt };
|
|
115
|
+
}
|
|
116
|
+
function isSteeringTurn(turn) {
|
|
117
|
+
return turn.metadata.delivery === "steer";
|
|
118
|
+
}
|
|
119
|
+
function objectValue(value) {
|
|
120
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
121
|
+
}
|
|
104
122
|
function sessionChromeGoalPillState(goalStatus, continuation) {
|
|
105
123
|
if (goalStatus === "completed") return "completed";
|
|
106
124
|
if (goalStatus === "paused") return "paused";
|
|
@@ -184,6 +202,25 @@ function SessionChrome({
|
|
|
184
202
|
const record = goal?.goal ?? null;
|
|
185
203
|
const incoming = queue.pendingInputs;
|
|
186
204
|
const turns = queue.queue;
|
|
205
|
+
const composerSteering = composer?.steering ?? null;
|
|
206
|
+
const { steering, queuedTurns } = useMemo(() => {
|
|
207
|
+
const pendingQueueSteer = turns.find((turn) => queue.pendingByTurn[turn.id] === "steer") ?? null;
|
|
208
|
+
const durableQueueSteer = !pendingQueueSteer && turns[0] && isSteeringTurn(turns[0]) ? turns[0] : null;
|
|
209
|
+
const currentSteering = composerSteering?.phase === "submitting" ? composerSteering : pendingQueueSteer ? {
|
|
210
|
+
phase: "submitting",
|
|
211
|
+
text: queuedTurnPresentation(pendingQueueSteer).text,
|
|
212
|
+
turnId: pendingQueueSteer.id
|
|
213
|
+
} : durableQueueSteer ? {
|
|
214
|
+
phase: "accepted",
|
|
215
|
+
text: queuedTurnPresentation(durableQueueSteer).text,
|
|
216
|
+
turnId: durableQueueSteer.id
|
|
217
|
+
} : composerSteering;
|
|
218
|
+
const currentTurnId = currentSteering?.turnId ?? null;
|
|
219
|
+
return {
|
|
220
|
+
steering: currentSteering,
|
|
221
|
+
queuedTurns: currentTurnId ? turns.filter((turn) => turn.id !== currentTurnId) : turns
|
|
222
|
+
};
|
|
223
|
+
}, [composerSteering, queue.pendingByTurn, turns]);
|
|
187
224
|
const canMutateQueue = !readOnly && composer !== void 0;
|
|
188
225
|
const liveGoal = record?.status === "active" && record.continuation?.state === "running" && record.continuation.reason === "goal_turn_running";
|
|
189
226
|
const elapsed = useLiveElapsed(
|
|
@@ -206,14 +243,28 @@ function SessionChrome({
|
|
|
206
243
|
icon: /* @__PURE__ */ jsx2(InboxIcon, { className: "size-3" })
|
|
207
244
|
});
|
|
208
245
|
}
|
|
209
|
-
if (
|
|
210
|
-
|
|
246
|
+
if (steering) {
|
|
247
|
+
rows.push({
|
|
248
|
+
id: "steering",
|
|
249
|
+
label: "Changing direction\u2026",
|
|
250
|
+
detail: steering.text,
|
|
251
|
+
tone: "accent",
|
|
252
|
+
icon: steering.phase === "submitting" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3" })
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (queuedTurns.length > 0) {
|
|
256
|
+
const presentations = queuedTurns.map(queuedTurnPresentation);
|
|
257
|
+
const first = presentations[0];
|
|
258
|
+
const allVoiceRequests = presentations.every(({ kind }) => kind === "realtime_voice");
|
|
259
|
+
const onlyVoiceHandoff = presentations.length === 1 && first?.kind === "realtime_voice_handoff";
|
|
260
|
+
const voiceOnly = allVoiceRequests || onlyVoiceHandoff;
|
|
261
|
+
const detail = first?.text;
|
|
211
262
|
rows.push({
|
|
212
263
|
id: "queue",
|
|
213
|
-
label: `${
|
|
264
|
+
label: allVoiceRequests ? queuedTurns.length === 1 ? "Voice request queued" : `${queuedTurns.length} voice requests queued` : onlyVoiceHandoff ? "Voice handoff queued" : `${queuedTurns.length} queued prompt${queuedTurns.length === 1 ? "" : "s"}`,
|
|
214
265
|
...detail ? { detail } : {},
|
|
215
266
|
tone: "neutral",
|
|
216
|
-
icon: /* @__PURE__ */ jsx2(ListOrderedIcon, { className: "size-3" })
|
|
267
|
+
icon: voiceOnly ? /* @__PURE__ */ jsx2(AudioLinesIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(ListOrderedIcon, { className: "size-3" })
|
|
217
268
|
});
|
|
218
269
|
}
|
|
219
270
|
if (record && goalState) {
|
|
@@ -237,7 +288,7 @@ function SessionChrome({
|
|
|
237
288
|
});
|
|
238
289
|
}
|
|
239
290
|
return rows;
|
|
240
|
-
}, [agentsSignal, elapsed, goalState, incoming, record,
|
|
291
|
+
}, [agentsSignal, elapsed, goalState, incoming, queuedTurns, record, steering]);
|
|
241
292
|
const [activeUncontrolled, setActiveUncontrolled] = useState(
|
|
242
293
|
defaultActive
|
|
243
294
|
);
|
|
@@ -261,10 +312,10 @@ function SessionChrome({
|
|
|
261
312
|
}, [active, activeControlled, onActiveChange, signalIds]);
|
|
262
313
|
useEffect(() => {
|
|
263
314
|
if (active !== "queue" || !replaceDraftFor) return;
|
|
264
|
-
if (!
|
|
315
|
+
if (!queuedTurns.some((turn) => turn.id === replaceDraftFor)) {
|
|
265
316
|
setReplaceDraftFor(null);
|
|
266
317
|
}
|
|
267
|
-
}, [active,
|
|
318
|
+
}, [active, queuedTurns, replaceDraftFor]);
|
|
268
319
|
useEffect(() => {
|
|
269
320
|
const rail = railRef.current;
|
|
270
321
|
const measure = () => {
|
|
@@ -301,7 +352,7 @@ function SessionChrome({
|
|
|
301
352
|
const node = panelBodyRef.current;
|
|
302
353
|
if (!node) return;
|
|
303
354
|
setPanelHeight(node.offsetHeight);
|
|
304
|
-
}, [open, active, incoming,
|
|
355
|
+
}, [open, active, incoming, queuedTurns, record, goalState, agentsPanel, agentsSignal, steering]);
|
|
305
356
|
useEffect(() => {
|
|
306
357
|
if (!open) return;
|
|
307
358
|
const node = panelBodyRef.current;
|
|
@@ -316,10 +367,10 @@ function SessionChrome({
|
|
|
316
367
|
const shellDuration = reduceMotion ? 0 : 0.22;
|
|
317
368
|
const crossfadeDuration = reduceMotion ? 0 : 0.18;
|
|
318
369
|
const ease = [0.22, 1, 0.36, 1];
|
|
319
|
-
const panelBody = active === "incoming" ? /* @__PURE__ */ jsx2(IncomingPanel, { inputs: incoming, onDismiss: onDismissIncoming }) : active === "queue" ? /* @__PURE__ */ jsx2(
|
|
370
|
+
const panelBody = active === "incoming" ? /* @__PURE__ */ jsx2(IncomingPanel, { inputs: incoming, onDismiss: onDismissIncoming }) : active === "steering" && steering ? /* @__PURE__ */ jsx2(SteeringPanel, { phase: steering.phase, text: steering.text }) : active === "queue" ? /* @__PURE__ */ jsx2(
|
|
320
371
|
QueuePanel,
|
|
321
372
|
{
|
|
322
|
-
turns,
|
|
373
|
+
turns: queuedTurns,
|
|
323
374
|
readOnly: !canMutateQueue,
|
|
324
375
|
mutationFor: queue.mutationFor,
|
|
325
376
|
replaceDraftFor,
|
|
@@ -553,6 +604,24 @@ function IncomingPanel({
|
|
|
553
604
|
}
|
|
554
605
|
);
|
|
555
606
|
}
|
|
607
|
+
function SteeringPanel({ phase, text }) {
|
|
608
|
+
return /* @__PURE__ */ jsxs2(
|
|
609
|
+
"div",
|
|
610
|
+
{
|
|
611
|
+
className: "flex items-start gap-2 rounded-og-sm px-1.5 py-1",
|
|
612
|
+
role: "status",
|
|
613
|
+
"aria-live": "polite",
|
|
614
|
+
"data-og-session-chrome-panel": "steering",
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ jsx2("span", { className: "mt-0.5 inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-og-accent-soft text-og-accent", children: phase === "submitting" ? /* @__PURE__ */ jsx2(Loader2Icon2, { className: "size-3 animate-og-spin", "aria-hidden": "true" }) : /* @__PURE__ */ jsx2(ZapIcon, { className: "size-3", "aria-hidden": "true" }) }),
|
|
617
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
618
|
+
/* @__PURE__ */ jsx2("p", { className: "truncate text-og-xs font-medium leading-4 text-og-fg", children: text }),
|
|
619
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-[10px] leading-4 text-og-fg-muted", children: phase === "submitting" ? "Sending your latest direction\u2026" : "Direction accepted. The agent will continue from it." })
|
|
620
|
+
] })
|
|
621
|
+
]
|
|
622
|
+
}
|
|
623
|
+
);
|
|
624
|
+
}
|
|
556
625
|
function QueuePanel({
|
|
557
626
|
turns,
|
|
558
627
|
readOnly,
|
|
@@ -572,6 +641,8 @@ function QueuePanel({
|
|
|
572
641
|
"aria-label": "Queued prompts",
|
|
573
642
|
"data-og-session-chrome-panel": "queue",
|
|
574
643
|
children: turns.map((turn, index) => {
|
|
644
|
+
const presentation = queuedTurnPresentation(turn);
|
|
645
|
+
const voice = presentation.kind !== "prompt";
|
|
575
646
|
const pending = mutationFor(turn.id);
|
|
576
647
|
const beforeUp = index > 0 ? turns[index - 1]?.id ?? null : null;
|
|
577
648
|
const beforeDown = index < turns.length - 1 ? turns[index + 2]?.id ?? null : null;
|
|
@@ -584,8 +655,14 @@ function QueuePanel({
|
|
|
584
655
|
className: "group flex flex-col gap-1 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--og-session-chrome-row-hover)]",
|
|
585
656
|
children: [
|
|
586
657
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-1.5", children: [
|
|
587
|
-
/* @__PURE__ */ jsx2(
|
|
588
|
-
|
|
658
|
+
voice ? /* @__PURE__ */ jsx2(
|
|
659
|
+
AudioLinesIcon,
|
|
660
|
+
{
|
|
661
|
+
"aria-hidden": "true",
|
|
662
|
+
className: "mt-0.5 size-3 shrink-0 text-og-accent"
|
|
663
|
+
}
|
|
664
|
+
) : /* @__PURE__ */ jsx2("span", { className: "mt-px shrink-0 font-og-mono text-[10px] leading-4 text-og-fg-subtle", children: index + 1 }),
|
|
665
|
+
/* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 truncate text-og-xs leading-4 text-og-fg", children: presentation.text }),
|
|
589
666
|
showActions ? /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 max-sm:opacity-100", children: [
|
|
590
667
|
onMove && turns.length > 1 ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
591
668
|
/* @__PURE__ */ jsx2(
|
|
@@ -3183,6 +3260,8 @@ function CopyButton({
|
|
|
3183
3260
|
const onClick = async (event) => {
|
|
3184
3261
|
event.preventDefault();
|
|
3185
3262
|
event.stopPropagation();
|
|
3263
|
+
const button = event.currentTarget;
|
|
3264
|
+
const pointerActivated = event.detail > 0;
|
|
3186
3265
|
const value = typeof text === "function" ? text() : text;
|
|
3187
3266
|
const ok = await copyTextToClipboard(value);
|
|
3188
3267
|
if (!ok) {
|
|
@@ -3190,9 +3269,6 @@ function CopyButton({
|
|
|
3190
3269
|
}
|
|
3191
3270
|
setCopied(true);
|
|
3192
3271
|
setTipOpen(true);
|
|
3193
|
-
if (event.detail > 0) {
|
|
3194
|
-
event.currentTarget.blur();
|
|
3195
|
-
}
|
|
3196
3272
|
if (timerRef.current !== null) {
|
|
3197
3273
|
clearTimeout(timerRef.current);
|
|
3198
3274
|
}
|
|
@@ -3201,6 +3277,9 @@ function CopyButton({
|
|
|
3201
3277
|
setCopied(false);
|
|
3202
3278
|
setTipOpen(false);
|
|
3203
3279
|
}, COPIED_MS);
|
|
3280
|
+
if (pointerActivated) {
|
|
3281
|
+
button.blur();
|
|
3282
|
+
}
|
|
3204
3283
|
};
|
|
3205
3284
|
const tip = copied ? "Copied" : label;
|
|
3206
3285
|
return /* @__PURE__ */ jsxs8(
|
|
@@ -6804,4 +6883,4 @@ export {
|
|
|
6804
6883
|
MessageTimeline,
|
|
6805
6884
|
TimelineRow
|
|
6806
6885
|
};
|
|
6807
|
-
//# sourceMappingURL=chunk-
|
|
6886
|
+
//# sourceMappingURL=chunk-UCZPNXV3.js.map
|