Repository navigation
Expand file tree
/
Copy pathstorage_types.h
More file actions
213 lines (190 loc) · 9.23 KB
/
Copy pathstorage_types.h
File metadata and controls
213 lines (190 loc) · 9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
* Data types for storage operations.
*
* Separated from sqlite::Backend/StorageBackend to reduce header dependencies
* for files that only need the data structures.
*/
#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include "nlohmann_json.hpp"
namespace ragger {
using json = nlohmann::json;
/// Input for a structured (skill-shaped) decision — agent API Phase 1.
/// text + trigger are required; everything else is optional.
/// Input to store_knowledge (PHASE7): one row of knowledge(kind). Formerly
/// DecisionInput for store_structured_decision/store_insight.
struct KnowledgeInput {
std::string kind; ///< decision | insight | note (see status::kKinds)
std::string text; ///< the ruling itself
std::string trigger; ///< "Use when ..." — future-query vocabulary
std::string rationale; ///< why; alternatives rejected ("" = NULL)
std::string scope; ///< what it does NOT apply to ("" = NULL)
std::string tags; ///< comma-separated, stored verbatim
std::string status = "current"; ///< current | provisional | pending
std::optional<int> supersedes; ///< decision_id this replaces
std::string session_guid; ///< source session GUID ("" = none)
std::string model_name; ///< producing model ("" = NULL model_id)
std::string source_timestamp; ///< historical created_at ("" = now)
std::vector<int> evidence; ///< turn_summary_ids backing the row
};
/// Input to store_episode_close (db 0.17, PHASE5 B.1): one closed episode —
/// its text plus the recorded membership. span_start/span_end are epoch
/// seconds of the first/last member turn. members must be non-empty and all
/// belong to session_guid; any straggler fails the whole close.
struct EpisodeClose {
std::string text;
std::string model_name;
std::string session_guid;
int64_t span_start = 0;
int64_t span_end = 0;
std::vector<int> member_turn_summary_ids;
};
struct KnowledgeResult {
int id = 0; ///< new knowledge_id
std::string kind; ///< echoed kind of the stored row
std::optional<int> superseded; ///< knowledge_id flipped to 'superseded'
/// Flag-only hint (Phase 2 step 5): up to 3 OTHER active knowledge rows
/// (kind decision|insight) whose embedding cosine with the new row is
/// >= decision_supersede_threshold. Never a merge — the caller decides.
std::vector<std::pair<int,float>> possible_supersedes;
};
struct SearchResult {
int id;
std::string text;
float score; // raw vector cosine similarity (reported score)
json metadata;
std::string timestamp;
// Per-signal ranking breakdown, captured for RAGGER_STATS instrumentation
// so each search type's contribution can be judged (tune/keep/drop a weight).
// Each *_score is the min-max-normalized [0,1] signal value that actually
// fed the weighted blend; a value of -1 means that signal was inactive for
// this search (bm25 disabled). `blended` is the final weighted ranking
// score (vector_weight*vec + bm25_weight*bm25). phon_score is retained at
// -1 for API/stats-schema compat only -- the old independent phonetic
// signal was folded into bm25_score by TextIndex::score_query() (v0.16;
// see fts_w_metaphone).
float vec_score = -1.0f;
float bm25_score = -1.0f;
float phon_score = -1.0f;
float blended = 0.0f;
};
/// Input for storing a Level 5 RAG document chunk (lean v2 documents schema).
/// `chunk_index` of 0 means "unchunked" (single-row document). `imported_at`
/// should be the same string for every chunk of one import so they share a
/// single timestamp (issue #48); empty = backend stamps now_iso() at insert.
///
/// `title` identifies the publication, `tags` is a comma-separated subject
/// list, `year` is the publish year, `path` is the origin. Only `text` is
/// embedded — title/tags/year are grouping/priority metadata, not embedded.
struct DocumentChunk {
std::string text;
std::string path;
std::string title;
std::string tags;
int year = 0;
int chunk_index = 0;
std::string imported_at;
};
struct SearchResponse {
std::vector<SearchResult> results;
json timing;
};
/// memory_search request (agent API Phase 2). Empty vectors/strings = no filter.
struct AgentSearchQuery {
std::string query;
std::vector<std::string> layers; ///< subset of turn|turn_summary|episode|summary|document|knowledge;
/// input aliases decision|insight accepted (PHASE7) = knowledge
/// restricted to that kind; empty = all
std::vector<std::string> kinds; ///< knowledge kinds filter (decision|insight|note); empty = all;
/// unknown kind -> invalid_argument
std::string since; ///< "YYYY-MM-DD", "YYYY-MM-DD HH:MM:SS", or relative "30d"/"12h"; "" = none
std::string until; ///< same formats; "" = none
std::string status = "active"; ///< knowledge only: "active" (current+provisional) | "any" | one exact status
std::string session; ///< only this session GUID
std::string exclude_session; ///< drop this session GUID
int limit = 10;
int max_tokens = 0; ///< 0 = no budget; else stop adding results past ~max_tokens (chars/4)
};
struct AgentHit {
std::string id; ///< typed handle "<layer>:<rowid>"
std::string layer;
float score = 0;
std::string matched_by; ///< "vector" | "lexical" | "both"
std::string created; ///< local "YYYY-MM-DD HH:MM:SS"
std::string snippet; ///< first <=240 chars of text, cut at a word boundary, "…" appended if cut
json extra; ///< layer-specific: decision → {status, trigger}; summary → {level}; turn_summary → {turn_id, session}
};
/// memory_get request (agent API Phase 2). Exactly one mode per call:
/// ids (mode 1) XOR session (mode 2) — both or neither is invalid_argument.
struct AgentGetQuery {
std::vector<std::string> ids; ///< typed handles; mode 1
std::string expand = "none"; ///< none | context | sources | chain
std::string session; ///< mode 2: history range for this session GUID
int after_turn = 0; ///< mode 2: turns with turn_id > after_turn (0 = from start)
int before_turn = 0; ///< mode 2: turns with turn_id < before_turn (0 = to end)
int limit = 20; ///< mode 2 page size, clamped [1,100]
};
/// memory_timeline request (agent API Phase 4): deterministic range scan,
/// newest first, key-paginated. No embeddings involved.
struct TimelineQuery {
std::string session; ///< GUID; "" = all
std::string since, until; ///< same formats as AgentSearchQuery
std::string granularity = "episode"; ///< turn | episode | session
int limit = 20; ///< clamp [1,100]
std::string cursor; ///< opaque "<created_epoch>:<rowid>"; "" = newest first page
};
/// memory_update request (agent API Phase 4): metadata-only curation.
/// Text never changes in place — a text change is a new row with supersedes.
struct UpdateRequest {
std::string id; ///< typed handle
std::optional<std::string> status;
std::optional<std::string> tags; ///< replaces the whole tag string
std::optional<std::string> text; ///< present => always rejected
};
/// User information (extracted from sqlite::Backend for modularity)
struct UserInfo {
int id;
std::string username;
// is_admin removed — sudo is the admin gate
std::string token_hash;
};
/// A summary row returned by session-level queries (turn/episode reads).
struct SummaryRecord {
int summary_id;
std::string text;
std::string status;
std::string timestamp;
};
/// A candidate turn for similarity-based episode boundary detection.
/// Carries the raw turn embedding and turn-summary embedding alongside the
/// summary text so the caller can compute cosine similarities and split
/// into episodes without a second round-trip to the DB.
struct EpisodeCandidateTurn {
int turn_summary_id;
std::string summary_text; // L2 turn-summary text
std::string timestamp; // "%F %T" local-time string for store_episode
int64_t epoch; // created_at epoch seconds (for gap math)
std::vector<float> turn_embedding; // from turns.embedding
std::vector<float> summary_embedding;// from turn_summaries.embedding
};
/// A schema object from sqlite_master (table, index, trigger, view).
struct SchemaObject {
std::string type;
std::string name;
std::string tbl_name;
std::string sql;
};
/// A single cell in a generic table row (for export/introspection).
struct ExportCell {
enum class Type { Null, Integer, Float, Text, Blob };
Type type = Type::Null;
int64_t int_val = 0;
double float_val = 0.0;
std::string text_val;
std::vector<uint8_t> blob_val;
};
using ExportRow = std::vector<ExportCell>;
} // namespace ragger