Composition examples
The same maintained guide available through berry guide examples.
Each Markdown block below is one complete source file named after the final segment of its declared name. Full names explicitly declare any namespace; directories never add one. For example, patterns/react.md declares name: patterns.react and is referenced as !ref patterns.react. These examples use unqualified names, so each filename matches the complete name. The repository witness builds this set together, checks its schemas and classification mappings, and executes its code and connection examples. These are reusable mechanisms, not extra required layers for every agent. Copy only the sources/dependencies needed for the task. These examples retain the selected model catalog's generation allowances; measure overrides against the actual workload and reasoning effort.
A finite generator accepts an object and returns structured output. output, not model.select.structured_output, selects that capability. Deliberately leave out unsupported schema annotations such as default and string length keywords. For a known array count, declare minItems and maxItems in the generating routine's output schema, with equal values for an exact count. Invalid model results then use the runtime's existing bounded correction before returning to a caller. Do not merely mention the count in description and throw later in a consumer. Dynamic or semantic constraints require explicit validation and a bounded correction composition before committing changes; never silently truncate data.
---
name: compose_note
description: Draft a note for the supplied request.
model:
select:
operation: generation
interaction: request
input:
type: object
properties:
request:
type: string
required:
- request
additionalProperties: false
output:
type: object
properties:
text:
type: string
required:
- text
additionalProperties: false
---
Write a concise note satisfying the request. Return its text in the output object.Explicit normalization and validation belong in executable behavior, not a fabricated schema keyword. The model callable receives the actual JSON object.
---
name: prepare_note
description: Validate a request and supply an explicit application default.
language: javascript
input:
type: object
properties:
request:
type: string
additionalProperties: false
output:
type: object
properties:
request:
type: string
required:
- request
additionalProperties: false
next: compose_note
---
export default function(input) {
const request = input.request ?? 'Write a welcome note.';
if (!request.trim() || Array.from(request).length > 1000) {
throw new Error('Request must contain between 1 and 1000 characters.');
}
return {request};
}A finite classifier selects a declared branch. The next.input mapping preserves the original request; omitting it would pass the decision instead.
---
name: choose_note
description: Decide whether to draft a note.
model:
select:
operation: classification
interaction: request
input:
type: object
properties:
request:
type: string
required:
- request
output:
oneOf:
- const: draft
description: The user requests a new note.
- const: skip
description: The user does not request a new note.
next:
select: $.output
cases:
draft: prepare_note
skip: null
input: $.input
---
Decide whether the request asks for a note. Return one declared alternative.Independent calls are ordinary composition. The parent waits for both results; writing the same file or State key concurrently would require serialization.
---
name: compare_notes
description: Produce two independent notes and retain both results.
language: javascript
input:
type: object
properties:
first:
type: string
second:
type: string
required:
- first
- second
tools:
- compose_note
output:
type: array
minItems: 2
maxItems: 2
items:
type: object
---
export default async function(input, tools) {
return await Promise.all([
tools.compose_note({request: input.first}),
tools.compose_note({request: input.second}),
]);
}Conversation is declared, not inferred from the name. The async child remains independent of the continuing conversation and its result returns by correlation. An admission receipt is never described as a completed draft.
---
name: note_assistant
description: Discuss notes while a requested draft is prepared.
model:
select:
operation: generation
interaction: stream
tools:
- prepare_note:
async: true
port:
input: true
output: true
limits:
messages: 1024
bytes: 1048576
pending: 16
---
Discuss the user's request. Call prepare_note for a requested draft. Acknowledge
started work and use its eventual result; do not claim a receipt is the draft.The following code constructs native media from actual bytes supplied by its caller. The outer object is application input, the inner parts envelope is the model input. A body containing JSON-looking text is not decoded into media.
---
name: describe_picture
description: Describe the supplied actual image.
model:
select:
operation: generation
interaction: request
input_modalities:
- text
- image
---
Describe only what is visible in the supplied image. State uncertainty honestly.---
name: picture_request
description: Preserve image bytes while constructing native model input.
language: javascript
input:
type: object
properties:
mimeType:
type: string
base64:
type: string
required:
- mimeType
- base64
tools:
- describe_picture
---
export default async function(input, tools) {
return await tools.describe_picture({parts: [
{text: 'Describe this image.'},
{mediaType: input.mimeType, raw: input.base64},
]});
}A resident can receive JSON without repeatedly invoking a model. receive returns a message with content. The recipient/input port owns routing; it is not a chat API.
---
name: echo_resident
description: Echo one incoming port message and finish.
language: javascript
port:
input: true
output: true
limits:
messages: 16
bytes: 65536
pending: 4
---
export default async function(input, tools, context) {
const message = await context.receive();
await context.emit(message.content);
return message.content;
}Any producer of an appropriate value can connect to load. A classifier is one example; it chooses an exact source address through !ref, not by guessing a hash.
---
name: note_guidance
description: Guidance for concise notes.
---
Keep one clear purpose and identify any requested next action.---
name: choose_guidance
description: Return the exact retained guidance through the ordinary reader.
model:
select:
operation: classification
output:
type: object
properties:
from:
const: {$ref: !ref note_guidance}
required:
- from
additionalProperties: false
next: load
---
Return the declared guidance address.A value the user marks as exact is extracted in code before any inference, so that no model rewrites it: a quoted string, or the text after "exactly:" up to the end of its sentence without the sentence's own period. Pass the extracted value to the step that applies it; let the model produce only the rest.
---
name: exact_values
description: Extract the values a request marks as exact - quoted strings and the text after "exactly:" - without the punctuation of the sentence around them.
language: javascript
input:
type: object
properties:
text:
type: string
required:
- text
additionalProperties: false
output:
type: object
properties:
quoted:
type: array
items:
type: string
exactly:
oneOf:
- type: string
- type: 'null'
required:
- quoted
- exactly
additionalProperties: false
---
export default function(input) {
const quoted = [];
for (const match of input.text.matchAll(/"([^"\n]*)"|“([^”\n]*)”/g)) quoted.push(match[1] ?? match[2]);
const marked = /\bexactly:\s*([^\n]*)/i.exec(input.text);
let exactly = null;
if (marked) {
const rest = marked[1];
const literal = /^(?:"([^"\n]*)"|“([^”\n]*)”)/.exec(rest);
if (literal) exactly = literal[1] ?? literal[2];
else {
const end = rest.search(/[.!?](\s|$)/);
exactly = (end < 0 ? rest : rest.slice(0, end)).trim() || null;
}
}
return {quoted, exactly};
}Admit an edit against the record and revision it read. The application captures
edit.id, edit.revision and edit.fields from the requested operation before
asking a model for values; the model supplies only patch. Never accept the
scope from the same generated replacement. A classifier may resolve a semantic
request into a declared edit operation before generation; ambiguous scope needs
clarification. Known exact values can fill the patch directly. This example is
a pure application function, not another State owner: the caller must validate
its field schemas, serialize admission with its existing storage transaction,
and persist the returned record and undo entry before publishing either.
---
name: scoped_edit
description: Admit a patch only for the captured record, revision and editable fields; return a new record without mutating the accepted one.
language: javascript
input:
type: object
properties:
record:
type: object
properties:
id: {type: string}
revision: {type: integer, minimum: 0}
fields: {type: object}
required: [id, revision, fields]
additionalProperties: false
edit:
type: object
properties:
id: {type: string}
revision: {type: integer, minimum: 0}
fields: {type: array, items: {type: string}}
required: [id, revision, fields]
additionalProperties: false
patch: {type: object}
required: [record, edit, patch]
additionalProperties: false
output:
type: object
properties:
id: {type: string}
revision: {type: integer, minimum: 0}
fields: {type: object}
required: [id, revision, fields]
additionalProperties: false
---
export default function ({record, edit, patch}) {
if (edit.id !== record.id || edit.revision !== record.revision) {
throw new Error('Edit is stale or addresses another record. Read the current record before proposing another edit.');
}
const allowed = new Set(edit.fields);
for (const key of Object.keys(patch)) {
if (!allowed.has(key) || !Object.hasOwn(record.fields, key)) {
throw new Error('Edit contains a field outside its captured scope: ' + key);
}
}
if (Object.keys(patch).length === 0) return record;
if (!Number.isSafeInteger(record.revision + 1)) throw new Error('Record revision is exhausted.');
return {id: record.id, revision: record.revision + 1, fields: {...record.fields, ...patch}};
}