Skip to content

feat(graph): ship conversational authoring and execution defaults - #4

Merged
SeasonsChange422 merged 18 commits into
mainfrom
docs/graph-ai-authoring-runtime-agents
Oct 15, 2026
Merged

SeasonsChange422 merged 18 commits into
mainfrom
docs/graph-ai-authoring-runtime-agents

Conversation

@SeasonsChange422

Copy link
Copy Markdown
Member

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:

  • 86 core Graph tests and 82 Graph view tests passed.
  • Go graph contract tests; Graph/BuiltinSkill handler, service and daemon tests passed.
  • Full cmd/migrate and internal/migrations tests passed, including concurrent rollback guards.
  • core/views/mobile TypeScript checks passed; targeted actor-directory ESLint passed.
  • Independent pre-merge review findings resolved and rechecked.

Release target: v0.1.5 from the merged main commit. Tag-triggered Release publishes the CLI release and Docker images and deploys production.

SeasonsChange422 and others added 18 commits October 14, 2026 05:01
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>
@SeasonsChange422
SeasonsChange422 merged commit 14de8d6 into main Oct 15, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant