Repository navigation
add a home page that turns what a person types into quick-action widgets - #114
Merged
Merged
Conversation
…uest is still being typed The home page shows what was done each day of the past year, a column per week, each day shaded by how busy it was, its tooltip saying each agent's part and how many were blocked, and a busy day leading to its part of the activity log. Under it, the past week in a line: how many requests, the three things most done, and how many were blocked. Days are on the browser's clock: GET /api/activity/summary?timeZone=… counts them in SQL, and @proxy/utils/days names days on a time zone's clock. The activity log takes outcome, from and to, so ?outcome=denied and ?day=2026-10-14 link to what was blocked and to a day. The model now answers incomplete for text cut off or saying too little yet, which is never kept, so what is on screen stays until there is more to tell from. A whole request no widget does opens "Not a quick action (yet)", pointing to the person's agents, once typing has paused.
- link a new event and a contact by the record's url, which the connectors set, rather than a link value they never have - read an answer again after a write clears the lookups, in every widget showing it, and keep none asked for before the clear - search email only from a day it can have come on: not one still to come, a time of day alone or a day said as "friday's", and "friday" or "december" alone as the last one - take only time zones by name, since Postgres reads an offset such as +05:00 the POSIX way, and answer a name the database has no rules for as a validation error - find people copied on an email too, the home page's mail searches answering Cc beside a list's values - link an email found by Gmail's own url, which opens a draft to be written
Each name searched every mailbox on its own, and over IMAP each search was its own sign-in, so five names and two IMAP mailboxes opened ten connections at once, past what servers allow an account. A mailbox search now takes several searches and answers what each found: over IMAP one sign-in runs them one after the other, over Gmail's API one token runs them together, and the People widget asks each mailbox once for all its names.
Over IMAP, the People widget's searches, each only for someone, are now one search for any of them: the newest of their emails, as many as all of them could want, are read once and each goes to everyone it involves. Someone those leave short, behind someone written to more, is searched for on their own over the same connection, so each still gets their own newest. Other searches still run one after the other.
…ed about "What's on my calendar tomorrow" shows that day of every calendar; "when am I meeting arne" finds the next events with Arne, by his name and the addresses his contact has, and shows the first one's day with it highlighted, the next few a click away. GET /api/widgets/events searches every calendar shown from a time on with Google's own search, and the New event widget's day is now a shared DayGrid, which puts events at the same time side by side.
…e calendar widget finds
"Move my 1:1 with Hugo to Thursday at 4" finds the event as the Calendar widget does and shows
what changes beside what it was: the time ("an hour later", "10am", "thursday", a weekday from the
event's own day on), the title, the place, and guests invited or taken off, with the day it moves
to and what it would clash with. PUT /api/widgets/events changes it through the calendar's
connector as an agent's edit would, only an event the person organizes, needing Invite guests
where it has any, and logs it without picking a calendar for the next new event. Calendar reads
now carry each event's place, guests and whether it can be changed.
The Calendar widget named the event's person after the first namesake the contacts and mailboxes
had ("mike" as Mike McCarthy for a meeting with Mike Mahlkow); it now names the one whose address
is among the event's guests, else the name as written.
…d classifier - take off an event only the guests a name means: its contact's addresses, or an address whose first word it is, so "dan" no longer takes off daniel@ and dana@ - search for the next event from the minute it is, not today's midnight, so a meeting over this morning isn't the one moved or shown; a day asked about still searches from its midnight - ask Gmail over IMAP for every email when a search says nothing, which X-GM-RAW won't take empty - keep an event on two calendars once, in a day as in a search, and the copy the person can change, rather than a colleague's they only read - ask at most six of a Google account's calendars at once, and fail the account when Google is out of reach or busy rather than showing what was found as all there is - list only as many Gmail messages as a search reads, and run three of an account's searches at once rather than one per name - clear the six-second timer of each source, and close an IMAP connection given up on rather than leaving it open until its searches are done - let the classifier answer in up to 2000 tokens, as its thinking and an email's body count too - share mapWithLimit, addDays, a day's key and a counted noun rather than keeping copies
hkonsti
force-pushed
the
hkonsti/jev-api-classification
branch
from
October 17, 2026 00:52
12946dd to
fabdcfb
Compare
The Google client and the mail connectors read the environment on import, so the sources, files and writes tests failed wherever DATABASE_URL isn't set, as in ci.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a home page with a command input: as the person types,
POST /api/intentasks gpt-oss-120b over OpenRouter (Cerebras, else Groq, held to a JSON schema) which widget fits and fills in its fields, and the page shows that widget — New event, Change event, Calendar, Person, Write email, Find email, Find file, Math and Convert units — or "Not a quick action (yet)" for a whole request none does. The widgets read every connection with the right collection through the new/api/widgets/*routes and write as the person picks: an event created or changed, or an email written, is logged in the activity log without an agent (AuditEntry.agentIdis now nullable), and the calendar or mailbox last written to is remembered in the newWriteTargettable (migrationv020_add_write_targets).The home page also shows a year-long activity graph and a summary of the past week, from the new
GET /api/activity/summary?timeZone=…, and the activity log now takesoutcome,fromandto. Mailbox searches take several queries at once, so the People widget signs in to each IMAP mailbox once for every name rather than once per name. The home page needs the new optionalOPENROUTER_KEY(added to.env.example,docker-compose.ymlandrender.yaml); without it the home page says it isn't set up, and nothing else changes.Open workspace in Conductor