@metaobjectsdev/sdk 0.23.2 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-context/skills/metaobjects-audit/SKILL.md +20 -7
- package/agent-context/skills/metaobjects-audit/references/capability-checklist.md +65 -19
- package/agent-context/skills/metaobjects-audit/references/csharp.md +2 -1
- package/agent-context/skills/metaobjects-audit/references/java.md +3 -2
- package/agent-context/skills/metaobjects-audit/references/kotlin.md +2 -1
- package/agent-context/skills/metaobjects-audit/references/requirements.md +3 -4
- package/agent-context/skills/metaobjects-audit/references/typescript.md +1 -1
- package/agent-context/skills/metaobjects-authoring/SKILL.md +53 -10
- package/agent-context/skills/metaobjects-authoring/references/requirements.md +49 -23
- package/agent-context/skills/metaobjects-codegen/SKILL.md +4 -3
- package/agent-context/skills/metaobjects-codegen/references/csharp.md +12 -2
- package/agent-context/skills/metaobjects-codegen/references/java.md +3 -3
- package/agent-context/skills/metaobjects-codegen/references/kotlin.md +4 -4
- package/agent-context/skills/metaobjects-codegen/references/python.md +12 -2
- package/agent-context/skills/metaobjects-codegen/references/typescript.md +14 -3
- package/agent-context/skills/metaobjects-fit-assessment/SKILL.md +4 -4
- package/agent-context/skills/metaobjects-prompts/SKILL.md +53 -32
- package/agent-context/skills/metaobjects-prompts/references/csharp.md +26 -21
- package/agent-context/skills/metaobjects-prompts/references/java.md +24 -18
- package/agent-context/skills/metaobjects-prompts/references/kotlin.md +25 -20
- package/agent-context/skills/metaobjects-prompts/references/python.md +68 -26
- package/agent-context/skills/metaobjects-prompts/references/typescript.md +29 -23
- package/agent-context/skills/metaobjects-verify/references/migration.md +1 -1
- package/agent-context/skills/metaobjects-verify/references/requirements.md +36 -22
- package/agent-context/templates/always-on.md.mustache +3 -1
- package/dist/agent-docs/body.d.ts +1 -1
- package/dist/agent-docs/body.d.ts.map +1 -1
- package/dist/agent-docs/body.js +24 -2
- package/dist/agent-docs/body.js.map +1 -1
- package/dist/collection.d.ts +71 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +203 -0
- package/dist/collection.js.map +1 -0
- package/dist/config.d.ts +51 -21
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +76 -10
- package/dist/config.js.map +1 -1
- package/dist/discovery.d.ts +43 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +100 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +42 -19
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +38 -95
- package/dist/memory.js.map +1 -1
- package/dist/metadata-files.d.ts +67 -0
- package/dist/metadata-files.d.ts.map +1 -0
- package/dist/metadata-files.js +155 -0
- package/dist/metadata-files.js.map +1 -0
- package/dist/records/any.d.ts +8 -8
- package/dist/records/decision.d.ts +2 -2
- package/dist/records/glossary.d.ts +4 -4
- package/dist/records/principle.d.ts +2 -2
- package/dist/scope.d.ts +16 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +75 -0
- package/dist/scope.js.map +1 -0
- package/dist/sources.d.ts +86 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +130 -0
- package/dist/sources.js.map +1 -0
- package/package.json +2 -2
- package/src/agent-docs/body.ts +24 -2
- package/src/collection.ts +268 -0
- package/src/config.ts +80 -12
- package/src/discovery.ts +110 -0
- package/src/index.ts +26 -9
- package/src/memory.ts +65 -99
- package/src/metadata-files.ts +158 -0
- package/src/scope.ts +95 -0
- package/src/sources.ts +160 -0
|
@@ -114,9 +114,9 @@ All live in `metaobjects-codegen-kotlin` under
|
|
|
114
114
|
| `KotlinSpringControllerGenerator` | `<Entity>Controller.kt` — Spring `@RestController`, five CRUD endpoints on the cross-port REST contract, for writable entities (`source.rdb` `@kind="table"`). A TPH `@discriminator` base emits ONE controller: polymorphic `GET /<base>(+/{id})` plus a per-subtype CRUD set at `/<base>/<discriminatorValue lowercased>` — create injects the discriminator from the URL (never the body); get/update/delete are scoped to the subtype (cross-subtype → 404); the discriminator is immutable. |
|
|
115
115
|
| `KotlinRepositoryGenerator` | `<Entity>RepositoryBase.kt` — an `open class` consumer persistence seam per writable entity (the Kotlin peer of Java's `SpringRepositoryGenerator`, but with method bodies). Carries the #203 `@autoSet` CRUD stamping: `onCreate` columns stamped once at insert, `onUpdate` columns re-stamped on every write, both excluded from the caller-supplied set. |
|
|
116
116
|
| `KotlinPayloadGenerator` | `<Template>Payload.kt` — `@Serializable` payload data class from a template's `@payloadRef` |
|
|
117
|
-
| `KotlinOutputParserGenerator` | the
|
|
118
|
-
| `KotlinExtractorGenerator` | the FR-010 tolerant `extract` mapper for a `template.
|
|
119
|
-
| `KotlinOutputPromptGenerator` | the FR-010 output-format prompt fragment for a `template.
|
|
117
|
+
| `KotlinOutputParserGenerator` | the strict parser-on-receipt for a **responding `template.prompt`** — one carrying `@responseRef` (ADR-0052: INBOUND; a `template.output` emits no parser). See the prompts reference. |
|
|
118
|
+
| `KotlinExtractorGenerator` | the FR-010 tolerant `extract` mapper for a responding `template.prompt` (all-nullable mirror → strict payload) |
|
|
119
|
+
| `KotlinOutputPromptGenerator` | the FR-010 output-format prompt fragment for a responding `template.prompt` (presentation via `@promptStyle: guide`/`inline`/`exampleOnly`) |
|
|
120
120
|
| `KotlinRenderHelperGenerator` | the typed render helper for a `template.prompt` payload |
|
|
121
121
|
| `KotlinValidatorGenerator` | `MetadataStartupValidator.kt` + `ExposedTableValidator.kt` (once per project) |
|
|
122
122
|
| `KotlinSpringConfigGenerator` | `MetadataExposedConfig.kt` — `@Configuration` wiring `Database.connect()` + the startup validator (once per project) |
|
|
@@ -129,7 +129,7 @@ wrapper (same column mapping, no write path). The `CREATE VIEW` DDL is emitted b
|
|
|
129
129
|
Node `meta migrate` from the projection's `origin.*` children — `origin.passthrough`,
|
|
130
130
|
`origin.aggregate` (`@agg` `count`/`sum`/`avg`/`min`/`max`, plus the #195 `any`/`all`
|
|
131
131
|
quantifiers over a `@filter` and `collect` array-rollup with `@distinct`/`@orderBy`),
|
|
132
|
-
`origin.
|
|
132
|
+
`origin.computed` (`@expr`), `origin.first`; an object-level
|
|
133
133
|
`@filter` scopes the whole view's rows (#207 — lowers to the outer `WHERE`). Never
|
|
134
134
|
hand-author the view SQL for a shape origins can express (an unmodeled view is unmanaged
|
|
135
135
|
and drifts silently); carry a genuinely irreducible body (recursive CTE, window function,
|
|
@@ -38,6 +38,16 @@ metaobjects docs ./metadata --out ./docs # → ./docs/api/python (AGENT-API.md
|
|
|
38
38
|
`AGENT-API.md` — the exact imports, signatures, and payload field shapes for the
|
|
39
39
|
generated code. **Before calling any generated code, read `api/python/AGENT-API.md`.**
|
|
40
40
|
|
|
41
|
+
**The two `docs` positionals are NOT the same argument.** This one is the METADATA
|
|
42
|
+
directory. The Node `meta docs` positional — used by every stack, since `migrate`,
|
|
43
|
+
`verify --db` and the neutral model docs are Node-only — is the PROJECT ROOT that
|
|
44
|
+
CONTAINS the metadata. Run `meta docs` with no positional, from the project root:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
metaobjects docs ./metadata --out ./docs # Python: the METADATA dir
|
|
48
|
+
meta docs --out ./docs # Node: run from the PROJECT ROOT (no positional)
|
|
49
|
+
```
|
|
50
|
+
|
|
41
51
|
## Generators
|
|
42
52
|
|
|
43
53
|
Wire generators by their stable name (`--generators <names>`), or run the default set.
|
|
@@ -50,13 +60,13 @@ a renamed physical column).
|
|
|
50
60
|
| `entity` | one **Pydantic model** per `object.entity` / projection (the `entity-model` generator): typed fields from the metadata, nullability from `@required`, `@maxLength`/validators, enum fields → a Python `Enum`. This is the typed data model. A TPH concrete subtype (`@discriminatorValue`) pins the inherited `@discriminator` field to a `Literal[...]` so the model rejects a foreign-subtype tag. |
|
|
51
61
|
| `routes` | a **FastAPI `APIRouter`** per writable entity (`source.rdb @kind="table"`) on the cross-port REST contract (`?filter[field][op]=`, `?sort=field:asc`, `?limit`/`?offset`, `?withCount=1` envelope, 400/404 envelopes). The router declares a repository **`Protocol`** you implement and inject. A TPH `@discriminator` base emits ONE polymorphic router: `GET /<base>(+/{id})` plus a per-subtype CRUD set at `/<base>/<discriminatorValue lowercased>` — create injects the discriminator from the URL (never the body); get/update/delete scoped to the subtype (cross-subtype → 404); discriminator immutable. Its repository `Protocol` is subtype-keyed (`subtype=None` for the polymorphic base) so your implementation applies the single-table discriminator scope. |
|
|
52
62
|
| `filter-allowlist` | per-entity filter allowlist (FR-009 — the server-side field+operator allowlist the routes validate against). |
|
|
53
|
-
| `payload` / `output-parser` / `output-prompt` / `extractor` / `render-helper` / `trace-helper` | the `template.
|
|
63
|
+
| `payload` / `output-parser` / `output-prompt` / `extractor` / `render-helper` / `trace-helper` | the prompt-pillar artifacts for a **responding `template.prompt`** — one carrying `@responseRef` (ADR-0052: these tiers are INBOUND; `template.output` is outbound only and emits no parser). The payload VO, the strict parser (`<template>_response_parser`), the **output-format prompt fragment** (`<template>_response_format`; presentation via `@promptStyle: guide`/`inline`/`exampleOnly`), the tolerant `extract`, the typed render helper, and the LLM-trace helper. See the **prompts** reference. |
|
|
54
64
|
| `template` | the generic Mustache `template` primitive. |
|
|
55
65
|
|
|
56
66
|
**Projections + entity read-views.** An `object.projection` (read-only `source.rdb`
|
|
57
67
|
`@kind: view` child) gets a read-only Pydantic model from the `entity` generator; its
|
|
58
68
|
`CREATE VIEW` DDL is emitted by the Node `meta migrate` from the projection's `origin.*`
|
|
59
|
-
children (`passthrough` / `aggregate` / `
|
|
69
|
+
children (`passthrough` / `aggregate` / `computed` / `first`) — never
|
|
60
70
|
hand-write the view SQL for a shape origins can express. An `object.entity` that adds a
|
|
61
71
|
`@role: replica` `@kind: view` source alongside its writable `table` is a write-through
|
|
62
72
|
**entity read-view** (#214): the generated read model carries the derived `origin.*`
|
|
@@ -67,6 +67,17 @@ block, and the inferred types.
|
|
|
67
67
|
A second file, `.metaobjects/config.json`, holds static project state parseable by
|
|
68
68
|
non-TS tooling; `meta init` scaffolds both plus the `metaobjects/` source dir.
|
|
69
69
|
|
|
70
|
+
`sources` in that file is where the metadata lives — `metaobjects/` is only its
|
|
71
|
+
DEFAULT value, so a project can point it anywhere. **Every entry is an OBJECT, never
|
|
72
|
+
a bare string**, and it names a DIRECTORY or a file:
|
|
73
|
+
|
|
74
|
+
```jsonc
|
|
75
|
+
{ "schema_version": 1, "sources": [{ "path": "model" }, { "path": "../shared/metadata" }] }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Every command's directory argument (`meta docs <project-root>`, `--cwd`) is the
|
|
79
|
+
PROJECT ROOT that CONTAINS the metadata — never the metadata directory itself.
|
|
80
|
+
|
|
70
81
|
## The generators
|
|
71
82
|
|
|
72
83
|
From `@metaobjectsdev/codegen-ts/generators` (server-side, framework-neutral):
|
|
@@ -78,7 +89,7 @@ From `@metaobjectsdev/codegen-ts/generators` (server-side, framework-neutral):
|
|
|
78
89
|
| `routesFile()` | `<Entity>.routes.ts` — Fastify CRUD routes on the cross-port REST contract. `routesFileHono()` is the Hono/Workers variant. A TPH `@discriminator` base mounts polymorphic `GET /<base>(+/:id)` plus a per-subtype CRUD set at `<basePath>/<discriminatorValue lowercased>` — create omits the discriminator (the URL names the subtype; the runtime injects it); get/update/delete scoped to the subtype (cross-subtype → 404); discriminator immutable via the runtime `discriminator` option. |
|
|
79
90
|
| `barrel()` | `index.ts` re-exporting each `<Entity>.ts` (one-shot, not per-entity) |
|
|
80
91
|
| `promptRender()` | `render<Name>()` per `template.prompt` |
|
|
81
|
-
| `outputParser()` | `<Name>.
|
|
92
|
+
| `outputParser()` | `<Name>.response.ts` (`parse*` / `safeParse*`) per **responding `template.prompt`** — one carrying `@responseRef` (ADR-0052: this tier is INBOUND; `template.output` is outbound only and emits nothing here). Siblings: `outputPrompt()` → `<Name>.responseFormat.ts` (the FR-010 output-format fragment, presentation via `@promptStyle`), `extractor()` → `<Name>.extractor.ts` (the tolerant `extract` mapper). |
|
|
82
93
|
| `callableFile()` | `<Entity>.callable.ts` — an FR-015 `call<Entity>` wrapper for a `source.rdb` `@kind: storedProc`/`tableFunction` (args from the `@parameterRef` value object, in declaration order) |
|
|
83
94
|
|
|
84
95
|
**Projections (read-only views).** For an `object.projection` (a read-only `source.rdb`
|
|
@@ -87,8 +98,8 @@ finder (no create/update/delete). The `CREATE VIEW` DDL is generated by `meta mi
|
|
|
87
98
|
from the projection's `origin.*` children — `origin.passthrough` (a forwarded column),
|
|
88
99
|
`origin.aggregate` (`@agg` `count`/`sum`/`avg`/`min`/`max`, plus the #195 `any`/`all`
|
|
89
100
|
predicate quantifiers over a `@filter` and `collect` array-rollup with optional
|
|
90
|
-
`@distinct`/`@orderBy`; any aggregate row-scoped with `@filter`),
|
|
91
|
-
|
|
101
|
+
`@distinct`/`@orderBy`; any aggregate row-scoped with `@filter`),
|
|
102
|
+
`origin.computed` (a row-level `@expr`), `origin.first` (one related row's
|
|
92
103
|
column along `@via`/`@of`/`@orderBy`). An object-level `@filter` on the projection scopes
|
|
93
104
|
the whole view's rows (#207 — lowers to the outer `WHERE`, the metadata-managed
|
|
94
105
|
soft-delete/status view). **Never hand-write the view SQL** for a shape origins can
|
|
@@ -28,7 +28,7 @@ cite. (3) Whether anyone fills the ledger in is itself untested; advertising it
|
|
|
28
28
|
is the brochure failure this skill exists to avoid.
|
|
29
29
|
|
|
30
30
|
TRIGGER to revisit — the release carrying `requirement.*` has shipped, AND either:
|
|
31
|
-
Arm A a dogfooded project's
|
|
31
|
+
Arm A a dogfooded project's retired capabilities are shown, retrospectively,
|
|
32
32
|
to have been discoverable PRE-adoption from repo evidence at file:line standard
|
|
33
33
|
(removal commit, dead flag, do-not-reintroduce comment);
|
|
34
34
|
Arm B a team that adopted via this assessment hits a resurrection the ledger would have
|
|
@@ -267,8 +267,8 @@ signature class. Hunt all ten classes:
|
|
|
267
267
|
@agg/@of/@via`, row-scoped with `@filter`), a predicate quantifier (`origin.aggregate
|
|
268
268
|
@agg: any|all`), an array rollup (`origin.aggregate @agg: collect`), a non-aggregate
|
|
269
269
|
derived scalar (`origin.computed @expr`), an argmax-style "one related row's column"
|
|
270
|
-
pick (`origin.first @via` — covers the common `DISTINCT ON` / lateral-join shape),
|
|
271
|
-
|
|
270
|
+
pick (`origin.first @via` — covers the common `DISTINCT ON` / lateral-join shape),
|
|
271
|
+
a soft-delete/status/type row-scope (an
|
|
272
272
|
object-level `@filter` on `object.projection`), or `extends`-borrowed — and joins
|
|
273
273
|
follow declared relationships/`identity.reference` FKs. Expressible → projection
|
|
274
274
|
candidate (note: an unmodeled hand view is *unmanaged* — invisible to `verify --db`;
|
|
@@ -407,7 +407,7 @@ promising it or counting it in benefits:
|
|
|
407
407
|
- hand `COUNT/SUM` subqueries, read-model SQL → `object.projection` + `origin.passthrough`
|
|
408
408
|
/ `origin.aggregate` (`count`/`sum`/`avg`/`min`/`max`, +`@filter` for scoped
|
|
409
409
|
aggregates, +`any`/`all` predicate quantifiers, +`collect` array rollups) /
|
|
410
|
-
`origin.
|
|
410
|
+
`origin.computed` (a non-aggregate derived scalar) /
|
|
411
411
|
`origin.first` (an argmax-style "one related row's column" pick — the usual
|
|
412
412
|
`DISTINCT ON`/lateral-join case) — plus a soft-delete/status/type view via the
|
|
413
413
|
object-level `@filter` on `object.projection` instead of a hand `WHERE`.
|
|
@@ -19,10 +19,13 @@ language lives in a reference fragment (pointed to at the bottom).
|
|
|
19
19
|
A **template** is a typed pair: a logical reference to external text + a payload
|
|
20
20
|
value-object declaring exactly what data the text expects.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
|
22
|
+
A template subtype's axis is **DIRECTION** — which way the text travels, not what it
|
|
23
|
+
is about (ADR-0052).
|
|
24
|
+
|
|
25
|
+
| Subtype | Direction | Use | Extra attrs |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `template.prompt` | outbound, and optionally inbound | LLM-targeted | `@maxTokens`, `@requiredSlots`, `@requiredTags`, `@model`, `@responseRef`, `@responseFormat`, `@promptStyle` |
|
|
28
|
+
| `template.output` | outbound ONLY | email / docs / config / export | `@kind: document \| email` (default `document`), `@requiredTags`; `@kind: email` adds `@subjectRef` / `@htmlBodyRef` / `@textBodyRef` |
|
|
26
29
|
|
|
27
30
|
Both carry the generic attrs:
|
|
28
31
|
|
|
@@ -36,13 +39,22 @@ Both carry the generic attrs:
|
|
|
36
39
|
`template.output @kind: email` renders a structured `EmailDocument` (subject + HTML
|
|
37
40
|
body + optional plain-text body) instead of one string — the TS render helper emits
|
|
38
41
|
an `EmailDocument`-returning function for it (see the `render-example-email`
|
|
39
|
-
conformance fixture). `@
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
conformance fixture). `@requiredTags` names output tags the rendered text must contain
|
|
43
|
+
(`verify` checks it) on both subtypes.
|
|
44
|
+
|
|
45
|
+
**The INBOUND half belongs to `template.prompt` alone.** `@responseRef` names the
|
|
46
|
+
response shape (an `object.value` or sourceless `object.projection`, #210) a model's
|
|
47
|
+
reply is parsed into, and its PRESENCE is what asks for the whole inbound tier: the
|
|
48
|
+
response record, the response-format fragment, the parser-on-receipt and the tolerant
|
|
49
|
+
extractor. `@responseFormat` (`json` default / `xml`, ADR-0053) is the syntax of that
|
|
50
|
+
REPLY; `@promptStyle` (`guide` / `inline` / `exampleOnly`, FR-010) selects how the
|
|
51
|
+
fragment presents the shape.
|
|
52
|
+
|
|
53
|
+
> **`@format` and `@responseFormat` are different facts.** `@format` is the syntax of
|
|
54
|
+
> the BODY you render; `@responseFormat` is the syntax of the answer you expect. A
|
|
55
|
+
> plain-text prompt asking for a JSON object is the common case. Putting `@promptStyle`
|
|
56
|
+
> or `@responseFormat` on a `template.output` is a LOAD ERROR — an output renders a
|
|
57
|
+
> document and nothing reads a reply to it.
|
|
46
58
|
|
|
47
59
|
A third, structurally different subtype is also registered core vocabulary:
|
|
48
60
|
**`template.toolcall`** (`@toolName` + `@payloadRef`, ADR-0011) — a vendor-agnostic
|
|
@@ -63,7 +75,7 @@ declared `field.<subType>` + `isArray` + `@objectRef`, and a nested payload is a
|
|
|
63
75
|
declared `field.object @objectRef` to another `object.value` (`isArray: true` for a
|
|
64
76
|
list — nested targets stay value-only, loader-enforced). The caller supplies the
|
|
65
77
|
field values at render time. An `origin.*` child on a payload field is IGNORED for
|
|
66
|
-
typing — and the assembly origins (`aggregate` / `
|
|
78
|
+
typing — and the assembly origins (`aggregate` / `computed` /
|
|
67
79
|
`first`) are ILLEGAL on an `object.value` host (`ERR_SUBTYPE_RULE_VIOLATION`, #210):
|
|
68
80
|
an origin-derived payload lives on the sourceless projection, which `@payloadRef`
|
|
69
81
|
accepts. Projections generally are covered by the `metaobjects-authoring` skill and
|
|
@@ -192,33 +204,42 @@ For every template, the verify step resolves the text, parses each `{{...}}`
|
|
|
192
204
|
reference, and checks it exists on the payload VO. If the text references
|
|
193
205
|
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
|
|
194
206
|
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
|
|
195
|
-
and `template.output` nodes the same way
|
|
207
|
+
and `template.output` nodes the same way (both RENDER; only the direction of what comes
|
|
208
|
+
back differs).
|
|
209
|
+
|
|
210
|
+
## A RESPONDING `template.prompt` generates a parser-on-receipt
|
|
211
|
+
|
|
212
|
+
For every `template.prompt` declaring `@responseRef`, codegen emits a **typed parser**
|
|
213
|
+
that turns a model's reply back into that shape. It binds `@responseRef`, never
|
|
214
|
+
`@payloadRef` — `@payloadRef` types the request the prompt renders outbound, and the
|
|
215
|
+
question and the answer are usually different shapes. Each port emits the parser
|
|
216
|
+
idiomatically: a throw-on-invalid parse plus, where the language has the precedent, a
|
|
217
|
+
Result-style "safe" variant that doesn't throw.
|
|
196
218
|
|
|
197
|
-
|
|
219
|
+
**A `template.output` gets no parser, ever.** Nothing reads a reply to a document. (Before
|
|
220
|
+
ADR-0052 it did, with no format filter at all — so an `@format: markdown` document got a
|
|
221
|
+
generated `JSON.parse` over rendered prose.)
|
|
198
222
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
throw-on-invalid parse plus, where the language has the precedent, a Result-style
|
|
203
|
-
"safe" variant that doesn't throw. The parser file is a companion to the payload-VO
|
|
204
|
-
file; `verify` catches payload-VO ↔ parser drift at build time too.
|
|
223
|
+
The strict tier is JSON-only: an `@responseFormat: xml` reply gets the tolerant extract
|
|
224
|
+
and nothing strict, because strict all-or-nothing semantics layered over a REPAIRING XML
|
|
225
|
+
reader would raise or accept based on how much repair happened.
|
|
205
226
|
|
|
206
227
|
The three-step consumer pattern is identical everywhere: render the prompt → call
|
|
207
|
-
your LLM client → parse the
|
|
228
|
+
your LLM client → parse the reply with the generated parser.
|
|
208
229
|
|
|
209
|
-
## `template.
|
|
230
|
+
## A RESPONDING `template.prompt` generates the response-format fragment (FR-010)
|
|
210
231
|
|
|
211
|
-
For every
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
232
|
+
For every `template.prompt` whose `@responseRef` resolves, codegen additionally emits a
|
|
233
|
+
`render<Name>Format(...)`-shaped function backed by the render engine's output-format
|
|
234
|
+
renderer — the "produce your answer like this" instruction fragment you splice into the
|
|
235
|
+
prompt text so the model returns exactly the shape the parser above expects. The gate is
|
|
236
|
+
`@responseRef` PRESENCE, not a format value: the old `@format ∈ {json,xml}` gate read the
|
|
237
|
+
syntax of the OUTBOUND body to decide whether to instruct the model about the syntax of
|
|
238
|
+
its REPLY, so a text-bodied prompt asking for a JSON answer got no fragment at all.
|
|
239
|
+
`@responseFormat` selects which syntax the fragment teaches; the fragment and the
|
|
240
|
+
extractor agree on the same root name.
|
|
220
241
|
|
|
221
|
-
`@promptStyle` on the `template.
|
|
242
|
+
`@promptStyle` on the `template.prompt` controls the fragment's presentation
|
|
222
243
|
(default `guide`):
|
|
223
244
|
|
|
224
245
|
| `@promptStyle` | Presentation |
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# C# parser-on-receipt
|
|
2
2
|
|
|
3
|
-
For every `template.
|
|
4
|
-
**typed parser** that validates
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
For every RESPONDING `template.prompt` — one declaring `@responseRef` —
|
|
4
|
+
`MetaObjects.Codegen`'s `OutputParserGenerator` emits a **typed parser** that validates
|
|
5
|
+
a model's reply against that shape. ADR-0052: the tier binds `@responseRef`, never
|
|
6
|
+
`@payloadRef` (which types the request the prompt renders outbound), and a
|
|
7
|
+
`template.output` gets no parser at all. This is the receive side only — codegen emits
|
|
8
|
+
**no** provider/LLM-call layer; you compose the call yourself. C# names records after the
|
|
9
|
+
resolved VALUE OBJECT, so the response record simply IS that VO's record — no second
|
|
10
|
+
naming convention, and the parser and the record can't silently drift.
|
|
8
11
|
|
|
9
12
|
## Contents
|
|
10
13
|
- Wire the generator
|
|
11
14
|
- What it emits
|
|
12
|
-
- The
|
|
15
|
+
- The response-format prompt fragment (FR-010)
|
|
13
16
|
- The three-step consumer pattern
|
|
14
17
|
- Recommended LLM caller (bring-your-own)
|
|
15
18
|
- Consumer dependency
|
|
@@ -27,12 +30,14 @@ dotnet meta gen ./metadata --out ./Generated --namespace Acme.Blog
|
|
|
27
30
|
|
|
28
31
|
## What it emits
|
|
29
32
|
|
|
30
|
-
Per `template.
|
|
31
|
-
static `<
|
|
33
|
+
Per responding `template.prompt`, `dotnet meta gen` writes one
|
|
34
|
+
`<PromptName>.response.cs` with a static `<PromptName>Parser` following the .NET BCL
|
|
35
|
+
`Parse`/`TryParse` dual API. The strict tier is JSON-only — an `@responseFormat: xml`
|
|
36
|
+
reply gets the tolerant extract and neither `Parse` nor `TryParse` —
|
|
32
37
|
`Parse` throws, `TryParse` returns a bool plus an out-error:
|
|
33
38
|
|
|
34
39
|
```csharp
|
|
35
|
-
// generated <
|
|
40
|
+
// generated <PromptName>.response.cs (shape)
|
|
36
41
|
public static class NpcResponseParser
|
|
37
42
|
{
|
|
38
43
|
/// <exception cref="JsonException">malformed JSON or schema mismatch.</exception>
|
|
@@ -53,25 +58,25 @@ generator also emits a tolerant `Extract(string[, ExtractOptions])` (self-contai
|
|
|
53
58
|
components) returning an `ExtractionResult` with a nullable `<Payload>Extracted` mirror
|
|
54
59
|
— a classified per-field report rather than a throw.
|
|
55
60
|
|
|
56
|
-
## The
|
|
61
|
+
## The response-format prompt fragment (FR-010)
|
|
57
62
|
|
|
58
|
-
For every
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
`RenderFormat(
|
|
62
|
-
|
|
63
|
-
the model. It runs as part of the same `dotnet meta gen` invocation as the payload
|
|
63
|
+
For every responding `template.prompt`, `MetaObjects.Codegen`'s `OutputPromptGenerator`
|
|
64
|
+
(stable name `output-prompt-generator`) emits a `<PromptName>.responseFormat.cs`
|
|
65
|
+
declaring a static `<PromptName>ResponseFormat` class with a `RenderFormat()` /
|
|
66
|
+
`RenderFormat(PromptOverrides)` pair, backed by the render engine's
|
|
67
|
+
`OutputFormatRenderer` — the "produce your answer like this" fragment for the model. It runs as part of the same `dotnet meta gen` invocation as the payload
|
|
64
68
|
and parser generators:
|
|
65
69
|
|
|
66
70
|
```bash
|
|
67
71
|
dotnet meta gen ./metadata --out ./Generated --namespace Acme.Blog
|
|
68
72
|
```
|
|
69
73
|
|
|
70
|
-
`@promptStyle` on the `template.
|
|
71
|
-
controls the fragment's presentation; guidance is never emitted as comments. Skipped
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
`@promptStyle` on the `template.prompt` (`guide` default / `inline` / `exampleOnly`)
|
|
75
|
+
controls the fragment's presentation; guidance is never emitted as comments. Skipped for
|
|
76
|
+
`template.output` nodes and an unresolved `@responseRef` — the same skip contract as the
|
|
77
|
+
parser generator. There is NO format gate: the old `@format ∈ {json,xml}` test read the
|
|
78
|
+
syntax of the outbound body to decide whether to describe the reply. The baked spec's
|
|
79
|
+
root name is the response record's, agreeing with the parser's root.
|
|
75
80
|
|
|
76
81
|
## The three-step consumer pattern
|
|
77
82
|
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# Java parser-on-receipt
|
|
2
2
|
|
|
3
|
-
For every `template.
|
|
4
|
-
a **typed parser** that validates
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
For every RESPONDING `template.prompt` — one declaring `@responseRef` —
|
|
4
|
+
`codegen-spring`'s `SpringOutputParserGenerator` emits a **typed parser** that validates
|
|
5
|
+
a model's reply against that shape. ADR-0052: the tier binds `@responseRef`, never
|
|
6
|
+
`@payloadRef` (which types the request the prompt renders outbound), and a
|
|
7
|
+
`template.output` gets no parser at all. This is the receive side only — codegen emits
|
|
8
|
+
**no** provider/LLM-call layer; you compose the call yourself.
|
|
7
9
|
|
|
8
10
|
## Contents
|
|
9
11
|
- Wire the generator
|
|
10
12
|
- What it emits
|
|
11
|
-
- The
|
|
13
|
+
- The response-format prompt fragment (FR-010)
|
|
12
14
|
- The three-step consumer pattern
|
|
13
15
|
- Recommended LLM caller (bring-your-own)
|
|
14
16
|
- Drift gate
|
|
@@ -31,17 +33,20 @@ the payload record it parses into) to the Maven plugin's `<generators>` list:
|
|
|
31
33
|
|
|
32
34
|
## What it emits
|
|
33
35
|
|
|
34
|
-
Per `template.
|
|
35
|
-
`parse` method returning the
|
|
36
|
-
|
|
36
|
+
Per responding `template.prompt`, `mvn metaobjects:generate` writes a `<Name>Parser`
|
|
37
|
+
class with a static `parse` method returning the `<Name>Response` record — this port's
|
|
38
|
+
records are TEMPLATE-named, so a responding prompt gets a SECOND record beside
|
|
39
|
+
`<Name>Payload`. The strict path throws
|
|
40
|
+
`com.fasterxml.jackson.core.JsonProcessingException` on malformed input, and is
|
|
41
|
+
JSON-only: an `@responseFormat: xml` reply gets the tolerant extract and no `parse`:
|
|
37
42
|
|
|
38
43
|
```java
|
|
39
44
|
// generated <Name>Parser.java (shape)
|
|
40
45
|
public final class NpcResponseParser {
|
|
41
46
|
private NpcResponseParser() { } // no instances
|
|
42
47
|
|
|
43
|
-
public static
|
|
44
|
-
// Jackson-backed: validates the text against the
|
|
48
|
+
public static NpcResponseResponse parse(String text) throws JsonProcessingException {
|
|
49
|
+
// Jackson-backed: validates the text against the @responseRef record
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
```
|
|
@@ -61,10 +66,10 @@ reference) return `MetaObjectAware` instances instead, and those need
|
|
|
61
66
|
`JsonObjectWriter`/`MetaObjectSerializer` — not a bare mapper — to serialize
|
|
62
67
|
correctly (see the codegen reference's "Serializing generated objects" section).
|
|
63
68
|
|
|
64
|
-
## The
|
|
69
|
+
## The response-format prompt fragment (FR-010)
|
|
65
70
|
|
|
66
|
-
For every
|
|
67
|
-
`SpringOutputPromptGenerator` emits a `<
|
|
71
|
+
For every responding `template.prompt`, `codegen-spring`'s
|
|
72
|
+
`SpringOutputPromptGenerator` emits a `<PromptShortName>ResponseFormat` class with a
|
|
68
73
|
static `renderFormat()` / `renderFormat(PromptOverrides)` pair, backed by
|
|
69
74
|
`OutputFormatRenderer` from the `metaobjects-render` module — the "produce your
|
|
70
75
|
answer like this" fragment for the model. Wire it alongside
|
|
@@ -77,11 +82,12 @@ answer like this" fragment for the model. Wire it alongside
|
|
|
77
82
|
</generator>
|
|
78
83
|
```
|
|
79
84
|
|
|
80
|
-
`@promptStyle` on the `template.
|
|
81
|
-
controls the fragment's presentation; guidance is never emitted as comments. Skipped
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
`@promptStyle` on the `template.prompt` (`guide` default / `inline` / `exampleOnly`)
|
|
86
|
+
controls the fragment's presentation; guidance is never emitted as comments. Skipped for
|
|
87
|
+
`template.output` nodes and an unresolved `@responseRef` — the same skip contract as the
|
|
88
|
+
parser generator. There is NO format gate: the old `@format ∈ {json,xml}` test read the
|
|
89
|
+
syntax of the outbound body to decide whether to describe the reply. The `SPEC`'s root
|
|
90
|
+
name is the response record's, agreeing with the parser's extract-codegen root.
|
|
85
91
|
|
|
86
92
|
## The three-step consumer pattern
|
|
87
93
|
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# Kotlin parser-on-receipt
|
|
2
2
|
|
|
3
|
-
For every `template.
|
|
4
|
-
a **typed parser** that validates
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
For every RESPONDING `template.prompt` — one declaring `@responseRef` —
|
|
4
|
+
`codegen-kotlin`'s `KotlinOutputParserGenerator` emits a **typed parser** that validates
|
|
5
|
+
a model's reply against that shape. ADR-0052: the tier binds `@responseRef`, never
|
|
6
|
+
`@payloadRef` (which types the request the prompt renders outbound), and a
|
|
7
|
+
`template.output` gets no parser at all. This is the receive side only — codegen emits
|
|
8
|
+
**no** provider/LLM-call layer; you compose the call yourself. The data class itself comes
|
|
9
|
+
from `KotlinPayloadGenerator` (a `@Serializable data class`) — this port's classes are
|
|
10
|
+
TEMPLATE-named, so a responding prompt gets a SECOND one, `<Name>Response`, beside
|
|
11
|
+
`<Name>Payload`, and the parser and the record can't silently drift.
|
|
9
12
|
|
|
10
13
|
## Contents
|
|
11
14
|
- Wire the generators
|
|
12
15
|
- What it emits
|
|
13
|
-
- The
|
|
16
|
+
- The response-format prompt fragment (FR-010)
|
|
14
17
|
- The three-step consumer pattern
|
|
15
18
|
- Consumer dependency
|
|
16
19
|
- Recommended LLM caller (bring-your-own)
|
|
@@ -34,9 +37,10 @@ the payload it parses into) to the Maven plugin's `<generators>` list:
|
|
|
34
37
|
|
|
35
38
|
## What it emits
|
|
36
39
|
|
|
37
|
-
Per `template.
|
|
38
|
-
`object` with a dual API matching kotlinx.serialization's exception
|
|
39
|
-
Kotlin stdlib `Result<T>` convention
|
|
40
|
+
Per responding `template.prompt`, `mvn metaobjects:generate` writes a
|
|
41
|
+
`<Name>Parser.kt` `object` with a dual API matching kotlinx.serialization's exception
|
|
42
|
+
model plus the Kotlin stdlib `Result<T>` convention. The strict tier is JSON-only — an
|
|
43
|
+
`@responseFormat: xml` reply gets the tolerant extract and neither strict function:
|
|
40
44
|
|
|
41
45
|
```kotlin
|
|
42
46
|
// generated <Name>Parser.kt (shape)
|
|
@@ -44,8 +48,8 @@ object NpcResponseParser {
|
|
|
44
48
|
private val json: Json = Json { ignoreUnknownKeys = false }
|
|
45
49
|
|
|
46
50
|
/** Throws kotlinx.serialization.SerializationException on bad input. */
|
|
47
|
-
fun parseNpcResponse(text: String):
|
|
48
|
-
json.decodeFromString<
|
|
51
|
+
fun parseNpcResponse(text: String): NpcResponseResponse =
|
|
52
|
+
json.decodeFromString<NpcResponseResponse>(text)
|
|
49
53
|
|
|
50
54
|
/** Result-style — does not throw. */
|
|
51
55
|
fun safeParseNpcResponse(text: String): Result<NpcResponsePayload> =
|
|
@@ -63,10 +67,10 @@ null) and a `extractLenient(loader, text)` overload that delegates to the runtim
|
|
|
63
67
|
components. The lenient mirror type (`<Name>Extracted`) uses nullable fields per
|
|
64
68
|
the Kotlin null-safety port — a missing/malformed component is `null`, not a throw.
|
|
65
69
|
|
|
66
|
-
## The
|
|
70
|
+
## The response-format prompt fragment (FR-010)
|
|
67
71
|
|
|
68
|
-
For every
|
|
69
|
-
`KotlinOutputPromptGenerator` emits a `<
|
|
72
|
+
For every responding `template.prompt`, `codegen-kotlin`'s
|
|
73
|
+
`KotlinOutputPromptGenerator` emits a `<PromptShortName>ResponseFormat.kt` `object`
|
|
70
74
|
with `renderFormat()` / `renderFormat(overrides: PromptOverrides)`, backed by
|
|
71
75
|
`OutputFormatRenderer` from the `metaobjects-render` module — the "produce your
|
|
72
76
|
answer like this" fragment for the model. Wire it alongside
|
|
@@ -79,11 +83,12 @@ answer like this" fragment for the model. Wire it alongside
|
|
|
79
83
|
</generator>
|
|
80
84
|
```
|
|
81
85
|
|
|
82
|
-
`@promptStyle` on the `template.
|
|
83
|
-
controls the fragment's presentation; guidance is never emitted as comments. Skipped
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
`@promptStyle` on the `template.prompt` (`guide` default / `inline` / `exampleOnly`)
|
|
87
|
+
controls the fragment's presentation; guidance is never emitted as comments. Skipped for
|
|
88
|
+
`template.output` nodes and an unresolved `@responseRef` — the same skip contract as the
|
|
89
|
+
parser generator. There is NO format gate: the old `@format ∈ {json,xml}` test read the
|
|
90
|
+
syntax of the outbound body to decide whether to describe the reply. The `SPEC`'s root
|
|
91
|
+
name is the response class's, agreeing with the parser's extract-codegen root.
|
|
87
92
|
|
|
88
93
|
## The three-step consumer pattern
|
|
89
94
|
|