@terreno/mcp 57.9.0 → 57.10.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/dist/docs/upgrades/57.10.1.md +54 -0
- package/dist/docs/versioned/next/README.md +1 -0
- package/dist/docs/versioned/next/explanation/README.md +4 -0
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/dist/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/dist/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/dist/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/dist/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/dist/docs/versioned/next/explanation/example-coverage.md +3 -1
- package/dist/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +29 -1
- package/dist/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/dist/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/dist/docs/versioned/next/how-to/README.md +6 -0
- package/dist/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/dist/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/dist/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/dist/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/dist/docs/versioned/next/how-to/charts-and-dashboards.md +2 -0
- package/dist/docs/versioned/next/how-to/circleci.md +5 -3
- package/dist/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/dist/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/dist/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/dist/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/dist/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/dist/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/dist/docs/versioned/next/reference/README.md +3 -0
- package/dist/docs/versioned/next/reference/admin-config.md +2 -0
- package/dist/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/dist/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/dist/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/dist/docs/versioned/next/reference/ai.md +251 -25
- package/dist/docs/versioned/next/reference/api.md +46 -0
- package/dist/docs/versioned/next/reference/blocks.md +178 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +1 -0
- package/dist/docs/versioned/next/reference/mcp-server.md +17 -0
- package/dist/docs/versioned/next/reference/test.md +11 -2
- package/dist/docs/versioned/next/reference/ui.md +325 -1
- package/dist/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/dist/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/dist/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/dist/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
- package/dist/tools.d.ts +4 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +37 -0
- package/dist/tools.js.map +1 -1
- package/package.json +3 -2
- package/src/docs/upgrades/57.10.1.md +54 -0
- package/src/docs/versioned/next/README.md +1 -0
- package/src/docs/versioned/next/explanation/README.md +4 -0
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/src/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/src/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/src/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/src/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/src/docs/versioned/next/explanation/example-coverage.md +3 -1
- package/src/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +29 -1
- package/src/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/src/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/src/docs/versioned/next/how-to/README.md +6 -0
- package/src/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/src/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/src/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/src/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/src/docs/versioned/next/how-to/charts-and-dashboards.md +2 -0
- package/src/docs/versioned/next/how-to/circleci.md +5 -3
- package/src/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/src/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/src/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/src/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/src/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/src/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/src/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/src/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/src/docs/versioned/next/reference/README.md +3 -0
- package/src/docs/versioned/next/reference/admin-config.md +2 -0
- package/src/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/src/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/src/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/src/docs/versioned/next/reference/ai.md +251 -25
- package/src/docs/versioned/next/reference/api.md +46 -0
- package/src/docs/versioned/next/reference/blocks.md +178 -0
- package/src/docs/versioned/next/reference/environment-variables.md +1 -0
- package/src/docs/versioned/next/reference/mcp-server.md +17 -0
- package/src/docs/versioned/next/reference/test.md +11 -2
- package/src/docs/versioned/next/reference/ui.md +325 -1
- package/src/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/src/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/src/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/src/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Agent UI blocks
|
|
2
|
+
|
|
3
|
+
When a chat turns UI blocks on, the assistant reply is one YAML document of Terreno
|
|
4
|
+
components, not free HTML or JSX. This page explains why the catalog is closed and why the
|
|
5
|
+
whole reply is the document. Field tables and error codes are in the
|
|
6
|
+
[reference](../reference/blocks.md). Asks, which return a typed answer to the agent, stay
|
|
7
|
+
in [Agent UI Asks](agent-ui-asks.md).
|
|
8
|
+
|
|
9
|
+
The design record is
|
|
10
|
+
[agent-ui-blocks.md](../implementationPlans/agent-ui-blocks.md). Pick executes that work as
|
|
11
|
+
Phase 5 of [Agent UI Asks](../implementationPlans/agent-ui-asks.md).
|
|
12
|
+
|
|
13
|
+
## Why a closed catalog
|
|
14
|
+
|
|
15
|
+
An agent that can emit arbitrary components can also emit styles, scripts, and layout the
|
|
16
|
+
app theme does not own. The catalog is the list of `@terreno/ui` components the chat can
|
|
17
|
+
paint: heading, text, metric, badge, divider, context, chart, table, actions, and the two
|
|
18
|
+
layout blocks `columns` and `card`. Unknown
|
|
19
|
+
keys and unknown block types fail validation, so a reply cannot smuggle a `style` object
|
|
20
|
+
or a hex color.
|
|
21
|
+
|
|
22
|
+
The same pure functions run wherever a document is checked. `parseBlocks` and
|
|
23
|
+
`validateBlocks` live in `@terreno/blocks`, which has no React and no Express. The renderer
|
|
24
|
+
and the chat route will call them; they do not grow a second grammar.
|
|
25
|
+
|
|
26
|
+
## Why the whole reply is YAML
|
|
27
|
+
|
|
28
|
+
The document is the reply. There is no prose before it and no fenced block inside
|
|
29
|
+
markdown. A leading or trailing fence is stripped so a model that adds one still parses.
|
|
30
|
+
JSON is accepted because it is a YAML 1.2 subset and is what a structured-output call
|
|
31
|
+
emits.
|
|
32
|
+
|
|
33
|
+
Key order is `v`, then `datasets`, then `blocks`. Datasets come first so a streaming
|
|
34
|
+
renderer can know the data before the first block. `parseBlocksPartial` returns the
|
|
35
|
+
top-level blocks that have already finished and marks the cut tail pending. The finished
|
|
36
|
+
document is still checked with `validateBlocks`.
|
|
37
|
+
|
|
38
|
+
Text in the same step as a tool call is not the reply, except when that text is a block document and no later step has text. An actions block that left off `id` receives one before storage, and the chat is sent the corrected document.
|
|
39
|
+
|
|
40
|
+
A reply that is not a mapping with `v` is not a document. The chat can still show it:
|
|
41
|
+
`wrapAsTextDocument` turns the raw text into one `text` block. The error
|
|
42
|
+
`NOT_A_DOCUMENT` is how the caller tells that case apart from a document that failed a
|
|
43
|
+
field check.
|
|
44
|
+
|
|
45
|
+
YAML anchors, aliases, and explicit tags are rejected. They let one node stand in for
|
|
46
|
+
another, which makes a small document able to expand in ways the limits cannot see.
|
|
47
|
+
|
|
48
|
+
## Ownership
|
|
49
|
+
|
|
50
|
+
| Layer | Owns |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `@terreno/blocks` | Schema, parse, partial parse, validate, JSON Schema, prompt section, CLI, limits, error codes |
|
|
53
|
+
| `@terreno/ui` | `BlocksView` for heading, text, metric, badge, divider, context, chart, table, actions, columns, and card. A select action changes the target chart or table dataset in that view. A segmented control starts on the option that matches that dataset. A callback stays disabled when `hostActions` is set and does not include its name. `GPTChat` `uiBlocks` renders assistant messages through `BlocksView`, including a spinner while the reply is still streaming. A `file:` image stays as alt text until `resolveImage` returns a URL. |
|
|
54
|
+
| `@terreno/ai` | When `uiBlocks` is on: the chat system prompt, the post-stream `{blocks}` check, `AIDataset` storage, and `POST /gpt/actions`. `AIService.generateBlocks` returns one validated document outside a chat turn. |
|
|
55
|
+
|
|
56
|
+
Asks use the same package under `src/asks/`. A block shows something. An ask collects an
|
|
57
|
+
answer and returns it to the agent.
|
|
58
|
+
|
|
59
|
+
A callback button is the Block Kit `block_actions` path. The document names the callback.
|
|
60
|
+
The host owns the code.
|
|
61
|
+
|
|
62
|
+
| | Block Kit | Terreno |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| Who runs the click | Slack posts `block_actions` to the app | The client posts `POST /gpt/actions` |
|
|
65
|
+
| Payload check | The app trusts the platform body | The host Zod schema runs before the handler |
|
|
66
|
+
| What comes back | `chat.update` replaces the message | `{replace, blocks}` replaces the block, or `{text}` appends a message |
|
|
67
|
+
| Time limit | The platform's request window | 10 seconds, then 504 |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# AI observability
|
|
2
|
+
|
|
3
|
+
Terreno ships Langfuse-like prompt versioning, nested traces, evaluators, datasets, experiments, and a local human review queue **inside `@terreno/ai`**, with operator UI in **`admin-frontend` only**.
|
|
4
|
+
|
|
5
|
+
## Why not Langfuse-only
|
|
6
|
+
|
|
7
|
+
Apps must iterate prompts without a required vendor account. `LangfuseApp` stays a second plugin. Traces and scores **fan out** to every registered sink (local Mongo, Langfuse, OTLP/OpenInference). Prompts, datasets, experiments, and the review queue have **one writer** each (a primary). The review queue is **local-only**.
|
|
8
|
+
|
|
9
|
+
That split is the two planes:
|
|
10
|
+
|
|
11
|
+
| Plane | Write | Admin read |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| Telemetry (traces, scores) | All sinks, best-effort | Local if the local plugin is on, else Langfuse |
|
|
14
|
+
| Control (prompts, datasets, experiments, queue) | One primary per capability | That primary |
|
|
15
|
+
|
|
16
|
+
`experiments.primary` must equal `datasets.primary`. Defaults are all `local`.
|
|
17
|
+
|
|
18
|
+
`ObservabilityApp` fails boot (constructor throws) when:
|
|
19
|
+
|
|
20
|
+
| Error | Cause |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `experiments.primary must equal datasets.primary` | Mixed dataset/experiment writers |
|
|
23
|
+
| `reviewQueue.primary must be local` | `reviewQueue` set to `langfuse` |
|
|
24
|
+
| `<capability> primary "<id>" has no plugin` | No registered plugin with that `id`, capability, and store |
|
|
25
|
+
|
|
26
|
+
Telemetry sinks still fan out even when a control primary is local-only.
|
|
27
|
+
|
|
28
|
+
Admin chrome lives in `admin-frontend`. One sidebar group **AI Observability** holds Prompts,
|
|
29
|
+
Traces, Evaluators, Datasets, Experiments, and Review (Review is omitted when the local plugin is
|
|
30
|
+
off). Existing **AI Requests** stays under **Screens**. Every observability screen shows
|
|
31
|
+
breadcrumbs `Admin / AI Observability / <Section> / <leaf>` and a status chip from
|
|
32
|
+
`GET /ai/observability/status`. Prompt detail is a hub (Overview, Versions, Traces, Experiments);
|
|
33
|
+
versions are immutable in admin (`Save as vN+1`); apps never inline the string.
|
|
34
|
+
|
|
35
|
+
## Why this shape for product work
|
|
36
|
+
|
|
37
|
+
Flourish AI features follow an 8-step loop: gold dataset → labels → prompt versions → evaluators → experiments with gates → `production` label → live traces and in-app feedback → weak traces back into the dataset.
|
|
38
|
+
|
|
39
|
+
That loop is the product requirement, not an optional dashboard. Operator steps: [Develop an AI feature](../how-to/ai-feature-development.md). Registration and env: [Observe LLM calls](../how-to/observe-llm-calls.md). Models and routes: [AI reference](../reference/ai.md). Design lock: [implementation plan](../implementationPlans/ai-observability.md).
|
|
40
|
+
|
|
41
|
+
## RBAC (domain-neutral)
|
|
42
|
+
|
|
43
|
+
Observability HTTP routes use Terreno RBAC resources (`aiPrompt`, `aiTrace`, `aiReview`,
|
|
44
|
+
`aiDataset`, `aiExperiment`, `aiEvaluator`) instead of domain-specific approval vocabulary.
|
|
45
|
+
Pass the same `accessControl` instance on `ObservabilityApp` and `AdminApp` so
|
|
46
|
+
`GET /ai/observability/status` permissions match `/admin/config` screen filtering. Admin widgets
|
|
47
|
+
hide write controls from status flags (fail closed while status is loading or errored). Seeded
|
|
48
|
+
`admin` receives every observability action; `auditor` receives `list` and
|
|
49
|
+
`read` on each observability resource through the read-only sentinel (but not `admin:access` —
|
|
50
|
+
pair auditor with a shell grant in a composed consumer role); `superadmin` receives `*`. Existing
|
|
51
|
+
customized `admin` and `auditor` roles gain only missing observability actions on re-seed. Legacy
|
|
52
|
+
`user.admin` remains a full-access fallback when RBAC is enabled. See
|
|
53
|
+
[API reference](../reference/api.md#ai-observability-rbac). The example backend registers
|
|
54
|
+
`accessControl: access` on `ObservabilityApp` and seeds optional `aiObservabilityViewer` and
|
|
55
|
+
`aiObservabilityOperator` roles (not auto-assigned) in `example-backend/src/rbacRoles.ts`.
|
|
56
|
+
|
|
57
|
+
`AIRequest` remains the cheap per-call log. Observability traces are the nested, scored, user/session/cost record used in the SOP.
|
|
58
|
+
|
|
59
|
+
## Prompt hub relationships (phase 4)
|
|
60
|
+
|
|
61
|
+
Prompts may carry an optional domain-neutral `description` (folder semantics stay consumer-defined). `GET /ai/observability/prompts/:name` composes bounded recent **traces** and **experiments** for that prompt name so the admin hub does not scan full trace or experiment lists on the client. Trace evidence is version-aware: list filters accept `prompt` plus optional `promptVersion`, and relationship trace rows include the matching `promptVersion` from `ObsTrace.prompts[]`. The same optional positive integer `promptVersion` on prompt detail filters hub traces with `$elemMatch` on `prompts` (name and version). Omit it to keep the unfiltered prompt-name match. Invalid or non-positive versions return **400**. Experiment relationships filter server-side by `promptName` on `GET /ai/observability/experiments?promptName=…` (omit or pass an empty value for no filter). The experiment list endpoint returns summary rows without per-item hydration; use experiment detail for full item results. Reading relationships uses the same `aiPrompt:read` grant as prompt detail.
|
|
62
|
+
|
|
63
|
+
## Phase 1 reference loop
|
|
64
|
+
|
|
65
|
+
The example backend always registers the local plugin. Its idempotent seed creates
|
|
66
|
+
`examples/example-summarize` with production on v1 and an experimental v2, the human
|
|
67
|
+
`correctness-human` evaluator, the automatic `schema-assert` evaluator, and a two-item
|
|
68
|
+
`example-gold` dataset. It also creates `chat-safety-synthetic`, a proofread set of
|
|
69
|
+
two-person chats for routing, toxicity, privacy, and dismissive-reply experiments.
|
|
70
|
+
This makes the review and experiment loops walkable without Langfuse:
|
|
71
|
+
resolve the production prompt → emit a trace → inspect spans and sensitive I/O → send the
|
|
72
|
+
trace to Review → record a human score.
|
|
73
|
+
|
|
74
|
+
The example frontend supplies that first step from real product usage: **Todos → Summarize**
|
|
75
|
+
calls `/ai/example-summarize`, which resolves `example-summarize` by name and `production`
|
|
76
|
+
label server-side. Prompt selection stays on the server, while the client only contributes
|
|
77
|
+
identity (`x-ai-session-id`) and, when the backend has no provider credentials, the user's own
|
|
78
|
+
key.
|
|
79
|
+
|
|
80
|
+
`AI_OBS_PRICE_MAP_JSON` belongs to deployment configuration because prices change
|
|
81
|
+
independently of prompt versions. A missing model price preserves token counts and omits
|
|
82
|
+
USD cost; it never invents `$0`.
|
|
83
|
+
|
|
84
|
+
## Phase 2 backend (evaluators, datasets, experiments)
|
|
85
|
+
|
|
86
|
+
With the local plugin registered and primaries set to `local`, the control plane now includes:
|
|
87
|
+
|
|
88
|
+
- **`llm-judge` and `json-assert` evaluators** — judges call `AIService.generateJsonObject` through a named registry prompt (`judgePromptName`); create/update rejects a judge when the prompt `outputSchema` omits a required dimension (the error names that key). `json-assert` supports path/constraint checks and a built-in mode that validates output against the prompt version `outputSchema`. Parse or generation failures record an error outcome instead of throwing to the caller. Custom creates score a full trace; generation span and dataset item targets are reserved. Seeded templates install `correctness` / `hallucination` / `helpfulness` / `toxicity` as `llm-judge`, `schema-assert` as `json-assert`, and `*-human` variants for the review queue.
|
|
89
|
+
- **Human review evaluators** — sending traces to review requires a `human` evaluator. Its dimensions become the review item's score fields and its instructions tell the reviewer how to apply them. `llm-judge` and `json-assert` evaluators run automatically and are rejected from the human queue.
|
|
90
|
+
- **Datasets** — CRUD plus item provenance (`origin`, `proofread`, `sourceTraceId`, tags, outcome class). Import accepts **JSON** (bare objects or structured rows) and **CSV** (quoted fields; `input.*` / `expectedOutput.*` column prefixes). Rows validate against the bound prompt input schema when configured. Adding from a trace copies I/O; sensitive traces always land `proofread: false`. Deleting an item never mutates the trace.
|
|
91
|
+
- **Experiments** — compare 2–3 prompt versions on a dataset with optional `modelOverride` (requires `aiServiceFactory` on `ObservabilityApp`), evaluator thresholds (defaulting to the SOP gates), **per-version gate tiles** (`gates[].version`), outlier/low-confidence item ids, and version-scoped promote (**409** when the selected version's gates fail). Unproofread items are excluded unless `includeUnproofread` is true. Local runs compile exact prompt versions and call `AIService.generateText` with compiled `prompt` + `systemPrompt` (no `promptName`/`promptLabel`). `ObservabilityApp` wires the local experiment runner from `aiService` at register time.
|
|
92
|
+
|
|
93
|
+
Operator UI for datasets and experiments ships in tasks 2.7–2.9; routes and stores are live for API clients and tests today.
|
|
94
|
+
|
|
95
|
+
## GPT tool spans and nested traces
|
|
96
|
+
|
|
97
|
+
`/gpt/prompt` streams tool rounds to the client **and** records them in observability traces. Each provider `tool-call` / `tool-result` pair becomes a `TOOL` span (input args, cleaned output, timing, `parentSpanId` on the chain root). When tools run, the exported trace uses a `CHAIN` root wrapping those `TOOL` children instead of a lone `LLM` span. Plain `AIService.generate*` calls without tool children still log a single `LLM` root.
|
|
98
|
+
|
|
99
|
+
## Admin multi-stage trace smoke test
|
|
100
|
+
|
|
101
|
+
`POST /ai/observability/traces/test-multi-stage` (admin-only) exercises a real multi-stage workflow through the configured `ObservabilityApp.aiService`: two `generateJsonObject` LLM passes (`skipTrace: true`) with named output schemas, a deterministic local `text-metrics` tool stage, then a final synthesis `generateJsonObject` call against a combining schema. System prompts live in `OBS_TEST_MULTI_STAGE_*` constants in `ai/src/service/prompts.ts` (never inline). Each LLM span records `{prompt, schemaName, outputSchema}` as input and the parsed object as output. The handler exports one parent `TraceRecord` via `ObservabilityApp.exportTrace` with child span order `LLM`, `LLM`, `TOOL`, `LLM` and returns `{traceId, output, stages}` so operators can open the persisted trace in admin. Missing `aiService` → **503**; child failure exports an error trace then propagates the error.
|