forked from odysseus-dev/odysseus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathodysseus-sessions
More file actions
executable file
·153 lines (123 loc) · 4.42 KB
/
Copy pathodysseus-sessions
File metadata and controls
executable file
·153 lines (123 loc) · 4.42 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
#!/usr/bin/env python3
"""odysseus-sessions — shell wrapper for chat sessions.
odysseus-sessions list [--archived] [--folder F] [--limit N]
odysseus-sessions show SESSION_ID
odysseus-sessions archive SESSION_ID
odysseus-sessions unarchive SESSION_ID
odysseus-sessions delete SESSION_ID # hard-delete (irreversible)
"""
from __future__ import annotations
import sys
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "_lib"))
from cli import quiet_logs, emit, fail, common_parser, run, REPO_ROOT as _REPO_ROOT
quiet_logs()
import argparse, json, logging, os, sys
from pathlib import Path
try:
from core.database import SessionLocal, Session as DbSession
quiet_logs()
except ModuleNotFoundError as e:
sys.stderr.write(f"error: {e}\nhint: run from repo root with venv active.\n")
sys.exit(2)
def _serialize(s: "DbSession") -> dict:
def _int_or_zero(value) -> int:
try:
return int(value or 0)
except (TypeError, ValueError):
return 0
return {
"id": s.id,
"name": s.name,
"model": s.model,
"endpoint_url": s.endpoint_url,
"owner": s.owner or "",
"folder": s.folder or "",
"archived": bool(s.archived),
"rag": bool(s.rag),
"is_important": bool(s.is_important),
"message_count": _int_or_zero(s.message_count),
"total_input_tokens": _int_or_zero(s.total_input_tokens),
"total_output_tokens": _int_or_zero(s.total_output_tokens),
"last_accessed": s.last_accessed.isoformat() if s.last_accessed else "",
"created_at": s.created_at.isoformat() if s.created_at else "",
}
def cmd_list(args):
db = SessionLocal()
try:
q = db.query(DbSession)
if not args.archived:
q = q.filter(DbSession.archived == False) # noqa: E712
elif args.archived == "only":
q = q.filter(DbSession.archived == True) # noqa: E712
if args.folder:
q = q.filter(DbSession.folder == args.folder)
q = q.order_by(DbSession.last_accessed.desc()).limit(args.limit)
emit([_serialize(s) for s in q.all()], args)
finally:
db.close()
def cmd_show(args):
db = SessionLocal()
try:
s = db.get(DbSession, args.id)
if not s:
fail(f"no session with id {args.id!r}")
emit(_serialize(s), args)
finally:
db.close()
def cmd_archive(args):
_set_archived(args, True)
def cmd_unarchive(args):
_set_archived(args, False)
def _set_archived(args, archived: bool):
db = SessionLocal()
try:
s = db.get(DbSession, args.id)
if not s:
fail(f"no session with id {args.id!r}")
s.archived = archived
db.commit()
emit({"ok": True, "id": s.id, "archived": s.archived}, args)
finally:
db.close()
def cmd_delete(args):
if not args.yes:
fail("delete is irreversible — pass --yes to confirm")
db = SessionLocal()
try:
s = db.get(DbSession, args.id)
if not s:
fail(f"no session with id {args.id!r}")
snap = _serialize(s)
db.delete(s)
db.commit()
emit({"ok": True, "deleted": snap}, args)
finally:
db.close()
def _build_parser():
common = argparse.ArgumentParser(add_help=False)
common.add_argument("--pretty", action="store_true")
p = argparse.ArgumentParser(prog="odysseus-sessions", parents=[common])
sub = p.add_subparsers(dest="cmd", required=True)
pl = sub.add_parser("list", parents=[common])
pl.add_argument("--archived", nargs="?", const=True, default=False,
help="include archived; --archived only = only archived")
pl.add_argument("--folder")
pl.add_argument("--limit", type=int, default=50)
pl.set_defaults(func=cmd_list)
psh = sub.add_parser("show", parents=[common])
psh.add_argument("id")
psh.set_defaults(func=cmd_show)
pa = sub.add_parser("archive", parents=[common])
pa.add_argument("id")
pa.set_defaults(func=cmd_archive)
pu = sub.add_parser("unarchive", parents=[common])
pu.add_argument("id")
pu.set_defaults(func=cmd_unarchive)
pd = sub.add_parser("delete", parents=[common])
pd.add_argument("id")
pd.add_argument("--yes", action="store_true", help="confirm deletion")
pd.set_defaults(func=cmd_delete)
return p
if __name__ == "__main__":
sys.exit(run(_build_parser()))