Agents

Overview

The same knowledge the menus have, as functions an agent can call.

Everything in comark-codemirror/agent is a pure function of an EditorState (or edits it through dispatch). It runs in Node as well as in the browser.

import { EditorState } from '@codemirror/state'
import { comark } from 'comark-codemirror'
import { complete, edit, llms, snapshot } from 'comark-codemirror/agent'

const state = EditorState.create({ doc, extensions: comark({ components }) })

await complete(state, pos)          // what is valid here? { context, items }
snapshot(state)                     // numbered text, outline, frontmatter, diagnostics
llms(state)                         // the syntax and components this document supports
edit(state, { target: { component: 'card', where: { title: 'B' } }, mode: 'append', content: 'More' })

"What is valid here?"

complete(state, pos, { explicit }) returns the cursor context and the items a user would see:

{
  "context": { "kind": "attr-key", "typed": "", "owner": { "type": "component", "name": "card" } },
  "items": [
    { "label": "title", "insert": "title=\"\"", "detail": "string · required", "section": "::card › props", "chain": true },
    { "label": "variant", "insert": "variant=\"\"", "detail": "\"soft\" | \"outline\"", "section": "::card › props", "chain": true }
  ]
}

An agent can ask what props a component takes, which slots exist, which frontmatter keys a binding can reach — and get exactly the manifest-backed answer.

Edits

Edits return a CodeMirror change spec, or a structured error ({ ok: false, code, message, candidates? }) — they never throw.

Function
replace(state, { search, replace, occurrence?, all? })str_replace semantics; ambiguous matches return candidates with line numbers
edit(state, { target, mode, content })replace a target, or insert before / after it, or prepend / append inside it
patch(state, diff)apply a unified diff (exact context)
setText(state, text)replace everything with the smallest single change
runCommand(state, name, params)any command; params.target selects a target first

Apply an edit with view.dispatch({ changes: edit.changes }), or let tools() do it.

Copyright © 2026