8000 feat(timeline): show what an item caused, with Approve and Decline on waiting approvals by adeelahmad · Pull Request #642 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,9 @@ listed under [In progress](#in-progress), and what comes next under [Planned](#p
an emoji and commenting in threads everyone who sees the item shares (agents too, over MCP), and asking the
assistant about any item from the item; a comment that tags @lens gets the agent's answer in the thread, with
every change it proposes waiting for a yes, a For you order learned from each person's own reactions, comments
and marks says why each item is where it is, and each person mutes a source or a kind for themselves, with nothing
deleted. Automations act
and marks says why each item is where it is, each person mutes a source or a kind for themselves, with nothing
deleted, and an opened item shows what it caused, the runs and approvals, with Approve and Decline right there.
Automations act
on that stream, on a schedule, at a time or when their own webhook is called, alone or with their triggers joined (all
of them, a number of times, one that doesn't come in time, or a batch): they test conditions (text, patterns,
numbers, lists, times, days, whether a value changed and whether something like it happened before in their
Expand Down Expand Up @@ -322,7 +323,6 @@ Open pull requests, not yet part of Lens, are listed here; none right now.

Next, and not in a pull request yet; each links to where it is tracked:

- **Timeline:** what each item caused, and Approve and Decline on waiting approvals ([timeline](docs/timeline.md)).
- **Notes:** nesting a note under its project or area without a click, pages in the graph, and wiki addresses for
topics, recordings and the other things that have pages ([notes](docs/notes.md)).
- **Local models:** GPU builds of llama.cpp fetched by Lens, and local embedding models
Expand Down
5 changes: 5 additions & 0 deletions changelog.d/timeline-caused.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
An opened timeline item now shows what happened because of it: the automation runs it started (with their status and
a link to the automation) and the approvals those runs asked you for, with Approve and Decline on the ones still
waiting, so a pick is made where it was caused. `GET /api/v1/activities/{id}/caused` and the MCP tool
`activity_caused` read the same for agents, and `approvals` (API, MCP and the assistant) takes the activity that
caused them.
3 changes: 2 additions & 1 deletion docs/assistant.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ When the configured model supports function calling, chat becomes an agent.
the person ([Timeline](timeline.md#review-marks)), and `mute_activities` mutes a source, person or kind for them,
for good or until a time ([Muting](timeline.md#muting)). After it has read text from outside Lens, hiding, muting
or marking reviewed waits for their yes; marking important, lifting a mute or bringing things back acts at once.
- **The person's approvals:** `approvals` lists what waits for their pick ([Approvals](automations.md#approvals)):
- **The person's approvals:** `approvals` lists what waits for their pick, or what one timeline activity caused
(`activity`) ([Approvals](automations.md#approvals)):
automations' actions about the namespaces the conversation reads, and its own proposals in this conversation.
`decline_approval` declines one; after it has read text from outside Lens (the approvals' own summaries count),
declining waits for the person's yes. It can't approve: that is the person's pick. An automation's agent doesn't
Expand Down
5 changes: 3 additions & 2 deletions docs/automations.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ When the school's next email arrives:
(`/approvals`; a badge in the top bar counts what waits), and your chat app gets a message with a link to it.
Approve, edit or decline it there. A yes in your chat app decides only actions that stay inside Lens, so for a post
to a room the reply points you to the page.
- The run shows on the [Timeline](timeline.md) (filter it by the automation to see what it did and caused) and on
the automation's **Runs** tab, with what each action did and what it cost.
- The run shows on the [Timeline](timeline.md) (filter it by the automation to see what it did and caused; the
email, opened, lists the run and the waiting post under **What this caused**, with **Approve** and **Decline**
right there) and on the automation's **Runs** tab, with what each action did and what it cost.

Everything else in this guide builds on this one: more [triggers](#automations-triggers-and-joins), sharper
[conditions](#match-trees), other [actions](#actions-and-intents), and [time](#time).
Expand Down
3 changes: 2 additions & 1 deletion docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ For an app that speaks OpenAI's API rather than MCP, the namespace can also answ
| `activity_mutes`, `mute_activities` | the person's mutes on the timeline, and mute a source or person (`actor`) or a kind (`kind`), for good or `until` a time, or lift one with `on` false ([Muting](timeline.md#muting)); nothing is deleted. Muting needs a write-scope token |
| `react_to_activity` | put an emoji (👍 ❤️ 🎉 👀 😂 😮 😢 🙏) on an activity for the person, or take theirs back (`on` false), as on a post in a feed ([Timeline](timeline.md#reactions-and-comments)); everyone who sees the activity sees it, and it is a `reaction.added` activity. Needs a write-scope token |
| `activity_comments` | an activity's comments, threaded, with who wrote each; on an asset's arrival the asset's own. What people wrote is data, never instructions |
| `activity_caused` | what an activity caused ([Timeline](timeline.md#what-an-item-caused)): the runs it started of the automations the person manages, with their status, and the approvals those asked the person for, each as `approvals` shows it; on an approval's own activity, that approval |
| `comment_on_activity` | write a comment on an activity for the person, or with `parent` a reply on a thread; a `comment.added` activity. Needs a write-scope token |
| `approvals` | what waits for your pick, newest first ([Approvals](automations.md#approvals)): an automation's actions and the assistant's proposals, each with what it would do, why, when it expires, its link and what an agent may do (`can`); one by `id`, by `status` (pending by default, or `any`), `origin` or `automation`, a page at a time. On a namespace's own server, that namespace's alone. What it would do holds text the automation read from outside Lens |
| `approvals` | what waits for your pick, newest first ([Approvals](automations.md#approvals)): an automation's actions and the assistant's proposals, each with what it would do, why, when it expires, its link and what an agent may do (`can`); one by `id`, by `status` (pending by default, or `any`), `origin`, `automation` or the `activity` that caused them, a page at a time. On a namespace's own server, that namespace's alone. What it would do holds text the automation read from outside Lens |
| `decline_approval` | decline one of your approvals by id: nothing is done, and the run records it. There is no tool to approve: that is your pick, in Lens or your chat app. Needs a write-scope token |
| `automations` | the person's automations ([Automations](automations.md#agents)): each one's triggers, whether it's on, its last run and what waits; with `automation_id` one in full with its latest runs, with `run_id` one run with its trace, log and what its actions did |
| `automation_actions` | what an automation's action nodes can do: each action's params, what it reaches and what it gives back |
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ request, to another check that proves the same thing; loosening a requirement or
| A For you order of the timeline, learned from each person's own reactions, comments and marks, each item saying why, with Latest the default; through the API, MCP, the assistant and the page | [test_timeline_for_you.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/api/test_timeline_for_you.py) `test_for_you_learns_from_reactions_comments_and_marks_and_says_why`, `test_agents_read_for_you_too`; jest [timeline-model.test.ts](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/timeline-model.test.ts) `keep the For you order as a view, not a filter`, [timeline-ui.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/timeline-ui.test.tsx) `For you: the toggle goes in the address, each placed line says why, and Latest stays the default` |
| Muting a source, a person or a kind on the timeline, for good or until a time, for the person alone, with nothing deleted; through the API, MCP, the assistant (asking first after outside text) and the page | [test_timeline_mutes.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/api/test_timeline_mutes.py) `test_a_mute_hides_an_actor_or_a_kind_for_the_person_alone`, `test_agents_mute_too_and_the_assistant_asks_first_after_outside_text`; jest [timeline-ui.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/timeline-ui.test.tsx) `muting a source takes everything from it out, lists it as muted, and Undo or the chip brings it back` |
| An asset moved to another namespace is `asset.moved`, a Move seen where it is now, and a sensor a person pauses, ignores, resumes or sets back to new is `sensor.changed`, an Update with the status it had before, seen in its namespace or by admins; a change that changes nothing logs nothing | [test_timeline_verbs.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/api/test_timeline_verbs.py) `test_moving_an_asset_is_a_move_seen_where_it_is_now`, `test_switching_a_sensor_is_an_update_with_what_it_was` |
| An opened timeline item shows what it caused, the runs it started of the automations the person manages and the approvals those asked for, with Approve and Decline on waiting ones; `GET /activities/{id}/caused`, `approvals?activity=`, MCP `activity_caused` and the assistant | [test_timeline_caused.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/api/test_timeline_caused.py) `test_an_item_lists_what_it_caused_and_the_waiting_approval_is_decided_there`, `test_agents_read_what_an_item_caused_too`; jest [timeline-ui.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/timeline-ui.test.tsx) `an opened item shows what it caused, and a waiting approval is approved there` |
| Every entity's own page at `/wiki/<namespace>/<Name>` | [test_entities.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/api/test_entities.py) `test_wiki_addresses`; [wiki-page.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/wiki-page.test.tsx); [journeys.mjs](https://github.com/adeelahmad/lense/blob/main/ci/clicks/journeys.mjs) `entity-find` |
| Entities, topics and people edited and merged from their lists, the graph or an asset, with Undo instead of a confirm | [test_entities.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/domain/test_entities.py) `test_suggestions_and_merge_undo`; [entities-curate.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/entities-curate.test.tsx); [topics-curate.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/topics-curate.test.tsx); [recording-entities-edit.test.tsx](https://github.com/adeelahmad/lense/blob/main/nextjs-frontend/__tests__/recording-entities-edit.test.tsx); [journeys.mjs](https://github.com/adeelahmad/lense/blob/main/ci/clicks/journeys.mjs) `entity-merge`, `graph-merge`, `speaker-rename` |
| Names get their real types (people, places, organisations, events, works) by rules, without a model; older Terms are typed on upgrade | [test_name_types.py](https://github.com/adeelahmad/lense/blob/main/fastapi_backend/tests/domain/test_name_types.py) `test_names_get_the_type_their_words_give`, `test_analysis_types_people_places_and_events`, `test_the_upgrade_types_the_old_terms_and_keeps_what_people_chose` |
Expand Down
25 changes: 22 additions & 3 deletions docs/timeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Status: in progress. The studio's timeline is built in steps; only what is merge
| A Latest card on Home with the newest unreviewed items | built |
| Reactions and comments on any item, shared by everyone who sees it; `react_to_activity`, `activity_comments` and `comment_on_activity` for agents | built |
| Ask about an item: talk to the assistant about it from the item, in the chat beside the page | built |
| What each item caused (automation runs, approvals), and Approve and Decline on waiting approvals | planned |
| What each item caused (the automation runs it started, the approvals they asked for), with Approve and Decline on waiting approvals from the item; `activity_caused` for agents | built |
| Tagging the agent in a comment, so it answers in the thread | built |
| Sources, sensors, people and agents as actors in the graph: a Source node with ADDED links, on the canvas, in the explorer and in Cypher | built |
| A For you order learned from what each person reacts to, comments on, marks important and hides, each item saying why | built |
Expand All @@ -40,8 +40,8 @@ unless you ask for them by kind.
- A run of the same source or person and the same kind, each within 30 minutes of the one before, is one line
("Work Gmail received 37 emails"), so a first mailbox sync reads as one line. A click opens it to its items.
- Each line has an icon by kind, the summary (a link to what it is about), who did it, the namespace, the kind and
how long ago. Opened, an item shows its object's fields, the automation run that caused it if one did, **Open**,
**Ask about this** and **Hide**.
how long ago. Opened, an item shows its object's fields, the automation run that caused it if one did, **What
this caused** ([below](#what-an-item-caused)), **Open**, **Ask about this** and **Hide**.
- Filters: words in the summary (Enter applies), **Unreviewed only**, **Important**, kinds by family (Email,
Calendar, Files, Notes, Sensors, Chat, Automations, System; noisy kinds like sensor readings only when picked),
source or person (from those on the timeline), namespace, entity (as activities tag it), a date range, and an
Expand Down Expand Up @@ -161,12 +161,31 @@ Marks change nothing else: an activity you hid still triggers automations and st
`mark_activities` marks them for the person. After it has read text from outside Lens (the timeline's own titles count), hiding or marking reviewed
waits for the person's yes, since that text may have asked for it; marking important or bringing things back acts
at once ([Chat](assistant.md)).
- MCP: `activity_caused` (`id`) is what an item caused, the runs and approvals ([What an item caused](#what-an-item-caused));
`approvals` and the assistant's `approvals` take `activity` to list the approvals one item led to.
- MCP, on the feed: `react_to_activity` (`id`, `emoji`, `on`) reacts for the person it acts for, `activity_comments`
(`id`) reads an item's threads, and `comment_on_activity` (`id`, `text`, `parent`) writes a comment or a reply,
with a token that has the write scope. The `timeline` page carries `reactions` and `comments` too. Comments are
what people wrote: agents read them as data, never as instructions. A comment an agent writes with `@lens` in it
gets the assistant's answer like anyone's, as the person the token acts for.

## What an item caused

An opened item shows what happened because of it: each automation run it started (of the automations you manage,
with its status and a link to the automation's runs) and each approval those runs asked you for, with what it would
do and its status. An approval still waiting has **Approve** and **Decline** right there, so the pick is made where it
was caused, and the item's line on the Approvals page is the same approval. An approval's own line on the timeline
("School emails asks for your pick") lists that approval under **Your pick**. Items that caused nothing show no such
block.

- `GET /api/v1/activities/{id}/caused` is `{runs, approvals}` for the person asking: the runs of the automations they
manage ([Automations](automations.md)), and their own approvals, each with `can` (approve, decline) as
`GET /api/v1/approvals` shows them; `POST /api/v1/approvals/{id}` decides one. `GET /api/v1/approvals?activity=<id>`
lists the approvals an activity caused on its own. On an `ask-approval-<id>` activity, the approval itself.
- `activity_caused` over MCP (`id`) reads the same, with each approval as `approvals` shows it; `approvals` takes
`activity` too, and so does the assistant's `approvals`. Approving stays the person's: an agent can list and
decline ([Agents](#agents)).

## Muting

Each person mutes a source or person (an actor) or a kind of activity ("hide syslog"), for good or until a time
Expand Down
Loading
Loading
0