agentcache-core 0.9.9__py3-none-any.whl
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.
- agentcache/__init__.py +29 -0
- agentcache/app.py +312 -0
- agentcache/cli.py +346 -0
- agentcache/connect.py +724 -0
- agentcache/core/__init__.py +19 -0
- agentcache/core/audit_log.py +104 -0
- agentcache/core/config.py +51 -0
- agentcache/core/context_builder.py +209 -0
- agentcache/core/graph.py +120 -0
- agentcache/core/image_store.py +111 -0
- agentcache/core/infer.py +142 -0
- agentcache/core/kv_scopes.py +86 -0
- agentcache/core/lessons.py +242 -0
- agentcache/core/llm.py +596 -0
- agentcache/core/memory_store.py +207 -0
- agentcache/core/observation_store.py +576 -0
- agentcache/core/privacy.py +34 -0
- agentcache/core/project_profile.py +625 -0
- agentcache/core/search_service.py +444 -0
- agentcache/core/session_store.py +382 -0
- agentcache/core/slots.py +504 -0
- agentcache/db.py +359 -0
- agentcache/import_data.py +86 -0
- agentcache/legacy.py +94 -0
- agentcache/mcp_stdio.py +141 -0
- agentcache/py.typed +0 -0
- agentcache/replay_import.py +680 -0
- agentcache/routes/__init__.py +29 -0
- agentcache/routes/_deps.py +46 -0
- agentcache/routes/auth.py +68 -0
- agentcache/routes/graph.py +81 -0
- agentcache/routes/health.py +149 -0
- agentcache/routes/mcp.py +614 -0
- agentcache/routes/memories.py +116 -0
- agentcache/routes/migration.py +32 -0
- agentcache/routes/observations.py +253 -0
- agentcache/routes/search.py +80 -0
- agentcache/search.py +935 -0
- agentcache/storage/__init__.py +29 -0
- agentcache/storage/images.py +102 -0
- agentcache/storage/paths.py +116 -0
- agentcache/storage/scopes.py +9 -0
- agentcache/viewer/favicon.svg +1 -0
- agentcache/viewer/index.html +4235 -0
- agentcache/viewer_helpers.py +61 -0
- agentcache/workers.py +192 -0
- agentcache_core-0.9.9.dist-info/METADATA +194 -0
- agentcache_core-0.9.9.dist-info/RECORD +52 -0
- agentcache_core-0.9.9.dist-info/WHEEL +5 -0
- agentcache_core-0.9.9.dist-info/entry_points.txt +2 -0
- agentcache_core-0.9.9.dist-info/licenses/LICENSE +190 -0
- agentcache_core-0.9.9.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory routes blueprint.
|
|
3
|
+
|
|
4
|
+
Handles:
|
|
5
|
+
POST /agentmemory/remember
|
|
6
|
+
POST /agentmemory/agent/remember
|
|
7
|
+
GET /agentmemory/memories
|
|
8
|
+
POST /agentmemory/forget
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from flask import Blueprint, jsonify, request
|
|
12
|
+
|
|
13
|
+
from .. import legacy as functions
|
|
14
|
+
from ..core import KV
|
|
15
|
+
from ._deps import get_kv, get_observation_store
|
|
16
|
+
from .auth import require_auth
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_memories_bp(kv=None):
|
|
20
|
+
"""Blueprint factory — receives kv at registration time (falls back to get_kv())."""
|
|
21
|
+
bp = Blueprint("memories", __name__)
|
|
22
|
+
|
|
23
|
+
def _kv():
|
|
24
|
+
return kv if kv is not None else get_kv()
|
|
25
|
+
|
|
26
|
+
# ------------------------------------------------------------------
|
|
27
|
+
# POST /agentmemory/remember
|
|
28
|
+
# ------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
@bp.route("/agentcache/remember", methods=["POST"])
|
|
31
|
+
@bp.route("/agentmemory/remember", methods=["POST"])
|
|
32
|
+
@require_auth
|
|
33
|
+
def api_remember():
|
|
34
|
+
try:
|
|
35
|
+
body = request.get_json(force=True) or {}
|
|
36
|
+
res = functions.remember(_kv(), body)
|
|
37
|
+
return jsonify(res), 201
|
|
38
|
+
except Exception as e:
|
|
39
|
+
return jsonify({"error": str(e)}), 400
|
|
40
|
+
|
|
41
|
+
# ------------------------------------------------------------------
|
|
42
|
+
# POST /agentmemory/agent/remember
|
|
43
|
+
# ------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
@bp.route("/agentcache/agent/remember", methods=["POST"])
|
|
46
|
+
@bp.route("/agentmemory/agent/remember", methods=["POST"])
|
|
47
|
+
@require_auth
|
|
48
|
+
def api_agent_remember():
|
|
49
|
+
try:
|
|
50
|
+
body = request.get_json(force=True) or {}
|
|
51
|
+
content = body.get("content")
|
|
52
|
+
if not content:
|
|
53
|
+
return jsonify({"error": "content is required"}), 400
|
|
54
|
+
|
|
55
|
+
agent_id = body.get("agentId")
|
|
56
|
+
project = body.get("project")
|
|
57
|
+
mem_type = body.get("type") or "fact"
|
|
58
|
+
|
|
59
|
+
concepts = body.get("concepts") or []
|
|
60
|
+
if isinstance(concepts, str):
|
|
61
|
+
concepts = [c.strip() for c in concepts.split(",") if c.strip()]
|
|
62
|
+
|
|
63
|
+
files = body.get("files") or []
|
|
64
|
+
if isinstance(files, str):
|
|
65
|
+
files = [f.strip() for f in files.split(",") if f.strip()]
|
|
66
|
+
|
|
67
|
+
payload = {
|
|
68
|
+
"content": content,
|
|
69
|
+
"type": mem_type,
|
|
70
|
+
"concepts": concepts,
|
|
71
|
+
"files": files,
|
|
72
|
+
"project": project,
|
|
73
|
+
}
|
|
74
|
+
if agent_id:
|
|
75
|
+
payload["agentId"] = agent_id
|
|
76
|
+
|
|
77
|
+
res = functions.remember(_kv(), payload)
|
|
78
|
+
return jsonify(res), 201
|
|
79
|
+
except Exception as e:
|
|
80
|
+
return jsonify({"error": str(e)}), 400
|
|
81
|
+
|
|
82
|
+
# ------------------------------------------------------------------
|
|
83
|
+
# GET /agentmemory/memories
|
|
84
|
+
# ------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
@bp.route("/agentcache/memories", methods=["GET"])
|
|
87
|
+
@bp.route("/agentmemory/memories", methods=["GET"])
|
|
88
|
+
@require_auth
|
|
89
|
+
def api_memories_list():
|
|
90
|
+
latest_only = request.args.get("latest", "false").lower() == "true"
|
|
91
|
+
limit = int(request.args.get("limit", "500"))
|
|
92
|
+
all_mems = _kv().list(KV.memories)
|
|
93
|
+
if latest_only:
|
|
94
|
+
all_mems = [m for m in all_mems if m.get("isLatest") is not False]
|
|
95
|
+
all_mems.sort(key=lambda m: m.get("createdAt", ""), reverse=True)
|
|
96
|
+
return jsonify({"memories": all_mems[:limit], "total": len(all_mems)}), 200
|
|
97
|
+
|
|
98
|
+
# ------------------------------------------------------------------
|
|
99
|
+
# POST /agentmemory/forget
|
|
100
|
+
# ------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
@bp.route("/agentcache/forget", methods=["POST"])
|
|
103
|
+
@bp.route("/agentmemory/forget", methods=["POST"])
|
|
104
|
+
@require_auth
|
|
105
|
+
def api_forget():
|
|
106
|
+
try:
|
|
107
|
+
body = request.get_json(force=True) or {}
|
|
108
|
+
res = get_observation_store().forget(body)
|
|
109
|
+
return jsonify(res), 200
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return jsonify({"error": str(e)}), 400
|
|
112
|
+
|
|
113
|
+
return bp
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
memories_bp = create_memories_bp(None)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Migration route blueprint.
|
|
3
|
+
|
|
4
|
+
Handles:
|
|
5
|
+
POST /agentmemory/migrate
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from flask import Blueprint, jsonify, request
|
|
9
|
+
|
|
10
|
+
from .. import legacy as functions
|
|
11
|
+
from ._deps import get_kv
|
|
12
|
+
from .auth import require_auth
|
|
13
|
+
|
|
14
|
+
migration_bp = Blueprint("migration", __name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# POST /agentcache/migrate
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@migration_bp.route("/agentcache/migrate", methods=["POST"])
|
|
23
|
+
@migration_bp.route("/agentmemory/migrate", methods=["POST"])
|
|
24
|
+
@require_auth
|
|
25
|
+
def api_migrate():
|
|
26
|
+
try:
|
|
27
|
+
body = request.get_json(force=True) or {}
|
|
28
|
+
dry_run = bool(body.get("dry_run", False))
|
|
29
|
+
result = functions.migrate_sessions_to_folders(get_kv(), dry_run)
|
|
30
|
+
return jsonify(result), 200
|
|
31
|
+
except Exception as e:
|
|
32
|
+
return jsonify({"error": str(e)}), 400
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Observation routes blueprint.
|
|
3
|
+
|
|
4
|
+
Handles:
|
|
5
|
+
POST /agentcache/observe
|
|
6
|
+
POST /agentcache/agent/observe
|
|
7
|
+
GET /agentcache/folder/observations
|
|
8
|
+
GET /agentcache/folders
|
|
9
|
+
POST /agentcache/folder/dedup
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import datetime
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
from flask import Blueprint, jsonify, request
|
|
16
|
+
|
|
17
|
+
from ..core.kv_scopes import KV
|
|
18
|
+
from ..core.observation_store import ObservationStore
|
|
19
|
+
from ._deps import get_observation_store
|
|
20
|
+
from .auth import require_auth
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _datetime_now_iso() -> str:
|
|
24
|
+
return (
|
|
25
|
+
datetime.datetime.now(datetime.timezone.utc).isoformat().replace("+00:00", "Z")
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_observations_bp(
|
|
30
|
+
observation_store: Optional[ObservationStore] = None,
|
|
31
|
+
) -> Blueprint:
|
|
32
|
+
bp = Blueprint("observations", __name__)
|
|
33
|
+
|
|
34
|
+
def get_store() -> ObservationStore:
|
|
35
|
+
return (
|
|
36
|
+
observation_store
|
|
37
|
+
if observation_store is not None
|
|
38
|
+
else get_observation_store()
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def get_kv():
|
|
42
|
+
return get_store().kv
|
|
43
|
+
|
|
44
|
+
@bp.route("/agentcache/observe", methods=["POST"])
|
|
45
|
+
@bp.route("/agentmemory/observe", methods=["POST"])
|
|
46
|
+
@require_auth
|
|
47
|
+
def api_observe():
|
|
48
|
+
body = {}
|
|
49
|
+
try:
|
|
50
|
+
body = request.get_json(force=True) or {}
|
|
51
|
+
folder_path = body.get("folderPath")
|
|
52
|
+
agent_id = body.get("agentId")
|
|
53
|
+
text = body.get("text") or body.get("content") or ""
|
|
54
|
+
|
|
55
|
+
if not folder_path or not agent_id or not text:
|
|
56
|
+
return (
|
|
57
|
+
jsonify({"error": "folderPath, agentId, and text are required"}),
|
|
58
|
+
400,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
payload = {
|
|
62
|
+
"folderPath": folder_path,
|
|
63
|
+
"agentId": agent_id,
|
|
64
|
+
"text": text,
|
|
65
|
+
"timestamp": body.get("timestamp") or _datetime_now_iso(),
|
|
66
|
+
"type": body.get("type"),
|
|
67
|
+
"title": body.get("title"),
|
|
68
|
+
"concepts": body.get("concepts"),
|
|
69
|
+
"files": body.get("files"),
|
|
70
|
+
"importance": body.get("importance"),
|
|
71
|
+
}
|
|
72
|
+
res = get_store().ingest(payload)
|
|
73
|
+
return jsonify(res), 201
|
|
74
|
+
except Exception as e:
|
|
75
|
+
import traceback
|
|
76
|
+
|
|
77
|
+
tb = traceback.format_exc()
|
|
78
|
+
print(
|
|
79
|
+
f"[observe] 400 — keys={list(body.keys())} {type(e).__name__}: {e}\n{tb}"
|
|
80
|
+
)
|
|
81
|
+
return (
|
|
82
|
+
jsonify(
|
|
83
|
+
{
|
|
84
|
+
"error": str(e),
|
|
85
|
+
"detail": type(e).__name__,
|
|
86
|
+
"keys": list(body.keys()),
|
|
87
|
+
"tb": tb,
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
400,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@bp.route("/agentcache/agent/observe", methods=["POST"])
|
|
94
|
+
@bp.route("/agentmemory/agent/observe", methods=["POST"])
|
|
95
|
+
@require_auth
|
|
96
|
+
def api_agent_observe():
|
|
97
|
+
try:
|
|
98
|
+
body = request.get_json(force=True) or {}
|
|
99
|
+
folder_path = body.get("folderPath")
|
|
100
|
+
agent_id = body.get("agentId")
|
|
101
|
+
text = body.get("text") or body.get("content") or ""
|
|
102
|
+
|
|
103
|
+
if not folder_path or not agent_id or not text:
|
|
104
|
+
return (
|
|
105
|
+
jsonify({"error": "folderPath, agentId, and text are required"}),
|
|
106
|
+
400,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
timestamp = body.get("timestamp") or _datetime_now_iso()
|
|
110
|
+
|
|
111
|
+
payload = {
|
|
112
|
+
"folderPath": folder_path,
|
|
113
|
+
"agentId": agent_id,
|
|
114
|
+
"text": text,
|
|
115
|
+
"timestamp": timestamp,
|
|
116
|
+
"type": body.get("type"),
|
|
117
|
+
"title": body.get("title"),
|
|
118
|
+
"concepts": body.get("concepts"),
|
|
119
|
+
"files": body.get("files"),
|
|
120
|
+
"importance": body.get("importance"),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
res = get_store().ingest(payload)
|
|
124
|
+
return jsonify(res), 201
|
|
125
|
+
except ValueError as e:
|
|
126
|
+
print(
|
|
127
|
+
f"[agent_observe] 400 ValueError — body keys: {list(body.keys())} — {e}"
|
|
128
|
+
)
|
|
129
|
+
return jsonify({"error": str(e)}), 400
|
|
130
|
+
except Exception as e:
|
|
131
|
+
import traceback
|
|
132
|
+
|
|
133
|
+
print(
|
|
134
|
+
f"[agent_observe] 400 error — body keys: {list(body.keys())} — {type(e).__name__}: {e}"
|
|
135
|
+
)
|
|
136
|
+
print(traceback.format_exc())
|
|
137
|
+
return jsonify({"error": str(e), "detail": type(e).__name__}), 400
|
|
138
|
+
|
|
139
|
+
@bp.route("/agentcache/folders", methods=["GET"])
|
|
140
|
+
@bp.route("/agentmemory/folders", methods=["GET"])
|
|
141
|
+
@require_auth
|
|
142
|
+
def api_folders():
|
|
143
|
+
from .. import legacy
|
|
144
|
+
|
|
145
|
+
folders = sorted(
|
|
146
|
+
get_kv().list(KV.folders),
|
|
147
|
+
key=lambda x: x.get("lastUpdated", ""),
|
|
148
|
+
reverse=True,
|
|
149
|
+
)
|
|
150
|
+
if legacy.is_agent_scope_isolated():
|
|
151
|
+
aid = legacy.get_agent_id()
|
|
152
|
+
if aid:
|
|
153
|
+
folders = [f for f in folders if f.get("agentId") == aid]
|
|
154
|
+
return jsonify({"folders": folders}), 200
|
|
155
|
+
|
|
156
|
+
@bp.route("/agentcache/folder/observations", methods=["GET"])
|
|
157
|
+
@bp.route("/agentmemory/folder/observations", methods=["GET"])
|
|
158
|
+
@require_auth
|
|
159
|
+
def api_folder_observations():
|
|
160
|
+
fp = request.args.get("folderPath")
|
|
161
|
+
aid = request.args.get("agentId")
|
|
162
|
+
if not fp or not aid:
|
|
163
|
+
return jsonify({"error": "folderPath and agentId are required"}), 400
|
|
164
|
+
from .. import legacy
|
|
165
|
+
|
|
166
|
+
if legacy.is_agent_scope_isolated():
|
|
167
|
+
current_aid = legacy.get_agent_id()
|
|
168
|
+
|
|
169
|
+
if current_aid and aid != current_aid:
|
|
170
|
+
return (
|
|
171
|
+
jsonify(
|
|
172
|
+
{
|
|
173
|
+
"error": "Unauthorized: Agent scope is isolated to another agent"
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
403,
|
|
177
|
+
)
|
|
178
|
+
observations = sorted(
|
|
179
|
+
get_kv().list(KV.folder_obs(fp, aid)),
|
|
180
|
+
key=lambda x: x.get("timestamp", ""),
|
|
181
|
+
reverse=True,
|
|
182
|
+
)
|
|
183
|
+
return (
|
|
184
|
+
jsonify({"observations": observations, "folderPath": fp, "agentId": aid}),
|
|
185
|
+
200,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
@bp.route("/agentcache/session/start", methods=["POST"])
|
|
189
|
+
@bp.route("/agentmemory/session/start", methods=["POST"])
|
|
190
|
+
@require_auth
|
|
191
|
+
def api_session_start():
|
|
192
|
+
import uuid
|
|
193
|
+
|
|
194
|
+
body = request.get_json(force=True) or {}
|
|
195
|
+
session_id = body.get("sessionId") or f"compat_{uuid.uuid4().hex[:16]}"
|
|
196
|
+
return (
|
|
197
|
+
jsonify(
|
|
198
|
+
{
|
|
199
|
+
"sessionId": session_id,
|
|
200
|
+
"status": "active",
|
|
201
|
+
"message": "Session model migrated to folder-based. Use /agentmemory/agent/observe.",
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
200,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
@bp.route("/agentcache/session/end", methods=["POST"])
|
|
208
|
+
@bp.route("/agentmemory/session/end", methods=["POST"])
|
|
209
|
+
@require_auth
|
|
210
|
+
def api_session_end():
|
|
211
|
+
return (
|
|
212
|
+
jsonify({"success": True, "message": "Session model is now folder-based."}),
|
|
213
|
+
200,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
@bp.route("/agentcache/folder/dedup", methods=["POST"])
|
|
217
|
+
@bp.route("/agentmemory/folder/dedup", methods=["POST"])
|
|
218
|
+
@require_auth
|
|
219
|
+
def api_folder_dedup():
|
|
220
|
+
try:
|
|
221
|
+
body = request.get_json(force=True) or {}
|
|
222
|
+
folder_path = body.get("folderPath") or None
|
|
223
|
+
agent_id = body.get("agentId") or None
|
|
224
|
+
res = get_store().dedup(folder_path, agent_id)
|
|
225
|
+
return jsonify(res), 200
|
|
226
|
+
except Exception as e:
|
|
227
|
+
return jsonify({"error": str(e)}), 400
|
|
228
|
+
|
|
229
|
+
@bp.route("/agentcache/observations", methods=["GET"])
|
|
230
|
+
@bp.route("/agentmemory/observations", methods=["GET"])
|
|
231
|
+
@require_auth
|
|
232
|
+
def api_observations_legacy():
|
|
233
|
+
session_id = request.args.get("sessionId", "")
|
|
234
|
+
if not session_id:
|
|
235
|
+
return jsonify({"observations": [], "sessionId": ""}), 200
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
obs = sorted(
|
|
239
|
+
get_kv().list(KV.observations(session_id)),
|
|
240
|
+
key=lambda x: x.get("timestamp", ""),
|
|
241
|
+
reverse=True,
|
|
242
|
+
)
|
|
243
|
+
return jsonify({"observations": obs, "sessionId": session_id}), 200
|
|
244
|
+
except Exception as e:
|
|
245
|
+
return (
|
|
246
|
+
jsonify({"observations": [], "sessionId": session_id, "error": str(e)}),
|
|
247
|
+
200,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
return bp
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
observations_bp = create_observations_bp()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Search and timeline routes blueprint.
|
|
3
|
+
|
|
4
|
+
Handles:
|
|
5
|
+
POST /agentmemory/search
|
|
6
|
+
POST /agentmemory/timeline
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from flask import Blueprint, jsonify, request
|
|
10
|
+
|
|
11
|
+
from ._deps import get_kv, get_observation_store, get_search_service
|
|
12
|
+
from .auth import require_auth
|
|
13
|
+
|
|
14
|
+
search_bp = Blueprint("search", __name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# POST /agentcache/search
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@search_bp.route("/agentcache/search", methods=["POST"])
|
|
23
|
+
@search_bp.route("/agentmemory/search", methods=["POST"])
|
|
24
|
+
@require_auth
|
|
25
|
+
def api_search():
|
|
26
|
+
try:
|
|
27
|
+
body = request.get_json(force=True) or {}
|
|
28
|
+
query = body.get("query")
|
|
29
|
+
if not query or not query.strip():
|
|
30
|
+
return jsonify({"error": "query is required"}), 400
|
|
31
|
+
limit = body.get("limit") or 10
|
|
32
|
+
folder_path = body.get("folderPath")
|
|
33
|
+
agent_id = body.get("agentId")
|
|
34
|
+
|
|
35
|
+
search_svc = get_search_service()
|
|
36
|
+
if search_svc is not None:
|
|
37
|
+
res = search_svc.search(
|
|
38
|
+
query=query,
|
|
39
|
+
limit=limit,
|
|
40
|
+
folder_path=folder_path,
|
|
41
|
+
agent_id=agent_id,
|
|
42
|
+
kv=get_kv(),
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
res = []
|
|
46
|
+
return jsonify(res), 200
|
|
47
|
+
except Exception as e:
|
|
48
|
+
return jsonify({"error": str(e)}), 400
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
# POST /agentcache/timeline
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@search_bp.route("/agentcache/timeline", methods=["POST"])
|
|
57
|
+
@search_bp.route("/agentmemory/timeline", methods=["POST"])
|
|
58
|
+
@require_auth
|
|
59
|
+
def api_timeline():
|
|
60
|
+
try:
|
|
61
|
+
body = request.get_json(force=True) or {}
|
|
62
|
+
folder_path = body.get("folderPath")
|
|
63
|
+
agent_id = body.get("agentId")
|
|
64
|
+
limit = body.get("limit") or 100
|
|
65
|
+
before = body.get("before")
|
|
66
|
+
after = body.get("after")
|
|
67
|
+
obs_store = get_observation_store()
|
|
68
|
+
if obs_store is not None:
|
|
69
|
+
result = obs_store.timeline(
|
|
70
|
+
limit=limit,
|
|
71
|
+
folder_path=folder_path,
|
|
72
|
+
agent_id=agent_id,
|
|
73
|
+
before=before,
|
|
74
|
+
after=after,
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
result = []
|
|
78
|
+
return jsonify({"observations": result}), 200
|
|
79
|
+
except Exception as e:
|
|
80
|
+
return jsonify({"error": str(e)}), 400
|