Agent chat - #52
Draft
paulsonnentag wants to merge 51 commits into
Draft
Agent chat#52paulsonnentag wants to merge 51 commits into
paulsonnentag wants to merge 51 commits into
Conversation
Provenance generalizes comments: entries stored in a generated doc's @provenance section link its elements (targets) back to ranges in the docs they came from (sources), always as automerge urls. The provider indexes every doc mounted inside it and answers patchwork:provenance subscriptions scoped by either end, so a source text doc can see inbound links it doesn't store. codemirror-base renders provenance source ranges (dotted link-accent tint) and pushes their targets into the shared focus selection when the cursor lands on them.
Add an unfoldable debug section showing installed/loaded/active llm:skills. Let the computer activate skills mid-run: a load_skill tool, and auto-activation when read_doc returns a document matching an inactive skill's datatypes (instructions delivered inline with the read result).
codemirror-base no longer knows about provenance: `codemirror:extension`
modules may now be factories receiving {handle, element, repo}, and the
corkboard registers one that decorates provenance source ranges and pushes
their linked targets into the shared focus selection.
The model can now mint edit-stable refs — an element by path/{id} matcher,
or a text range by cursor-anchored offsets — so provenance entries can point
at specific passages and elements instead of whole documents. Bumps the
debug panel version to v0.0.2.
…rgets Lets a selection on a Petrinaut canvas light up the source text range, not just the other way round.
Provenance entries moved under the document's @Patchwork envelope (a plain array, no `entries` wrapper) — the provider indexes and ref-urls them from the new path.
Collaborator
✅ Patchwork glance readyhttps://patchwork-preview-52--patchwork-base.netlify.appPatchwork from |
The agent's computer gets a start_scenario tool: called before each alternative's edits, it forks a fresh draft off main and re-aims the run's doc resolution at it, so one sequential run can produce several independent scenarios. Runs that opened scenarios end with a picker embed instead of the single accept/reject — chips check each branch out (with diff baselines) for browsing back and forth, accept merges the selected scenario and unlinks the rest, reject-all discards everything.
On pnpm >= 11 a workspace-less `pnpm -r` recurses into every directory with a package.json, including the aggregated copies in static-dist/packages/. Those keep their dev/build scripts but have no sources or node_modules, so they all fail and their exit code tears down the whole watch.
- add get datatypes tool and skill - add create embed of datatype to existing corkboard skill
Record merge provenance on the DraftDoc (mergedFrom per clone, mergedInto) and walk the change DAG between fork and merge heads to pull a merged draft's changes out of the time-based grouping into one labelled group. Scrub boundaries now resolve from the rendered row order instead of raw timestamps (merged changes interleave in time), and the baseline handle renders as the boundary below its change so a selected group reads as a full band. Merging adopts members the target never forked, keeping their changes scoped to the target draft.
Mirror the drafts sidebar's updated mergeDraft in mergeAgentDraft: adopt members the merge target never forked, and record mergedFrom per clone and mergedInto on the draft, so chat-accepted drafts show up as attributed "Merged" groups in the drafts timeline.
Fill the FIRST unfilled tool-call card — searching from the end paired a multi-call round's results with the wrong cards. Inactivity timeout up to 5 minutes: a model streaming a huge tool call looks silent to the llm lib. SkillsDebug reads the shared CHAT_VERSION instead of its own constant.
Change groups split at comment timestamps so each comment (including replies and resolved threads) gets its own row. Clicking a comment pins the draft to its state at that time, switches the context sidebar to the comments tab via a new patchwork:open-context-tool event, and asks the comments view to select and scroll to the thread through an openThread field on the shared patchwork:focus doc. Comment writes no longer count as edits, and the idle scrubber line sits above comments newer than the latest change.
A thread whose target was not a bare document url was assumed to be a cursor-anchored range, and dropped when it had no range to measure. That hid every comment anchored to a whole value — an entity in a list, a field — so Petrinaut's per-place comments were written, indexed, and never listed. Threads are now sorted by what their targets resolve to rather than by what their urls look like: an unranged target is visible while it resolves, and fails the same way a ranged one does when the thing it names is deleted. Unranged threads become primary by being clicked, as document-level ones already did. The header carries a build number so a stale panel is visible on screen.
It existed to confirm a push reached the browser; it has, so the header goes back to just the title.
A draft now carries reviews: each person's approve-or-reject verdict, keyed by their contact, pinned to the member heads they were shown. Merging needs at least one approval that still covers what is in the draft — changes landing afterwards make a verdict stale, and a stale approval no longer opens the gate. Rejection is advisory: recorded and shown, but not a veto. Whoever's approval authorised a merge is frozen onto the draft at merge time and carried through to the merged group, so the timeline row in the target says who signed it off.
The empty state's greeting spoke for the user before they had said anything; an empty chat now says nothing, with the input as the invitation. The skills panel was a fold-out for reading how llm:skill activation was behaving, which it no longer needs to be looked at for. Its two read-only accessors on llm-skills existed only to feed it and go with it.
Chat derives every surface from the editor tokens but was taking its ink from the chrome ones. The theme mixes each accent toward the line of the surface it will be read on, so --studio-primary-text and --editor-primary-text are different colours the moment a theme gives the editor its own fill — which is how an accent ends up unreadable on the background chat actually paints. Accent, link, danger and the three text weights now come from the editor family, falling back to the chrome one. --accent-line is ink ON the accent fill, but all but three uses were edges on the ambient surface, where it draws the background colour. Those move to a new --accent-border. --border sat on the same offset as --bg-darkest and --bg-hover, so a border on either was invisible; it moves a step further out. A rejected draft review had no colour of its own and fell through to muted, so the two outcomes didn't read as opposites.
+971 / -155 used --studio-added and --studio-deleted directly. Those are highlight colours, meant to be painted behind text rather than read as it, so on a light panel the counts came out as near-invisible neon. Drafts only ever uses them as ink, so they now go through the theme's own convention for that — the accent mixed 35% toward the surface's line, which lightens instead on a dark theme. Added to theme.css as --studio-added-text / --studio-deleted-text alongside the other inks; spelled out in drafts too, since the theme document is published from elsewhere and won't carry the new token for a while. The secondary ink sat at line-offset-50, three quarters of the way into the fill, which put the timestamps and most of the timeline on the edge of legibility. It also left "muted" lighter than the "faint" below it; both now step in the order their names imply.
Approving a change is the same act as commenting on it — you looked, formed a view, said so — so the Approve/Reject pair moves to the comments panel, under the header and above the threads it concludes. comments-view reaches drafts only through the provider channel (draft:list, draft:checked-out) and the repo, so the bar simply doesn't render when no drafts tool is answering, or on main. The DraftDoc shape it writes is restated locally rather than imported; the packages stay standalone. The drafts sidebar keeps the half that belongs to it: it still reads the reviews to decide whether merging is allowed, and still names the approvers on the merged row. It no longer offers a verdict, so its contact subscription and the icons that went with the bar are gone.
The card had no hierarchy: muted label, muted buttons, muted everything on a tinted box. Now the draft name is the title under a small REVIEWING eyebrow, the two verdicts are outlined in their own colour and fill in once given (the other stepping back to neutral, so the card shows one decision), and a standing verdict colours the card's edge. Reviewers are an overlapping avatar row with the verdict badged on each corner. Add comment leaves the header for its own dashed row below the card: a comment is the finer-grained thing, said about part of what the verdict is about. The panel's muted ink steps in from offset-50 to -40 — at three quarters into the fill the title and every timestamp were barely there.
Comments start from the thing being commented on — a selection in the editor, a cell in a notebook — not from the panel. The document-level thread creator and its button existed to cover tools that couldn't anchor a comment anywhere; that path goes too, since nothing else called it.
The gate got in the way more than it protected anything. Merging is always available again; approvals are purely a record — whoever's approval stands at merge time is still frozen onto the draft and named on the merged row, and an unapproved merge simply says nothing about approvers.
Approving still happens in the comments panel; the draft card now shows who has approved or rejected the draft as avatar marks beside its name, faded when the verdict predates the draft's current contents. Member heads are watched for every listed draft, not just the selected one, so the marks are right on unselected cards too. Drops the dead review-strip CSS left from the card-based UI.
A merge that threw halfway left the draft listed and the view where it was, indistinguishable from a button that did nothing. Report the error and log each member as it merges.
A group of changes shows in a draft's timeline only when it names who made it: an actor that resolves to a contact, or an agent tag. Changes from a device that never signed in are left out rather than shown under an anonymous avatar. Merged-draft groups always show, and the empty state says when there are edits but none from a known account.
A merge group renders as one bordered block holding the merge row and, unfolded, its contributor runs. The chevron moves into the row as a 1.25rem SVG target instead of a glyph hanging in the gutter strip.
The merge row's chevron no longer carries a z-index, so the pinned sticker paints over it like over the rest of the row. Rows without a chevron indent by its width so every avatar lines up.
It holds the approve/reject verdict as well as the comments now; the tab and header say so. The plugin id stays comments-view, which is what the drafts sidebar opens it by.
Resting the pointer on a contact avatar — the inline one in history rows, review marks and comments, or the default-size one — floats a card with their picture at 64px and their full name. The card lives on <body>, placed against the viewport so no scrolling ancestor clips it, and takes no pointer events. The inline avatar's title tooltip goes, since the card now says the same thing.
A member whose clone or target the repo can't produce — a doc that only ever lived in another browser's storage, or that the sync server never saw — is skipped and reported instead of aborting the merge. Members load 16 at a time with a 20s bound each, since a draft can carry well over a thousand of them. The merge reports how many were left out.
The count goes to the console instead of a dialog: with the dead infrastructure clones drafts currently accumulate, it would fire on every merge.
The clone policy turns positive: a doc is draft content when it carries a @patchwork.type that isn't on the skip-list, which now also names patchwork:tool-storage. Untyped docs — the per-session focus doc, the checked-out-draft doc, read positions, raw blobs — are no longer forked, no longer reported as members, and no longer get a main draft stamped on them when a provider mounts over one. Opening a draft prunes its clone map once per session: entries that are not content under the policy, and clones the connected sync server reports unavailable (never on a timeout, never offline, never merged entries). Member resolution for scrubbing and review staleness runs concurrently with one summary warning instead of one per dead member.
The chat's accept path is its own copy of the sidebar's merge, and it still stopped at the first clone the sync server couldn't find. It now loads every clone up front, concurrently, and merges the ones that loaded, logging one summary line for the rest. The agent's own resolution (resolveInDraft) follows the same positive clone policy as the sidebar: only typed docs off the skip-list get a per-draft clone; untyped session docs and tool-storage pass through.
The actor-attribution entry now stores the contact url pinned to the contact doc's heads at the moment the actor was first attributed (automerge:<id>#h1|h2). The sidebar hands that url straight to the contact-inline view, which renders the doc at those heads: the name and picture of the time, hover card included. Identity comparisons (group splitting, avatar dedupe) strip the pin via canonicalUrl so one person across sessions still reads as one contributor. Bare pre-pinning entries keep rendering the live contact.
… target History comments are now identified by thread id + comment id, not by the member they were read through, so a thread reachable via two members after a merge renders once. A thread present at a merge group's mergeHeads and absent at its baseHeads was born on that branch; the timeline lists such comments inside the unfolded merge block, interleaved with the contributor runs, instead of at the top level of the target's history. The branch's own timeline is unchanged. Both merge paths (sidebar and chat accept) mark branch-born threads resolved on the target after target.merge(clone). The clone is untouched, so the branch checked out again still shows them open.
A user message matching "minimum order(s)" or "partial fulfilment" on a petrinaut-petrinet document gets a pre-written turn instead of a model call: a plan sentence, the tool calls (run through runToolByName, so the edits are real and land in the agent's draft), then a closing summary. Prose streams a word at a time with a lead-in and sentence pauses. The two runs edit disjoint fields — run 1 splices the two small-order arrival kernels, run 2 appends a partial-fulfilment transition; both only append to parameters — so they can be made on separate drafts and merged either way round.
The scripted partial-fulfilment run now adds five parameters, a PartialShipmentCosts place, two transitions (partial fulfilment and finished-goods consolidation), four metrics, and edits the existing net: the full-fulfilment transition is renamed, prioritises tagged remainders and records sales under the plain segment; spot cancellation softens once part of the order has shipped; the orders-fulfilled and lead-time metrics count only the closing delivery; policy cost includes the new place. Still disjoint from the minimum-orders run, which only touches the two small-order arrival kernels.
A merge forces a full regrouping of the target's timeline so the merged changes come out of the time-based groups and into one merge block. That pass resolved every member one at a time with no bound, so a timeline carrying dead members stalled on them — the old groups stayed on screen under a permanent "Building history…", and the merge block never came. The grouper now loads members 16 at a time with a 30 s bound and reports the unloadable ones in one line. Both merge paths load a member's target before the parent adopts it, so an original no peer has any more is skipped instead of being written into main's clone map as a member. The clone-map prune now also covers main.
The overlay logs each clone it creates — the doc's type, the element whose handle request caused it (tag, tool-id/doc-url, enclosing patchwork-view), the draft, and a running tally by type — and the agent's resolveInDraft logs the same with the calling frames. A merge logs its members tallied by datatype, so a bloated draft says what it is made of.
The log you pasted showed ~30 members each carrying the same 13 change hashes: clones of clones. A clone url handed back to the overlay (or to the agent's resolveInDraft) as if it were an original isn't found in the clone map — that is keyed by originals — so it got forked again on every hop. Both fork sites now look the url up by value and, when it is already this draft's clone, return it as-is and warn with the requester. Console prefixes are now `[drafts:fork]`, `[agent:fork]`, `[drafts:merge]`, `[agent:merge]` so `:fork` / `:merge` filter the trail. The merge summary counts clone-of-clone members and lists them. The per-change grouper trace that flooded the console is gone; the other grouper traces are console.debug (Verbose only).
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.
No description provided.