daily-focus 2.0.0-dev.15 → 2.0.0-dev.17
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/package.json +2 -2
- package/prompts/morning-brief-personal.md +4 -2
- package/prompts/morning-brief-work.md +4 -2
- package/public/app.js +129 -49
- package/public/style.css +51 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daily-focus",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.17",
|
|
4
4
|
"description": "An interactive dashboard of what you should focus on today at work",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dashboard",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"daily-focus": {
|
|
43
43
|
"appInterface": 1,
|
|
44
|
-
"appSource": "
|
|
44
|
+
"appSource": "b9481d3565f319ac0190aee10fd633c8f06438e0"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"start": "node src/server.ts",
|
|
@@ -340,7 +340,7 @@ Then the general editorial bar:
|
|
|
340
340
|
{
|
|
341
341
|
"version": 1,
|
|
342
342
|
"generatedAt": "<ISO 8601 timestamp, with offset>",
|
|
343
|
-
"generatedBy": "<
|
|
343
|
+
"generatedBy": "<your model or agent id, such as codex, and nothing else>",
|
|
344
344
|
"date": "<today, YYYY-MM-DD>",
|
|
345
345
|
"headline": "<one or two sentences, or omit>",
|
|
346
346
|
"items": [ … ]
|
|
@@ -418,7 +418,9 @@ Check all of these, and fix anything that fails:
|
|
|
418
418
|
6. Every `url` starts with `http://` or `https://`, and came from a tool rather than
|
|
419
419
|
being built by you.
|
|
420
420
|
7. Every `start`/`end` has a timezone offset, unless deliberately all-day.
|
|
421
|
-
8. `generatedAt` is now, and `generatedBy` names whoever ran
|
|
421
|
+
8. `generatedAt` is now, and `generatedBy` names whoever ran — your model or agent
|
|
422
|
+
id and nothing else: not a working directory, a path or an account. The dashboard
|
|
423
|
+
prints it after "updated … by" in its header.
|
|
422
424
|
9. **When `focus.md` sets an objective, at least one item offers a concrete path to
|
|
423
425
|
it** — a real one you found, or the synthesised one. With no objective, no item has
|
|
424
426
|
`advancesObjective`.
|
|
@@ -512,7 +512,7 @@ Then the general editorial bar:
|
|
|
512
512
|
{
|
|
513
513
|
"version": 1,
|
|
514
514
|
"generatedAt": "<ISO 8601 timestamp, with offset>",
|
|
515
|
-
"generatedBy": "<
|
|
515
|
+
"generatedBy": "<your model or agent id, such as codex, and nothing else>",
|
|
516
516
|
"date": "<today, YYYY-MM-DD>",
|
|
517
517
|
"headline": "<one or two sentences, or omit>",
|
|
518
518
|
"dayStart": "09:00",
|
|
@@ -601,7 +601,9 @@ Check all of these, and fix anything that fails:
|
|
|
601
601
|
6. Every `url` starts with `http://` or `https://`.
|
|
602
602
|
7. Every `start`/`end` has a timezone offset, unless deliberately all-day.
|
|
603
603
|
8. `generatedAt` is now, and `generatedBy` names whoever ran — your model or agent
|
|
604
|
-
id
|
|
604
|
+
id and nothing else: not a working directory, a path or an account. The dashboard
|
|
605
|
+
prints it after "updated … by" in its header, so `codex` reads well there and
|
|
606
|
+
`codex (/root)` does not.
|
|
605
607
|
9. **When `focus.md` sets an objective, at least one item offers a concrete path to
|
|
606
608
|
it** — a real one you found, or the synthesised "no path today" item. A brief with
|
|
607
609
|
no route to the objective and no acknowledgement of that fact is a failed run.
|
package/public/app.js
CHANGED
|
@@ -2480,10 +2480,11 @@ function agentRunBanner(run, state2, handlers2) {
|
|
|
2480
2480
|
};
|
|
2481
2481
|
if (run.status === "running") {
|
|
2482
2482
|
const helping = (run.steps ?? []).filter((step) => step.subagent && step.state === "running").length;
|
|
2483
|
+
const doing = briefLanded(run, state2.brief?.generatedAt) ? "The brief is in. The morning agent is checking it and writing its report" : "The morning agent is writing a new brief";
|
|
2483
2484
|
return bannerNode(
|
|
2484
2485
|
"info",
|
|
2485
2486
|
"i",
|
|
2486
|
-
|
|
2487
|
+
`${doing}, started ${relativeTime(run.startedAt, now)}` + (helping ? `, with ${helping} ${helping === 1 ? "subagent" : "subagents"} at work.` : "."),
|
|
2487
2488
|
[el("button", { type: "button", class: "button banner__action", onClick: () => handlers2.stopAgent() }, "Stop")],
|
|
2488
2489
|
strip
|
|
2489
2490
|
);
|
|
@@ -2504,6 +2505,11 @@ function agentRunBanner(run, state2, handlers2) {
|
|
|
2504
2505
|
strip
|
|
2505
2506
|
);
|
|
2506
2507
|
}
|
|
2508
|
+
function briefLanded(run, generatedAt) {
|
|
2509
|
+
const started = parseDate(run.startedAt)?.getTime();
|
|
2510
|
+
const landed = generatedAt ? parseDate(generatedAt)?.getTime() : void 0;
|
|
2511
|
+
return started !== void 0 && landed !== void 0 && landed >= started;
|
|
2512
|
+
}
|
|
2507
2513
|
function isHeldOverDayOff(state2) {
|
|
2508
2514
|
if (state2.brief.generatedAt === null || state2.schedule.runsToday) return false;
|
|
2509
2515
|
const today = dayKey(new Date(state2.now));
|
|
@@ -3731,7 +3737,7 @@ function briefRefresh(state2, handlers2) {
|
|
|
3731
3737
|
const agent = state2.agentRun;
|
|
3732
3738
|
if (!agent?.enabled) return null;
|
|
3733
3739
|
const running = agent.last?.status === "running";
|
|
3734
|
-
const label = running ? `The morning agent is writing a new brief, started ${formatTime(agent.last?.startedAt)}` : `Run the morning agent now, for a fresh brief${nextRunPhraseFor(agent)}`;
|
|
3740
|
+
const label = running ? agent.last && briefLanded(agent.last, state2.brief.generatedAt) ? `The brief is in; the morning agent is checking it and writing its report, started ${formatTime(agent.last.startedAt)}` : `The morning agent is writing a new brief, started ${formatTime(agent.last?.startedAt)}` : `Run the morning agent now, for a fresh brief${nextRunPhraseFor(agent)}`;
|
|
3735
3741
|
return el(
|
|
3736
3742
|
"button",
|
|
3737
3743
|
{
|
|
@@ -3898,8 +3904,8 @@ function RunPanel({ run, state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
3898
3904
|
el(
|
|
3899
3905
|
"div",
|
|
3900
3906
|
{ class: "flyout__body", ref: body, onScroll },
|
|
3901
|
-
runStatus(run, now, handlers2),
|
|
3902
|
-
runReport(run, ui2, handlers2),
|
|
3907
|
+
run.status === "running" ? null : runStatus(run, now, handlers2),
|
|
3908
|
+
runReport(run, { landed: briefLanded(run, state2.brief?.generatedAt), now }, ui2, handlers2),
|
|
3903
3909
|
run.status === "running" ? null : runConversation(run, busy, answering, enabled, ui2, handlers2, askInput),
|
|
3904
3910
|
runList(run, runs, now, agent, handlers2)
|
|
3905
3911
|
)
|
|
@@ -3936,8 +3942,8 @@ function describeWhen(value, now) {
|
|
|
3936
3942
|
const named = day === "today" || day === "tomorrow" || day === "yesterday";
|
|
3937
3943
|
return `${named ? day : date && date.getFullYear() === now.getFullYear() ? formatShortDay(value) : formatDay(value)} at ${formatTime(value)}`;
|
|
3938
3944
|
}
|
|
3939
|
-
function runReport(run, ui2, handlers2) {
|
|
3940
|
-
if (run.steps?.length) return runWork(run, ui2, handlers2);
|
|
3945
|
+
function runReport(run, live, ui2, handlers2) {
|
|
3946
|
+
if (run.steps?.length) return runWork(run, live, ui2, handlers2);
|
|
3941
3947
|
const messages = run.messages ?? (run.report ? [run.report] : []);
|
|
3942
3948
|
const running = run.status === "running";
|
|
3943
3949
|
const earlier = !running && messages.length && messages.at(-1) === run.report ? messages.slice(0, -1) : messages;
|
|
@@ -3976,12 +3982,9 @@ function runReport(run, ui2, handlers2) {
|
|
|
3976
3982
|
})
|
|
3977
3983
|
) : null;
|
|
3978
3984
|
if (running) {
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
el("h3", { class: "flyout__label" }, "What it is doing"),
|
|
3983
|
-
list ?? el("p", { class: "flyout__empty" }, "Nothing yet.")
|
|
3984
|
-
);
|
|
3985
|
+
const latest = earlier.at(-1);
|
|
3986
|
+
const summary = `${latest ? firstLine(latest) : "Starting"} \xB7 ${earlier.length} ${earlier.length === 1 ? "message" : "messages"}`;
|
|
3987
|
+
return liveSection(run, live, summary, [list, el("ol", { class: "assistant__steps agent-run__steps" }, waitingLine(earlier.length > 0))], ui2, handlers2);
|
|
3985
3988
|
}
|
|
3986
3989
|
return el(
|
|
3987
3990
|
"section",
|
|
@@ -3996,16 +3999,9 @@ function runReport(run, ui2, handlers2) {
|
|
|
3996
3999
|
) : null
|
|
3997
4000
|
);
|
|
3998
4001
|
}
|
|
3999
|
-
function runWork(run, ui2, handlers2) {
|
|
4002
|
+
function runWork(run, live, ui2, handlers2) {
|
|
4000
4003
|
const running = run.status === "running";
|
|
4001
|
-
if (running)
|
|
4002
|
-
return el(
|
|
4003
|
-
"section",
|
|
4004
|
-
{ class: "flyout__section" },
|
|
4005
|
-
el("h3", { class: "flyout__label" }, "What it is doing"),
|
|
4006
|
-
runSteps(run, run.steps, null, ui2, handlers2)
|
|
4007
|
-
);
|
|
4008
|
-
}
|
|
4004
|
+
if (running) return liveSection(run, live, workSummary(run), runSteps(run, run.steps, null, true, ui2, handlers2), ui2, handlers2);
|
|
4009
4005
|
const last = run.steps.findLast((step) => step.by === null && step.kind === "message");
|
|
4010
4006
|
const steps2 = last && sameWords(last.text, run.report) ? run.steps.filter((step) => step !== last) : run.steps;
|
|
4011
4007
|
const handoffs = steps2.filter((step) => step.subagent).length;
|
|
@@ -4022,29 +4018,122 @@ function runWork(run, ui2, handlers2) {
|
|
|
4022
4018
|
null,
|
|
4023
4019
|
`How it got there, in ${steps2.length} ${steps2.length === 1 ? "step" : "steps"}` + (handoffs ? `, with ${handoffs} ${handoffs === 1 ? "subagent" : "subagents"}` : "")
|
|
4024
4020
|
),
|
|
4025
|
-
runSteps(run, steps2, null, ui2, handlers2)
|
|
4021
|
+
runSteps(run, steps2, null, false, ui2, handlers2)
|
|
4026
4022
|
) : null
|
|
4027
4023
|
);
|
|
4028
4024
|
}
|
|
4025
|
+
function liveSection(run, live, summary, content, ui2, handlers2) {
|
|
4026
|
+
const phase = live.landed ? "The brief is in; checking it and writing its report" : "Writing a new brief";
|
|
4027
|
+
return el(
|
|
4028
|
+
"section",
|
|
4029
|
+
{ class: "flyout__section" },
|
|
4030
|
+
el("h3", { class: "flyout__label" }, `${phase}, started ${relativeTime(run.startedAt, live.now)}`),
|
|
4031
|
+
el(
|
|
4032
|
+
"div",
|
|
4033
|
+
{ class: "agent-run__live" },
|
|
4034
|
+
workFold(run, summary, content, ui2, handlers2),
|
|
4035
|
+
el("button", { type: "button", class: "button", onClick: () => handlers2.stopAgent() }, "Stop")
|
|
4036
|
+
)
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
function workFold(run, summary, content, ui2, handlers2) {
|
|
4040
|
+
const key = `${run.id}:work`;
|
|
4041
|
+
return el(
|
|
4042
|
+
"details",
|
|
4043
|
+
{
|
|
4044
|
+
class: "agent-run__list agent-run__list--working",
|
|
4045
|
+
open: ui2.messageOpen.value.get(key) ?? false,
|
|
4046
|
+
onToggle: (event) => {
|
|
4047
|
+
const isOpen = event.currentTarget.open;
|
|
4048
|
+
handlers2.toggleMessage(key, isOpen ? true : null);
|
|
4049
|
+
}
|
|
4050
|
+
},
|
|
4051
|
+
el("summary", null, summary),
|
|
4052
|
+
content
|
|
4053
|
+
);
|
|
4054
|
+
}
|
|
4055
|
+
function workSummary(run) {
|
|
4056
|
+
const own = run.steps.filter((step) => step.by === null);
|
|
4057
|
+
const inFlight = own.findLast((step) => step.kind === "tool" && step.state === "running");
|
|
4058
|
+
const latest = own.at(-1);
|
|
4059
|
+
const working = run.steps.filter((step) => step.subagent && step.state === "running");
|
|
4060
|
+
const count = `${run.steps.length} ${run.steps.length === 1 ? "step" : "steps"}`;
|
|
4061
|
+
if (inFlight?.subagent) {
|
|
4062
|
+
return `Waiting on ${working.map((step) => step.detail ?? "a subagent").join(", ") || "a subagent"} \xB7 ${count}`;
|
|
4063
|
+
}
|
|
4064
|
+
const doing = inFlight ? inFlight.text : latest ? latest.kind === "message" ? firstLine(latest.text) : latest.text : "Starting";
|
|
4065
|
+
const helping = working.length;
|
|
4066
|
+
return `${doing} \xB7 ${count}${helping ? `, ${helping} ${helping === 1 ? "subagent" : "subagents"} at work` : ""}`;
|
|
4067
|
+
}
|
|
4068
|
+
function waitingLine(begun) {
|
|
4069
|
+
return el(
|
|
4070
|
+
"li",
|
|
4071
|
+
{ class: "assistant__step assistant__step--waiting", "data-state": "running" },
|
|
4072
|
+
el("span", { class: "assistant__step-text" }, begun ? "Thinking\u2026" : "Starting\u2026")
|
|
4073
|
+
);
|
|
4074
|
+
}
|
|
4029
4075
|
var NESTING = 4;
|
|
4030
|
-
|
|
4031
|
-
|
|
4076
|
+
var CALLS_FOLD = 2;
|
|
4077
|
+
function runSteps(run, steps2, by, active, ui2, handlers2, depth = 0) {
|
|
4078
|
+
const own = steps2.map((step, index) => ({ step, index })).filter(({ step }) => step.by === by);
|
|
4079
|
+
const inFlight = own.some(({ step }) => step.state === "running");
|
|
4080
|
+
const items = [];
|
|
4081
|
+
let calls = [];
|
|
4082
|
+
const flush = () => {
|
|
4083
|
+
if (calls.length >= CALLS_FOLD) items.push(callsFold(run, by, calls, ui2, handlers2));
|
|
4084
|
+
else for (const placed of calls) items.push(callLine(placed));
|
|
4085
|
+
calls = [];
|
|
4086
|
+
};
|
|
4087
|
+
for (const placed of own) {
|
|
4088
|
+
const { step, index } = placed;
|
|
4089
|
+
const folds = step.subagent && depth < NESTING;
|
|
4090
|
+
if (step.kind === "tool" && !folds && step.state !== "running") {
|
|
4091
|
+
calls.push(placed);
|
|
4092
|
+
continue;
|
|
4093
|
+
}
|
|
4094
|
+
flush();
|
|
4095
|
+
if (step.kind === "message") items.push(el("li", { key: index, class: "agent-run__said" }, renderMarkdownBlocks(step.text)));
|
|
4096
|
+
else if (folds) items.push(runHandoff(run, steps2, step, ui2, handlers2, depth, index));
|
|
4097
|
+
else items.push(callLine(placed));
|
|
4098
|
+
}
|
|
4099
|
+
flush();
|
|
4032
4100
|
return el(
|
|
4033
4101
|
"ol",
|
|
4034
4102
|
{ class: "assistant__steps agent-run__steps" },
|
|
4035
|
-
own.length ? null : el("li", { class: "assistant__step assistant__step--message" }, "Nothing yet."),
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4103
|
+
own.length || active ? null : el("li", { class: "assistant__step assistant__step--message" }, "Nothing yet."),
|
|
4104
|
+
items,
|
|
4105
|
+
active && !inFlight ? waitingLine(own.length > 0) : null
|
|
4106
|
+
);
|
|
4107
|
+
}
|
|
4108
|
+
function callLine({ step, index }) {
|
|
4109
|
+
return el(
|
|
4110
|
+
"li",
|
|
4111
|
+
{ key: index, class: "assistant__step", "data-state": step.state },
|
|
4112
|
+
el("span", { class: "assistant__step-text" }, step.text),
|
|
4113
|
+
step.detail ? el("code", { class: "assistant__step-detail", title: step.detail }, step.detail) : null
|
|
4114
|
+
);
|
|
4115
|
+
}
|
|
4116
|
+
function callsFold(run, by, calls, ui2, handlers2) {
|
|
4117
|
+
const key = `${run.id}:${by ?? "run"}:calls@${calls[0].index}`;
|
|
4118
|
+
const failed = calls.filter(({ step }) => step.state === "failed").length;
|
|
4119
|
+
const names = [...new Set(calls.map(({ step }) => step.text))];
|
|
4120
|
+
const named = names.length <= 2 ? names.join(", ") : `${names.slice(0, 2).join(", ")} and ${names.length - 2} more`;
|
|
4121
|
+
const summary = `${calls.length} calls${failed ? `, ${failed} failed` : ""} \xB7 ${named}`;
|
|
4122
|
+
return el(
|
|
4123
|
+
"li",
|
|
4124
|
+
{ key, class: "assistant__step agent-run__calls", "data-state": failed ? "failed" : "done" },
|
|
4125
|
+
el(
|
|
4126
|
+
"details",
|
|
4127
|
+
{
|
|
4128
|
+
open: ui2.messageOpen.value.get(key) ?? false,
|
|
4129
|
+
onToggle: (event) => {
|
|
4130
|
+
const isOpen = event.currentTarget.open;
|
|
4131
|
+
handlers2.toggleMessage(key, isOpen ? true : null);
|
|
4132
|
+
}
|
|
4133
|
+
},
|
|
4134
|
+
el("summary", null, summary),
|
|
4135
|
+
el("ol", { class: "assistant__steps agent-run__steps" }, calls.map((placed) => callLine(placed)))
|
|
4136
|
+
)
|
|
4048
4137
|
);
|
|
4049
4138
|
}
|
|
4050
4139
|
function runHandoff(run, steps2, step, ui2, handlers2, depth, index) {
|
|
@@ -4054,8 +4143,7 @@ function runHandoff(run, steps2, step, ui2, handlers2, depth, index) {
|
|
|
4054
4143
|
const calls = own.filter((candidate) => candidate.kind === "tool").length;
|
|
4055
4144
|
const doing = step.state === "running" ? latest ? latest.kind === "message" ? firstLine(latest.text) : latest.text : "starting" : `${calls} ${calls === 1 ? "step" : "steps"}`;
|
|
4056
4145
|
const key = `${run.id}:${id}`;
|
|
4057
|
-
const
|
|
4058
|
-
const open = ui2.messageOpen.value.has(key) ? ui2.messageOpen.value.get(key) : fallback;
|
|
4146
|
+
const open = ui2.messageOpen.value.get(key) ?? false;
|
|
4059
4147
|
return el(
|
|
4060
4148
|
"li",
|
|
4061
4149
|
{ key: index, class: "assistant__step agent-run__handoff", "data-state": step.state },
|
|
@@ -4066,7 +4154,7 @@ function runHandoff(run, steps2, step, ui2, handlers2, depth, index) {
|
|
|
4066
4154
|
// As the message folds do: a toggle back to the default is forgotten.
|
|
4067
4155
|
onToggle: (event) => {
|
|
4068
4156
|
const isOpen = event.currentTarget.open;
|
|
4069
|
-
handlers2.toggleMessage(key, isOpen
|
|
4157
|
+
handlers2.toggleMessage(key, isOpen ? true : null);
|
|
4070
4158
|
}
|
|
4071
4159
|
},
|
|
4072
4160
|
el(
|
|
@@ -4075,7 +4163,7 @@ function runHandoff(run, steps2, step, ui2, handlers2, depth, index) {
|
|
|
4075
4163
|
el("span", { class: "assistant__step-text" }, `Subagent: ${step.detail ?? "unnamed"}`),
|
|
4076
4164
|
el("span", { class: "assistant__step-detail" }, doing)
|
|
4077
4165
|
),
|
|
4078
|
-
runSteps(run, steps2, id, ui2, handlers2, depth + 1)
|
|
4166
|
+
runSteps(run, steps2, id, step.state === "running", ui2, handlers2, depth + 1)
|
|
4079
4167
|
)
|
|
4080
4168
|
);
|
|
4081
4169
|
}
|
|
@@ -4083,14 +4171,6 @@ function sameWords(a4, b4) {
|
|
|
4083
4171
|
return a4.replace(/\s+/g, " ").trim() === b4.replace(/\s+/g, " ").trim();
|
|
4084
4172
|
}
|
|
4085
4173
|
function runStatus(run, now, handlers2) {
|
|
4086
|
-
if (run.status === "running") {
|
|
4087
|
-
return el(
|
|
4088
|
-
"p",
|
|
4089
|
-
{ class: "agent-run__status" },
|
|
4090
|
-
`Writing a new brief, started ${relativeTime(run.startedAt, now)}. `,
|
|
4091
|
-
el("button", { type: "button", class: "button", onClick: () => handlers2.stopAgent() }, "Stop")
|
|
4092
|
-
);
|
|
4093
|
-
}
|
|
4094
4174
|
const took = runDuration(run);
|
|
4095
4175
|
if (run.status === "done") {
|
|
4096
4176
|
return el("p", { class: "agent-run__status" }, `Finished at ${formatTime(run.endedAt)}${took ? `, in ${took}` : ""}.`);
|
package/public/style.css
CHANGED
|
@@ -679,6 +679,24 @@ body[data-view='tickets'] #brief-refresh {
|
|
|
679
679
|
.agent-run__list summary:hover {
|
|
680
680
|
color: var(--ink-1);
|
|
681
681
|
}
|
|
682
|
+
/* The one line of a run still going: what it is on now, so it reads a step darker than a finished run's fold. */
|
|
683
|
+
.agent-run__list--working > summary {
|
|
684
|
+
color: var(--ink-2);
|
|
685
|
+
white-space: normal;
|
|
686
|
+
}
|
|
687
|
+
/* That line and Stop on one row; opened, the steps grow under the line and Stop stays put at the top. */
|
|
688
|
+
.agent-run__live {
|
|
689
|
+
display: flex;
|
|
690
|
+
align-items: flex-start;
|
|
691
|
+
gap: 10px;
|
|
692
|
+
}
|
|
693
|
+
.agent-run__live > details {
|
|
694
|
+
flex: 1 1 auto;
|
|
695
|
+
min-width: 0;
|
|
696
|
+
}
|
|
697
|
+
.agent-run__live > .button {
|
|
698
|
+
flex: none;
|
|
699
|
+
}
|
|
682
700
|
/* What the agent said along the way, one fold per message, under its first line. */
|
|
683
701
|
.agent-run__messages {
|
|
684
702
|
display: flex;
|
|
@@ -2347,8 +2365,12 @@ a.button {
|
|
|
2347
2365
|
font-variant-numeric: tabular-nums;
|
|
2348
2366
|
}
|
|
2349
2367
|
|
|
2350
|
-
/*
|
|
2368
|
+
/*
|
|
2369
|
+
* A spinner, for the turn while it works and for each call it is waiting on;
|
|
2370
|
+
* and on the line a running run folds under, which is all of it that shows.
|
|
2371
|
+
*/
|
|
2351
2372
|
.assistant__status--working::after,
|
|
2373
|
+
.agent-run__list--working > summary::after,
|
|
2352
2374
|
.assistant__step[data-state='running']::before {
|
|
2353
2375
|
content: '';
|
|
2354
2376
|
display: inline-block;
|
|
@@ -2360,7 +2382,8 @@ a.button {
|
|
|
2360
2382
|
border-top-color: transparent;
|
|
2361
2383
|
animation: assistant-spin 0.9s linear infinite;
|
|
2362
2384
|
}
|
|
2363
|
-
.assistant__status--working::after
|
|
2385
|
+
.assistant__status--working::after,
|
|
2386
|
+
.agent-run__list--working > summary::after {
|
|
2364
2387
|
margin-left: 6px;
|
|
2365
2388
|
vertical-align: -1px;
|
|
2366
2389
|
}
|
|
@@ -2371,6 +2394,7 @@ a.button {
|
|
|
2371
2394
|
}
|
|
2372
2395
|
@media (prefers-reduced-motion: reduce) {
|
|
2373
2396
|
.assistant__status--working::after,
|
|
2397
|
+
.agent-run__list--working > summary::after,
|
|
2374
2398
|
.assistant__step[data-state='running']::before {
|
|
2375
2399
|
animation: none;
|
|
2376
2400
|
}
|
|
@@ -2447,6 +2471,31 @@ a.button {
|
|
|
2447
2471
|
font-size: 11.5px;
|
|
2448
2472
|
color: var(--ink-3);
|
|
2449
2473
|
}
|
|
2474
|
+
/* A run of calls between two things the agent said, folded to the one line that counts them. */
|
|
2475
|
+
.agent-run__calls > details {
|
|
2476
|
+
flex: 1 1 auto;
|
|
2477
|
+
min-width: 0;
|
|
2478
|
+
}
|
|
2479
|
+
.agent-run__calls summary {
|
|
2480
|
+
cursor: pointer;
|
|
2481
|
+
overflow: hidden;
|
|
2482
|
+
text-overflow: ellipsis;
|
|
2483
|
+
white-space: nowrap;
|
|
2484
|
+
color: var(--ink-3);
|
|
2485
|
+
}
|
|
2486
|
+
.agent-run__calls summary:hover {
|
|
2487
|
+
color: var(--ink-1);
|
|
2488
|
+
}
|
|
2489
|
+
.agent-run__calls .agent-run__steps {
|
|
2490
|
+
margin-top: 4px;
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
/* Between calls: composing, which no call records. Quieter than a call, since nothing has happened yet. */
|
|
2494
|
+
.assistant__step--waiting .assistant__step-text {
|
|
2495
|
+
font-style: italic;
|
|
2496
|
+
color: var(--ink-3);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2450
2499
|
/* What it said on the way: its own words, in the reading face, set apart from the calls by having no mark. */
|
|
2451
2500
|
.assistant__step--message {
|
|
2452
2501
|
display: block;
|