feat(snippets): a snippet has notes; when_to_use is the situation it is ranked on (#4378)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m37s
CI & Build / Build & push image (push) Successful in 34s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m37s
CI & Build / Build & push image (push) Successful in 34s
A snippet had no field for prose, so what a session learned about one went into when_to_use — the trigger joined onto every chunk it is embedded as. A sweep found write-ups of up to 3 KB there, headings and all. - notes: stored after the code under `## Notes`, parsed back from the body, carried by every path that rebuilds it (update, merge, un-merge). A snippet with no notes composes the body it always did. - create/update_snippet (MCP) take notes and return trigger_advice when when_to_use is long, headed or multi-paragraph. Advice, not a refusal. - Tool docs, the reusing-code skill and the editor hint describe the trigger as the situation and point the explanation at notes. - Editor gains a Notes field; the detail view renders it as markdown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -65,9 +65,9 @@ async def list_snippets(
|
||||
snippet that lives in repo A and, separately, at path B in another repo is
|
||||
not returned for repo=A + path=B.
|
||||
|
||||
Returns {"snippets": [{id, title, tags, preview, usage}], "total": int}. The
|
||||
title reads "name — when to reach for it"; open one in full with
|
||||
get_snippet(id).
|
||||
Returns {"snippets": [{id, title, when_to_use, tags, preview, usage}],
|
||||
"total": int}. The title is the snippet's name and `when_to_use` says when
|
||||
to reach for it; open one in full with get_snippet(id).
|
||||
|
||||
`usage` is {surfaced_count, pull_count, last_surfaced_at, last_pulled_at}:
|
||||
how often the entry has been put in front of an agent versus actually
|
||||
@@ -109,6 +109,7 @@ async def create_snippet(
|
||||
system_ids: list[int] | None = None,
|
||||
force: bool = False,
|
||||
commit_sha: str = "",
|
||||
notes: str = "",
|
||||
) -> dict:
|
||||
"""Record a shape in the project's pattern library, so every later
|
||||
instance starts from it instead of re-deriving it.
|
||||
@@ -136,8 +137,16 @@ async def create_snippet(
|
||||
language: Language/format, e.g. "python", "vue", "sql". Becomes a tag and
|
||||
the code-fence language.
|
||||
signature: One-line signature/interface, e.g. "debounce(fn, ms) -> fn".
|
||||
when_to_use: One line on when to reach for it — this becomes part of the
|
||||
title, so it's what a recall menu shows. Keep it sharp.
|
||||
when_to_use: The situation to reach for it in — a sentence or two, e.g.
|
||||
"Debouncing a reactive input before it triggers a fetch." This is
|
||||
what the snippet is RANKED on: it is joined onto the name in every
|
||||
vector the snippet is embedded as, so each extra paragraph blurs the
|
||||
one situation it should surface for. Several distinct situations
|
||||
are fine; the explanation is not — that goes in `notes`.
|
||||
notes: Everything worth saying that is not the situation: why it is
|
||||
shaped this way, what it replaced, caveats, history. Stored after
|
||||
the code under its own heading and shown with the snippet. When a
|
||||
later session learns something about the snippet, it goes here.
|
||||
repo/path/symbol: Canonical location of the reference implementation.
|
||||
locations: Several locations at once, as [{"repo","path","symbol"}, ...],
|
||||
when you already know the thing lives in more than one place. Takes
|
||||
@@ -154,6 +163,10 @@ async def create_snippet(
|
||||
later. Optional, but pass it whenever you're recording from a
|
||||
checkout.
|
||||
|
||||
When `when_to_use` reads like a write-up — long, several paragraphs, or
|
||||
headed — the response carries `trigger_advice`: move the explanation into
|
||||
`notes` with update_snippet.
|
||||
|
||||
Returns the created snippet (including a parsed `snippet` field), OR — when a
|
||||
duplicate already exists and force is false — {"duplicate": true,
|
||||
"existing_id": ..., "message": ...} and nothing is created. When that happens
|
||||
@@ -182,7 +195,7 @@ async def create_snippet(
|
||||
body = snippets_svc.compose_body(
|
||||
code=code, language=language, signature=signature,
|
||||
when_to_use=when_to_use, repo=repo, path=path, symbol=symbol,
|
||||
locations=locations,
|
||||
locations=locations, notes=notes,
|
||||
)
|
||||
if not force:
|
||||
dup = await dedup_svc.find_duplicate_note(
|
||||
@@ -201,12 +214,15 @@ async def create_snippet(
|
||||
uid, name=name, code=code, language=language, signature=signature,
|
||||
when_to_use=when_to_use, repo=repo, path=path, symbol=symbol,
|
||||
locations=locations, tags=tags, project_id=project_id or None,
|
||||
commit_sha=commit_sha,
|
||||
commit_sha=commit_sha, notes=notes,
|
||||
)
|
||||
if system_ids:
|
||||
await systems_svc.set_record_systems(uid, note.id, system_ids)
|
||||
data = snippets_svc.snippet_to_dict(note)
|
||||
await systems_tools.attach_systems(uid, uid, data, note.id, project_id or None)
|
||||
advice = snippets_svc.trigger_advice(when_to_use)
|
||||
if advice:
|
||||
data["trigger_advice"] = advice
|
||||
return data
|
||||
|
||||
|
||||
@@ -437,6 +453,7 @@ async def update_snippet(
|
||||
project_id: int = 0,
|
||||
system_ids: list[int] | None = None,
|
||||
commit_sha: str = "",
|
||||
notes: str | None = None,
|
||||
) -> dict:
|
||||
"""Update a snippet. Only the fields you pass change.
|
||||
|
||||
@@ -446,6 +463,12 @@ async def update_snippet(
|
||||
worse than none, so correcting downward has to be possible.
|
||||
|
||||
Args:
|
||||
when_to_use: The situation to reach for it in — a sentence or two. It
|
||||
is what the snippet is ranked on, so correct it toward the
|
||||
situation; an explanation belongs in `notes`.
|
||||
notes: Replaces the free-text notes (why, history, caveats). Pass the
|
||||
whole text — read the current notes from get_snippet first when
|
||||
adding to them.
|
||||
locations: Replace the whole location set, as [{"repo","path","symbol"},
|
||||
...]. Pass [] to clear every location. The single repo/path/symbol
|
||||
args instead overlay onto the FIRST location, leaving the rest.
|
||||
@@ -476,7 +499,7 @@ async def update_snippet(
|
||||
signature=signature, when_to_use=when_to_use,
|
||||
repo=repo, path=path, symbol=symbol,
|
||||
locations=locations, tags=tags, project_id=project,
|
||||
commit_sha=commit_sha or None,
|
||||
commit_sha=commit_sha or None, notes=notes,
|
||||
)
|
||||
except PermissionError as exc:
|
||||
# Readable but not writable — surface the real reason, not "not found".
|
||||
@@ -493,6 +516,11 @@ async def update_snippet(
|
||||
await systems_tools.attach_systems(
|
||||
uid, note.user_id, data, snippet_id, note.project_id
|
||||
)
|
||||
# Advised on the trigger as it now STANDS, not only when this call set it:
|
||||
# an edit to anything else is the moment someone is already in the record.
|
||||
advice = snippets_svc.trigger_advice(data["snippet"].get("when_to_use"))
|
||||
if advice:
|
||||
data["trigger_advice"] = advice
|
||||
return data
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user