Repository navigation
feat(graph): ship conversational authoring and execution defaults - #4
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Records the verified deviations in Graph AI authoring (server LLM key required, single executor agent, selected agent not used for generation, no team context for the model), the proposed move to runtime-agent tasks following the quick-create pattern, open decisions for the product owner, an implementation plan, and the carried-over backlog.
…r model Graph "Create with AI" required MULTICA_LLM_* on the server and 503'd without it, and the single agent_id it accepted never took part in generation — it was only written into the finished nodes. Authoring now runs where the work actually happens: the request is queued as a task on a runtime agent the requester picks, and that agent answers with a validated draft. - Request carries an agent scope plus one default executor, so a draft can spread its steps across the team instead of stamping one agent on every node. - The model sees a team directory built from that scope, rather than being told to guess names from the description. - Generation is asynchronous: POST returns 202 with a view derived on read (queued/running/succeeded/failed/cancelled), and the requester can cancel. One in-flight request per requester; 3 minute queue and 15 minute run timeouts; at most 4 accepted-or-rejected drafts. - `multica graph draft context|submit` is how the authoring task reads its request and hands in a definition. These are the task-credential commands, not management ones. - Migrations 372-374 add the graph_generation table that stores the request and its draft. - The legacy POST /api/graphs/generate and the server-model path stay as a fallback until real-agent acceptance passes. Co-Authored-By: Claude Code <noreply@anthropic.com>
Wire the web client to the asynchronous authoring API the backend now serves. The runtime path is preferred whenever the server can serve it and the previous synchronous path stays as the fallback, so a self-hosted instance that predates the runtime path keeps working unchanged. - `packages/core/graphs` gains the generation view, create request and authoring-message types, a job query keyed under `graphKeys.all(wsId)` that polls every 5 seconds while the job is queued or running, and create/cancel mutations. Because the key sits under that prefix, the existing `graph:` realtime handler already invalidates it — no new realtime code. - `graphGenerationMode` resolves the three-way mode (runtime, legacy, unavailable) in one place, and the option schema folds `enabled` and `runtime_enabled` into explicit booleans without merging the two signals. - `GraphActorMultiPicker` is a sibling of `GraphActorPicker` rather than a `multiple` mode on it: the existing picker has five call sites with a strict single-value signature, and a sibling can reuse the file's private helpers. - The composer renders participating agents, a default executor, the approver and the cost hint only on the runtime path; the legacy path renders exactly what it did before. Submitting, cancelling and every failure code are driven by the job, and failures keep the description and the conversation so the user can retry immediately. - The editor snapshots the definition at enqueue time so the staleness check compares against what the model actually saw, consumes a finished job into a proposal exactly once, and leaves the apply/discard flow untouched. The legacy `POST /api/graphs/generate` and `useGenerateGraph` are kept: the fallback path and the mobile client still use them. `apps/mobile` therefore still shows "AI generation unavailable" on a server without `MULTICA_LLM_*` even though the web client works there; moving it over is tracked separately. Co-Authored-By: Claude Code <noreply@anthropic.com>
`graphIntegrationPool` hand-builds a legacy schema and then applies only the migrations in a hardcoded window `[332, 371]` minus 358. When 372–374 added the `graph_generation` table the window was not raised, so two integration tests failed with `relation "graph_generation" does not exist` — the private schema had silently fallen behind the Graph schema. Raise the bound to 374 and replace the bare numbers with named constants so the intent is written down, then add `TestGraphIntegrationCoversGraphMigrations` to glob `migrations/*_graph*.up.sql` and fail when a Graph migration lands outside the window. The upper bound is kept rather than dropped: today the whole range happens to be Graph migrations, but the next unrelated migration would otherwise be applied to this hand-built schema and fail deep inside the Graph suite with the same opaque error. 358 stays excluded. It installs `pin_plugin_execution_manifest()`, whose body declares `plugin_*%ROWTYPE` and reads `plugin_workspace_capability_state` — tables this schema never creates, so it cannot even parse. Co-Authored-By: Claude Code <noreply@anthropic.com>
The docs still described AI authoring as a synchronous call to a server-configured model, and the built-in skill told agents the server's own provider writes the draft. Both stopped being true when authoring moved to a runtime agent, and a claim of that shape reads as authoritative and misleads. - The delivery doc's AI authoring row, workflow step and LLM paragraph now describe the runtime path: the request is queued on the default executor's runtime, drafts may spread steps across the participating agents, and the `MULTICA_LLM_*` variables only serve chat titles and quick actions. The migration number is corrected to 374, the Compose sentence no longer claims it carries LLM config, and the evidence table gains a caveat that no row covers the runtime path and that its migration numbers stop at 371. - `.env.example` keeps the three variables — `handler/chat_title.go` and `service/chat_quick_actions_generate.go` still read them — and adds a note that this layer does not back Graph authoring. - The design and plan documents record the adopted section 6 decisions and the real progress, including that real-agent acceptance has not run. - The skill documents `multica graph draft context|submit`, notes that a rejected draft spends one of four submissions, and that these two commands are the exception to "Graph task credentials cannot use management commands" because they require a task credential. The source map replaces the stale `GenerateGraph` description and gains grep anchors, each verified against the tree. Co-Authored-By: Claude Code <noreply@anthropic.com>
Real-machine acceptance on a fresh local environment with no MULTICA_LLM_* configured. Recorded as three evidence rows' worth of findings: - Claude-executor generation succeeded and put two different agents in one draft (ab1296b6 and 92ae4457), which is the multi-agent criterion. - Cancel, daemon-offline/queue-timeout and concurrency limits all behaved as designed. - The content sent to the model is a fixed template plus an alias-only request; the alias-to-UUID map stays server-side. - The Codex-executor run did NOT complete: the only local Codex account is out of quota until 2026-10-20. The proxy the daemon needed was fixed first, so the task did reach the model; the refusal was then reported correctly and left no draft. - Retry exhaustion is still only covered by Go tests. The attempt to induce it with a real agent was refused by the agent as prompt injection. Acceptance has therefore not fully passed, so deleting the legacy path stays blocked. Co-Authored-By: Claude Code <noreply@anthropic.com>
…ance The mobile migration was investigated and deliberately deferred, so the plan now records what that investigation found instead of leaving the next reader to redo it: the only real defect is two reads of `enabled`, the runtime flag is already parsed onto the same object, and the genuine gap is that mobile has no multi-select picker at all for `agent_scope`. Also records the two operational follow-ups: re-running the Codex half once its account quota resets on 2026-10-20, and rotating the Codex proxy password that was printed to the terminal once during the run. Co-Authored-By: Claude Code <noreply@anthropic.com>
The Graph AI entry point asked for a description, queued a generation task on the chosen executor's runtime, and let the agent hand in a draft with `multica graph draft submit` — four submissions to get it right. Two things were wrong with that shape. The interaction hid the work: nothing was visible until "Apply". And the budget had no counterpart anywhere in the repository (creating an agent is an unbounded conversation), while its failure path lied — exhausting it called CancelTaskWithReason, which revoked the submitting task's own token, so the agent's next call got a 401 and the page blamed the description. Creation is now a chat session, the same mechanism the agent builder uses: - `handler/graph_builder.go` creates a hidden `kind='system'` carrier agent (`system_key = graph_builder:<flow>`) and a `chat_session` in one transaction, under the same workspace lock the chat path uses. The carrier clones the chosen executor's runtime and model and installs `graphBuilderInstructions` as its only system prompt — a chat task has no per-task ad-hoc prompt channel. - `graphBuilderExecutor` gates the choice: the agent must be in the workspace, invocable by the caller, have a model, and have a runtime that is bound, usable and online. - The carrier contract embeds the same `graphDefinitionGrammar` the legacy server-model prompt uses, and `graph_prompt_contract_test.go` fails if either side drifts. - The one-shot pipeline is deleted: the authoring handler and request builder, the generation store and task, `daemon/prompt_graph_authoring.go`, the Graph authoring daemon/CLI capabilities, the `graph draft` command group, and the `graph_generation` table (migration 375, migration window guard raised to match). `graphAgentEligible` moves next to its remaining caller in `handler/graph_generation.go`, and the legacy synchronous `POST /api/graphs/generate` stays for self-hosted and mobile callers. - `ListGraphBuilderSessions` lists only the caller's own graph-builder conversations, so an orphaned carrier can be found and discarded after the client's draft document is gone. Co-Authored-By: Claude Code <noreply@anthropic.com>
The editor's AI mode showed a fixed three-step picture and a proposal that only reached the canvas after "Apply". It now runs the same two steps as creating an agent — a setup step, then a conversation with the live draft beside it — and no submission budget in either step. - `authoring-protocol.ts` owns the whole wire contract: the first-line envelope prefix, alias-only agent and approver references (rewritten recursively through loops and subgraphs, so no UUID ever leaves the client), the 40-agent / 12-skill directory cap, and the `<graph_draft>` block parser with its control-character repair retry. `escapeJsonStringControlCharacters` moves to a shared `model-json.ts` so the agent builder and this protocol do not each carry a copy. - `mergeGraphDraft` reports `unparsable`, `invalid`, `unknown_alias` or `too_large` and merges nothing on any of them, so a bad reply leaves the canvas on its last good version and says why. `stripGraphDraft` is wired into the message list's `transformContent` — without it a half-written block streams into the transcript. - `graph-ai-workspace.tsx` is the conversation on the left and a read-only canvas on the right, with undo, "Open the editor", and an exit that deletes the conversation and keeps the draft. A reply merges as soon as it lands, is not judged while it is still streaming, and records `appliedMessageId` so reopening the editor does not merge the same reply twice. - The session binding is part of the draft document (`ai` in the persisted payload, every field validated or dropped whole) rather than the URL: `packages/views` may not import a router, and this draft already survives a reload keyed by user, workspace and graph. - `graphGenerationMode` reads `builder_enabled` before `enabled`, so an older server falls back to the one-shot form while a newer one is never asked for the removed `/api/graphs/generations`. The one-shot composer, its proposal and its apply/discard pair stay for that fallback, and the mobile fallback object is renamed to match. Co-Authored-By: Claude Code <noreply@anthropic.com>
The design note still described the proposal that this change replaces, and still quoted a submission budget that no longer exists anywhere. It is now the design note for what shipped: the carrier agent and its session, the envelope and the `<graph_draft>` block, the two-step interaction, why the session id lives in the draft document, why a reply merges on arrival, and exactly which files the change deletes. Its D1-D8 deviation list stays as the record of why the rework happened. The delivery doc's AI row, workflow step and failure paragraph now describe a conversation with no turn limit; the migration line moves to 375, which drops `graph_generation`. The 2026-10-14 acceptance section recorded a pipeline that no longer exists, so it now opens with that fact and separates what still holds (no server model, per-node agents, aliases only, refused out-of-scope aliases) from what the deletion made moot, with the raw evidence kept below. A new section states plainly that the conversation flow has automated cover but has not been walked through on a machine with a live daemon. The 2026-10-14 plan is deleted; its content is either shipped or superseded by the design note. Co-Authored-By: Claude Code <noreply@anthropic.com>
… command The skill still told an agent that a Graph design request arrives as a task that hands a draft in with `multica graph draft context|submit`, and that a rejected draft spends one of four submissions. Neither command exists now, and the budget is gone, so the section describes the conversation that replaced them: the request runs on the default executor's runtime, the agent answers in the chat like any other task, and a reply may end with one `<graph_draft>` block that the page merges as it arrives. Nothing is saved, published or run by the conversation, and there is no limit on turns. `builtin_skills_test.go` pinned the deleted strings, so its anchors move to the new claims — including a `mustNotContain` on `multica graph draft`, which keeps the command from reappearing in the text by accident. The source map loses its `graph_authoring*`, `graph_generation.go` and draft-command entries, gains `graph_builder.go`, `authoring-protocol.ts` and the workspace components, and its verification greps now point at what exists. Co-Authored-By: Claude Code <noreply@anthropic.com>
`archiveAfterCreate` was never callable: the conversation is archived when a brand-new graph is saved, and by then the user has left AI mode and the workspace that owns the hook has unmounted. The editor archives the session itself, reading `draft.ai.sessionId` before `saved()` clears the document it came from, so the helper was a second copy of that behaviour with no caller. Co-Authored-By: Claude Code <noreply@anthropic.com>
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.
Graph creation now runs in a conversation backed by runtime agents. Drafts follow the conversation, actor aliases stay stable when a selected agent becomes unavailable, and node results are surfaced in issue comments and run views.
New Agent nodes default to 16 attempts and a 21600-second timeout; both fixed upper bounds are removed from definition validation and execution admission. New loops default to 16 iterations across shared and mobile editors and AI authoring prompts.
The unreleased graph-generation teardown is split into standalone concurrent-index migrations 377–378 followed by table removal at 379, with rollback cleanup hooks and matching integration fixtures. Production main currently precedes these migrations; developer databases that already applied the former 375 may retain its old tracking entry.
Validation:
Release target: v0.1.5 from the merged main commit. Tag-triggered Release publishes the CLI release and Docker images and deploys production.