mirror of
https://github.com/vectorize-io/hindsight.git
synced 2026-09-14 19:31:49 +08:00
280f098202
Makes images and files first-class raw content in `retain`. `content` accepts an ordered list of text/image/file blocks, the extractor reads each attachment in the position it occupies, and every read surface hands back the attachments behind what it returns. A plain string behaves exactly as before — text-only retain is byte-identical, because everything new sits behind an ATTACHMENTS block that is empty when a chunk carries none. Blocks are flattened at the API boundary into one canonical body with atomic placeholders, so `documents.original_text` stays plain text and content_hash idempotency, `update_mode=append`, chunk-delta re-extraction and `reprocess_document` keep working untouched. Bytes live in the existing FileStorage abstraction, content-addressed by sha256. Schema (one migration, both dialects): `attachments` for the blob, `document_attachments` for which documents reference it, and `memory_units.attachment_ids` for which attachments a *fact* came from — a column rather than a third table, because those ids behave exactly like `tags`. Provenance is per fact, not per chunk. Extraction runs one call per chunk, and a chunk holding a screenshot also holds the prose around it, so a chunk-level edge cited the diagram as evidence for the paragraph that never mentioned it. The extractor is asked instead, and a fact stated in the prose carries nothing. Extraction quality was measured against a real image-QA dataset with a raw-VLM ceiling arm before merging: transcribing structured attachments rather than summarizing them, and recording how each value is drawn, took the gap between "the model can read this off the image" and "memory can answer it" from 31.3% to 10.0% on the same 40 charts. The prose-article benchmark went 75% -> 100% over the same change, so it is not chart-specific tuning. Also here: * A vision slot (`HINDSIGHT_API_VLM_*`) so attachment-bearing chunks alone use a vision model and text-only chunks stay on a cheaper retain LLM. A vision call deliberately does not fail over to the retain chain's text models — that would reintroduce the silent omission the 422 gate exists to prevent. * The extension retain hook can now see each attachment (media type, size, kind, filename) and refusing a retain reclaims its bytes, which previously stayed fetchable forever. * A filename lives on the document edge, not the blob: the same PDF can be attached under a different name elsewhere, and content-addressing made the first name win for both. Known limitations, documented rather than hidden: store-owned memory backends get nothing (that retain path is Postgres-free and pre-dates this work), very dense pages are sampled rather than exhausted, and the Python client's ContentBlock is a plain dict where TypeScript gets the real union. Breaking for Go and Rust callers: `content` is now a union, so a bare string no longer satisfies it. Go gains a `TextContent()` helper; Rust uses `Content::Variant0(...)`.
1272 lines
37 KiB
JSON
1272 lines
37 KiB
JSON
{
|
|
"$defs": {
|
|
"BankTemplateConfig": {
|
|
"description": "Bank configuration fields within a template manifest.\n\nOnly includes configurable (per-bank) fields. Credential fields\n(API keys, base URLs) are intentionally excluded for security.",
|
|
"properties": {
|
|
"reflect_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Mission/context for Reflect operations",
|
|
"title": "Reflect Mission"
|
|
},
|
|
"retain_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Steers what gets extracted during retain",
|
|
"title": "Retain Mission"
|
|
},
|
|
"retain_extraction_mode": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Fact extraction mode: 'concise' (default), 'verbose', 'custom', 'verbatim', or 'chunks'",
|
|
"title": "Retain Extraction Mode"
|
|
},
|
|
"retain_custom_instructions": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Custom extraction prompt (when mode='custom')",
|
|
"title": "Retain Custom Instructions"
|
|
},
|
|
"retain_chunk_size": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Target max characters for each content chunk",
|
|
"title": "Retain Chunk Size"
|
|
},
|
|
"retain_structured_chunk_size": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max characters for a single JSONL line or conversation turn to keep whole; defaults to retain_chunk_size when unset",
|
|
"title": "Retain Structured Chunk Size"
|
|
},
|
|
"enable_observations": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle observation consolidation",
|
|
"title": "Enable Observations"
|
|
},
|
|
"observations_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Controls what gets synthesised",
|
|
"title": "Observations Mission"
|
|
},
|
|
"enable_text_search": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle the keyword (BM25) arm during recall, leaving pure vector search",
|
|
"title": "Enable Text Search"
|
|
},
|
|
"enable_temporal_retrieval": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle the temporal arm (and its date-aware query analysis) during recall",
|
|
"title": "Enable Temporal Retrieval"
|
|
},
|
|
"enable_graph_retrieval": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle the entity/link graph arm during recall",
|
|
"title": "Enable Graph Retrieval"
|
|
},
|
|
"enable_reranking": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle cross-encoder reranking during recall",
|
|
"title": "Enable Reranking"
|
|
},
|
|
"disposition_skepticism": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Skepticism trait (1-5)",
|
|
"title": "Disposition Skepticism"
|
|
},
|
|
"disposition_literalism": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Literalism trait (1-5)",
|
|
"title": "Disposition Literalism"
|
|
},
|
|
"disposition_empathy": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Empathy trait (1-5)",
|
|
"title": "Disposition Empathy"
|
|
},
|
|
"entity_labels": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"$ref": "#/$defs/LabelGroup"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Controlled vocabulary for entity labels",
|
|
"title": "Entity Labels"
|
|
},
|
|
"entities_allow_free_form": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Allow entities outside the label vocabulary",
|
|
"title": "Entities Allow Free Form"
|
|
},
|
|
"retain_default_strategy": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Name of the default retain strategy (key into retain_strategies map)",
|
|
"title": "Retain Default Strategy"
|
|
},
|
|
"retain_strategies": {
|
|
"anyOf": [
|
|
{
|
|
"additionalProperties": true,
|
|
"type": "object"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Map of retain strategy name to per-strategy config dict",
|
|
"title": "Retain Strategies"
|
|
},
|
|
"retain_chunk_batch_size": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max chunks per streaming batch (0 disables batching)",
|
|
"title": "Retain Chunk Batch Size"
|
|
},
|
|
"retain_max_attachments_per_chunk": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Hard cap on inline images in a single extraction chunk",
|
|
"title": "Retain Max Attachments Per Chunk"
|
|
},
|
|
"mcp_enabled_tools": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "MCP tool allowlist for this bank (None = all tools)",
|
|
"title": "Mcp Enabled Tools"
|
|
},
|
|
"consolidation_llm_batch_size": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "LLM batch size for observation consolidation",
|
|
"title": "Consolidation Llm Batch Size"
|
|
},
|
|
"consolidation_source_facts_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max tokens of source facts per consolidation batch",
|
|
"title": "Consolidation Source Facts Max Tokens"
|
|
},
|
|
"consolidation_source_facts_max_tokens_per_observation": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max tokens of source facts per observation",
|
|
"title": "Consolidation Source Facts Max Tokens Per Observation"
|
|
},
|
|
"max_observations_per_scope": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max observations to retain per consolidation scope",
|
|
"title": "Max Observations Per Scope"
|
|
},
|
|
"observation_scope_limits": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"additionalProperties": true,
|
|
"type": "object"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Per-scope overrides of max_observations_per_scope: [{\"scope\": [\"run_*\", \"shared\"], \"limit\": 1}]. Each scope is a list of fnmatch tag-globs; a consolidation scope matches under exact cover (every tag matched by a glob and every glob matched by a tag). The first matching rule wins; unmatched scopes fall back to max_observations_per_scope.",
|
|
"title": "Observation Scope Limits"
|
|
},
|
|
"reflect_source_facts_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max tokens of source facts per reflect call",
|
|
"title": "Reflect Source Facts Max Tokens"
|
|
},
|
|
"mental_model_min_refresh_interval_seconds": {
|
|
"anyOf": [
|
|
{
|
|
"minimum": 0,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Minimum seconds between two automatic refreshes of the same mental model in this bank. 0 (the default) means no floor. Overridable per model via the trigger's min_refresh_interval_seconds.",
|
|
"title": "Mental Model Min Refresh Interval Seconds"
|
|
},
|
|
"llm_gemini_safety_settings": {
|
|
"anyOf": [
|
|
{
|
|
"items": {},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Per-bank Gemini/VertexAI safety filter settings",
|
|
"title": "Llm Gemini Safety Settings"
|
|
},
|
|
"recall_budget_function": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Recall budget mapping function: 'fixed' or 'adaptive'",
|
|
"title": "Recall Budget Function"
|
|
},
|
|
"recall_budget_fixed_low": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Fixed thinking_budget for budget=low (function='fixed')",
|
|
"title": "Recall Budget Fixed Low"
|
|
},
|
|
"recall_budget_fixed_mid": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Fixed thinking_budget for budget=mid (function='fixed')",
|
|
"title": "Recall Budget Fixed Mid"
|
|
},
|
|
"recall_budget_fixed_high": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Fixed thinking_budget for budget=high (function='fixed')",
|
|
"title": "Recall Budget Fixed High"
|
|
},
|
|
"recall_budget_adaptive_low": {
|
|
"anyOf": [
|
|
{
|
|
"type": "number"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Ratio of max_tokens for budget=low (function='adaptive')",
|
|
"title": "Recall Budget Adaptive Low"
|
|
},
|
|
"recall_budget_adaptive_mid": {
|
|
"anyOf": [
|
|
{
|
|
"type": "number"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Ratio of max_tokens for budget=mid (function='adaptive')",
|
|
"title": "Recall Budget Adaptive Mid"
|
|
},
|
|
"recall_budget_adaptive_high": {
|
|
"anyOf": [
|
|
{
|
|
"type": "number"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Ratio of max_tokens for budget=high (function='adaptive')",
|
|
"title": "Recall Budget Adaptive High"
|
|
},
|
|
"recall_budget_min": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Floor for the adaptive function (after clamping)",
|
|
"title": "Recall Budget Min"
|
|
},
|
|
"recall_budget_max": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Ceiling for the adaptive function (after clamping)",
|
|
"title": "Recall Budget Max"
|
|
},
|
|
"audit_log_enabled": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Enable audit logging for this bank (overrides the server default)",
|
|
"title": "Audit Log Enabled"
|
|
},
|
|
"store_document_text": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Persist raw source text (documents.original_text / chunks.chunk_text). Set false to keep only derived facts.",
|
|
"title": "Store Document Text"
|
|
},
|
|
"enable_auto_consolidation": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Automatically consolidate observations after retain",
|
|
"title": "Enable Auto Consolidation"
|
|
},
|
|
"consolidation_max_memories_per_round": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max memory units fed into a single consolidation round",
|
|
"title": "Consolidation Max Memories Per Round"
|
|
},
|
|
"consolidation_llm_parallelism": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Number of consolidation LLM batches processed concurrently",
|
|
"title": "Consolidation Llm Parallelism"
|
|
},
|
|
"recall_include_chunks": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Include raw chunks in recall results",
|
|
"title": "Recall Include Chunks"
|
|
},
|
|
"recall_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max tokens of results returned by recall",
|
|
"title": "Recall Max Tokens"
|
|
},
|
|
"recall_chunks_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max tokens of raw chunks returned by recall (when recall_include_chunks is set)",
|
|
"title": "Recall Chunks Max Tokens"
|
|
},
|
|
"memory_defense": {
|
|
"anyOf": [
|
|
{
|
|
"additionalProperties": true,
|
|
"type": "object"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Memory Defense policy for this bank (validated against the DefensePolicy schema on write)",
|
|
"title": "Memory Defense"
|
|
}
|
|
},
|
|
"title": "BankTemplateConfig",
|
|
"type": "object"
|
|
},
|
|
"BankTemplateDirective": {
|
|
"description": "A directive definition within a bank template manifest.\n\nDirectives are matched by name on re-import: existing directives\nwith the same name are updated, new ones are created.",
|
|
"properties": {
|
|
"name": {
|
|
"description": "Human-readable name for the directive (used as match key on re-import)",
|
|
"title": "Name",
|
|
"type": "string"
|
|
},
|
|
"content": {
|
|
"description": "The directive text to inject into prompts",
|
|
"title": "Content",
|
|
"type": "string"
|
|
},
|
|
"priority": {
|
|
"default": 0,
|
|
"description": "Higher priority directives are injected first",
|
|
"title": "Priority",
|
|
"type": "integer"
|
|
},
|
|
"is_active": {
|
|
"default": true,
|
|
"description": "Whether this directive is active",
|
|
"title": "Is Active",
|
|
"type": "boolean"
|
|
},
|
|
"tags": {
|
|
"default": [],
|
|
"description": "Tags for filtering",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"content"
|
|
],
|
|
"title": "BankTemplateDirective",
|
|
"type": "object"
|
|
},
|
|
"BankTemplateMentalModel": {
|
|
"description": "A mental model definition within a bank template manifest.",
|
|
"properties": {
|
|
"id": {
|
|
"description": "Unique ID for the mental model (alphanumeric lowercase with hyphens)",
|
|
"title": "Id",
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"description": "Human-readable name for the mental model",
|
|
"title": "Name",
|
|
"type": "string"
|
|
},
|
|
"source_query": {
|
|
"description": "The query to run to generate content",
|
|
"title": "Source Query",
|
|
"type": "string"
|
|
},
|
|
"tags": {
|
|
"default": [],
|
|
"description": "Tags for scoped visibility",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
},
|
|
"max_tokens": {
|
|
"default": 2048,
|
|
"description": "Maximum tokens for generated content",
|
|
"maximum": 8192,
|
|
"minimum": 256,
|
|
"title": "Max Tokens",
|
|
"type": "integer"
|
|
},
|
|
"trigger": {
|
|
"$ref": "#/$defs/MentalModelTrigger",
|
|
"default": {},
|
|
"description": "Trigger settings"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"source_query"
|
|
],
|
|
"title": "BankTemplateMentalModel",
|
|
"type": "object"
|
|
},
|
|
"LabelGroup": {
|
|
"description": "A label group (dimension) with its type and allowed values.",
|
|
"properties": {
|
|
"key": {
|
|
"title": "Key",
|
|
"type": "string"
|
|
},
|
|
"description": {
|
|
"default": "",
|
|
"title": "Description",
|
|
"type": "string"
|
|
},
|
|
"type": {
|
|
"default": "value",
|
|
"enum": [
|
|
"value",
|
|
"multi-values",
|
|
"text",
|
|
"multi-text",
|
|
"map"
|
|
],
|
|
"title": "Type",
|
|
"type": "string"
|
|
},
|
|
"optional": {
|
|
"default": true,
|
|
"title": "Optional",
|
|
"type": "boolean"
|
|
},
|
|
"tag": {
|
|
"default": false,
|
|
"title": "Tag",
|
|
"type": "boolean"
|
|
},
|
|
"values": {
|
|
"default": [],
|
|
"items": {
|
|
"$ref": "#/$defs/LabelValue"
|
|
},
|
|
"title": "Values",
|
|
"type": "array"
|
|
},
|
|
"fields": {
|
|
"additionalProperties": {
|
|
"$ref": "#/$defs/MapField"
|
|
},
|
|
"default": {},
|
|
"title": "Fields",
|
|
"type": "object"
|
|
}
|
|
},
|
|
"required": [
|
|
"key"
|
|
],
|
|
"title": "LabelGroup",
|
|
"type": "object"
|
|
},
|
|
"LabelValue": {
|
|
"description": "A single allowed value for a label group.",
|
|
"properties": {
|
|
"value": {
|
|
"title": "Value",
|
|
"type": "string"
|
|
},
|
|
"description": {
|
|
"default": "",
|
|
"title": "Description",
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"value"
|
|
],
|
|
"title": "LabelValue",
|
|
"type": "object"
|
|
},
|
|
"MapField": {
|
|
"description": "A field within a map-type entity label group. Supports recursion via type='map'.",
|
|
"properties": {
|
|
"type": {
|
|
"default": "text",
|
|
"enum": [
|
|
"text",
|
|
"multi-text",
|
|
"value",
|
|
"multi-values",
|
|
"map"
|
|
],
|
|
"title": "Type",
|
|
"type": "string"
|
|
},
|
|
"description": {
|
|
"default": "",
|
|
"title": "Description",
|
|
"type": "string"
|
|
},
|
|
"values": {
|
|
"default": [],
|
|
"items": {
|
|
"$ref": "#/$defs/LabelValue"
|
|
},
|
|
"title": "Values",
|
|
"type": "array"
|
|
},
|
|
"fields": {
|
|
"additionalProperties": {
|
|
"$ref": "#/$defs/MapField"
|
|
},
|
|
"default": {},
|
|
"title": "Fields",
|
|
"type": "object"
|
|
}
|
|
},
|
|
"title": "MapField",
|
|
"type": "object"
|
|
},
|
|
"MentalModelTrigger": {
|
|
"description": "Trigger settings for a mental model.",
|
|
"properties": {
|
|
"mode": {
|
|
"default": "full",
|
|
"description": "Refresh mode. 'full' (default) regenerates the mental model content from scratch on each refresh. 'delta' performs surgical edits against the existing content: unchanged sections are preserved byte-for-byte, stale content is removed, new content is added. If the mental model has no existing content, or if the source_query has changed since the last refresh, delta mode falls back to a full regeneration automatically.",
|
|
"enum": [
|
|
"full",
|
|
"delta"
|
|
],
|
|
"title": "Mode",
|
|
"type": "string"
|
|
},
|
|
"refresh_after_consolidation": {
|
|
"default": false,
|
|
"description": "If true, refresh this mental model after observations consolidation (real-time mode)",
|
|
"title": "Refresh After Consolidation",
|
|
"type": "boolean"
|
|
},
|
|
"refresh_cron": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Cron expression (UTC, standard 5-field syntax, e.g. '0 3 * * *' for daily at 03:00 UTC) for refreshing this mental model on a fixed schedule. Mutually exclusive with refresh_after_consolidation \u2014 a model refreshes either after consolidation or on a cron schedule, not both. A scheduled refresh only runs when the model is stale (new memories in its scope since the last refresh); if nothing changed, the tick is skipped to avoid a wasted LLM call. null = no schedule.",
|
|
"title": "Refresh Cron"
|
|
},
|
|
"min_refresh_interval_seconds": {
|
|
"anyOf": [
|
|
{
|
|
"minimum": 0,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Minimum seconds between two automatic refreshes of this mental model. A triggered refresh that arrives sooner is not dropped: it is queued and parked until the window expires, and every further trigger in the meantime folds into that one queued refresh, so a burst of retains costs one refresh instead of one per retain. Applies to both refresh_after_consolidation and refresh_cron. Explicit refreshes (API, MCP, control plane) ignore it and run immediately. 0 disables the floor for this model; null falls back to the bank/global mental_model_min_refresh_interval_seconds setting (itself 0 by default, i.e. no floor).",
|
|
"title": "Min Refresh Interval Seconds"
|
|
},
|
|
"fact_types": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"enum": [
|
|
"world",
|
|
"experience",
|
|
"observation"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Filter which fact types are retrieved during reflect. None means all types (world, experience, observation).",
|
|
"title": "Fact Types"
|
|
},
|
|
"exclude_mental_models": {
|
|
"default": false,
|
|
"description": "If true, exclude all mental models from the reflect loop (skip search_mental_models tool).",
|
|
"title": "Exclude Mental Models",
|
|
"type": "boolean"
|
|
},
|
|
"exclude_mental_model_ids": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Exclude specific mental models by ID from the reflect loop.",
|
|
"title": "Exclude Mental Model Ids"
|
|
},
|
|
"tags_match": {
|
|
"anyOf": [
|
|
{
|
|
"enum": [
|
|
"any",
|
|
"all",
|
|
"any_strict",
|
|
"all_strict",
|
|
"exact"
|
|
],
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Override how the model's tags filter memories during refresh. If not set, defaults to 'all_strict' when the model has tags (security isolation) or 'any' when the model has no tags. Under 'all_strict' a memory must carry EVERY one of the model's tags and untagged memories are excluded, which is why a model tagged with labels its memories do not carry refreshes to empty content. Set to 'all' to keep requiring the tags while including untagged memories, or to 'any' to include untagged memories alongside any single tag match.",
|
|
"title": "Tags Match"
|
|
},
|
|
"tag_groups": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Compound boolean tag expressions to use during refresh instead of the model's own tags. When set, these tag groups are passed to reflect and the model's flat tags are NOT used for filtering. Supports nested and/or/not expressions for complex tag-based scoping.",
|
|
"title": "Tag Groups"
|
|
},
|
|
"include_chunks": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Override whether the internal recall used during refresh returns raw chunk text. None means use the bank/global config default (recall_include_chunks).",
|
|
"title": "Include Chunks"
|
|
},
|
|
"recall_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Override the token budget for facts returned by the internal recall during refresh. None means use the bank/global config default (recall_max_tokens).",
|
|
"title": "Recall Max Tokens"
|
|
},
|
|
"recall_chunks_max_tokens": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Override the token budget for raw chunks returned by the internal recall during refresh. None means use the bank/global config default (recall_chunks_max_tokens).",
|
|
"title": "Recall Chunks Max Tokens"
|
|
},
|
|
"response_schema": {
|
|
"anyOf": [
|
|
{
|
|
"additionalProperties": true,
|
|
"type": "object"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Optional JSON Schema for structured output. When set, each refresh runs the same structured-output extraction as reflect's response_schema and stores the parsed result under reflect_response.structured_output alongside the markdown content.",
|
|
"title": "Response Schema"
|
|
},
|
|
"keep_trace": {
|
|
"default": false,
|
|
"description": "If true, every refresh of this mental model records how it reached its result under reflect_response.trace: the mode it ran in and why, the resolved scope and time window, how many facts retrieval returned versus how many the agent used, the tool and LLM calls, and any delta operations. Only the latest refresh's trace is kept. This is the only way to diagnose a cron- or consolidation-driven refresh after the fact, since no human sees those run. Tool outputs are reduced to result counts to keep the stored trace bounded; use LLM request tracing for raw prompts and responses.",
|
|
"title": "Keep Trace",
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"title": "MentalModelTrigger",
|
|
"type": "object"
|
|
},
|
|
"TagGroupAnd": {
|
|
"description": "Compound AND group: all child filters must match.",
|
|
"properties": {
|
|
"and": {
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"title": "And",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"and"
|
|
],
|
|
"title": "TagGroupAnd",
|
|
"type": "object"
|
|
},
|
|
"TagGroupLeaf": {
|
|
"description": "A leaf tag filter: matches memories by tag list and match mode.",
|
|
"properties": {
|
|
"tags": {
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
},
|
|
"match": {
|
|
"default": "any_strict",
|
|
"enum": [
|
|
"any",
|
|
"all",
|
|
"any_strict",
|
|
"all_strict",
|
|
"exact"
|
|
],
|
|
"title": "Match",
|
|
"type": "string"
|
|
},
|
|
"resolve": {
|
|
"default": "exact",
|
|
"enum": [
|
|
"exact",
|
|
"fuzzy"
|
|
],
|
|
"title": "Resolve",
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"tags"
|
|
],
|
|
"title": "TagGroupLeaf",
|
|
"type": "object"
|
|
},
|
|
"TagGroupNot": {
|
|
"description": "Compound NOT group: child filter must NOT match.",
|
|
"properties": {
|
|
"not": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
],
|
|
"title": "Not"
|
|
}
|
|
},
|
|
"required": [
|
|
"not"
|
|
],
|
|
"title": "TagGroupNot",
|
|
"type": "object"
|
|
},
|
|
"TagGroupOr": {
|
|
"description": "Compound OR group: at least one child filter must match.",
|
|
"properties": {
|
|
"or": {
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"title": "Or",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"or"
|
|
],
|
|
"title": "TagGroupOr",
|
|
"type": "object"
|
|
}
|
|
},
|
|
"description": "A bank template manifest for import/export.\n\nVersion field enables forward-compatible schema evolution: the API\nauto-upgrades older manifest versions to the current schema on import.",
|
|
"example": {
|
|
"bank": {
|
|
"disposition_empathy": 5,
|
|
"enable_observations": true,
|
|
"reflect_mission": "You are helping a support agent remember customer interactions.",
|
|
"retain_mission": "Extract customer issues, resolutions, and sentiment."
|
|
},
|
|
"directives": [
|
|
{
|
|
"content": "Always respond with empathy and understanding.",
|
|
"name": "Always be empathetic",
|
|
"priority": 10
|
|
}
|
|
],
|
|
"mental_models": [
|
|
{
|
|
"id": "sentiment-overview",
|
|
"name": "Customer Sentiment Overview",
|
|
"source_query": "What is the overall sentiment trend?",
|
|
"trigger": {
|
|
"refresh_after_consolidation": true
|
|
}
|
|
}
|
|
],
|
|
"version": "1"
|
|
},
|
|
"properties": {
|
|
"version": {
|
|
"description": "Manifest schema version (currently '1')",
|
|
"title": "Version",
|
|
"type": "string"
|
|
},
|
|
"bank": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/BankTemplateConfig"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Bank configuration to apply. Omit to leave config unchanged."
|
|
},
|
|
"mental_models": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"$ref": "#/$defs/BankTemplateMentalModel"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Mental models to create or update (matched by id). Omit to leave unchanged.",
|
|
"title": "Mental Models"
|
|
},
|
|
"directives": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"$ref": "#/$defs/BankTemplateDirective"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Directives to create or update (matched by name). Omit to leave unchanged.",
|
|
"title": "Directives"
|
|
}
|
|
},
|
|
"required": [
|
|
"version"
|
|
],
|
|
"title": "BankTemplateManifest",
|
|
"type": "object"
|
|
}
|