@meridiona/meridian-darwin-arm64 1.56.0 → 1.58.0
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/VERSION +1 -1
- package/bin/meridian +0 -0
- package/package.json +1 -1
- package/services/agents/run_task_linker_mlx.py +114 -12
- package/services/observability/dashboards/classifier-debug.json +17 -4
- package/services/pyproject.toml +1 -1
- package/services/tests/evals/classify_session.py +1 -1
- package/services/tests/evals/compare_pipeline.py +2 -2
- package/ui.tar.gz +0 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.58.0
|
package/bin/meridian
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meridiona/meridian-darwin-arm64",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.58.0",
|
|
4
4
|
"description": "Prebuilt Meridian app for macOS arm64 (daemon binary + dashboard + Python services). Installed via @meridiona/meridian.",
|
|
5
5
|
"homepage": "https://github.com/Meridiona/meridian",
|
|
6
6
|
"repository": {
|
|
@@ -66,6 +66,20 @@ _CONTEXT_WINDOW = 5
|
|
|
66
66
|
_MAX_TOKENS = 1024
|
|
67
67
|
_TEMPERATURE = 0.0 # greedy decoding — deterministic classification
|
|
68
68
|
|
|
69
|
+
# Candidate-set policy. When the dev has CONFIRMED a daily plan, restrict the
|
|
70
|
+
# classifier's candidate tickets to exactly those planned tickets instead of
|
|
71
|
+
# offering every open ticket (the historical "boost-never-filter" behaviour).
|
|
72
|
+
# Rationale: a focused candidate set sharpens precision on the day's declared
|
|
73
|
+
# work; off-plan work then intentionally falls through to `untracked` — a
|
|
74
|
+
# deliberate holding state — rather than being mis-linked onto an unrelated open
|
|
75
|
+
# ticket. NOTE: until a recall-recovery stage exists, `untracked` sessions do
|
|
76
|
+
# not produce PM worklogs, so off-plan work is not written back while this is on.
|
|
77
|
+
# "1" (default) → plan-only filtering whenever a plan is confirmed
|
|
78
|
+
# "0" → legacy boost-never-filter (plan tickets floated up, all kept)
|
|
79
|
+
# Read once at import — flipping it requires an MLX-server restart. Only ever
|
|
80
|
+
# active on days with a confirmed, non-empty plan; unplanned days are unaffected.
|
|
81
|
+
_PLAN_ONLY_CANDIDATES = os.environ.get("CLASSIFY_PLAN_ONLY_CANDIDATES", "1") == "1"
|
|
82
|
+
|
|
69
83
|
# The eval-tuned default classifier model. It lives in the llm_selector catalog
|
|
70
84
|
# (_MODELS) as "qwen3.5-9b-optiq"; llm_selector keeps it on machines where it
|
|
71
85
|
# fits and degrades only when Metal headroom can't accommodate it. The catalog
|
|
@@ -579,7 +593,9 @@ def _fetch_session(
|
|
|
579
593
|
row = con.execute(
|
|
580
594
|
"SELECT id, app_name, started_at, ended_at, duration_s, session_text,"
|
|
581
595
|
" session_text_source, window_titles, category, confidence,"
|
|
582
|
-
" session_summary,
|
|
596
|
+
" session_summary, coding_agent_session_uuid,"
|
|
597
|
+
" segment_started_at, sealed_at, summary_source,"
|
|
598
|
+
" min_frame_id, max_frame_id, frame_count"
|
|
583
599
|
" FROM app_sessions WHERE id = ?",
|
|
584
600
|
(session_id,),
|
|
585
601
|
).fetchone()
|
|
@@ -683,17 +699,46 @@ def _fetch_pm_tasks(
|
|
|
683
699
|
rows = con.execute(base_cols).fetchall()
|
|
684
700
|
tasks = [dict(r) for r in rows]
|
|
685
701
|
|
|
686
|
-
#
|
|
687
|
-
#
|
|
688
|
-
# BOOST, never a filter — every other candidate still follows, so recall is
|
|
689
|
-
# untouched. A focus key that isn't in `tasks` (e.g. excluded by curation)
|
|
690
|
-
# simply has no effect; we never resurrect a filtered-out ticket.
|
|
702
|
+
# Candidate-set policy (see _PLAN_ONLY_CANDIDATES). `focus_keys` are the
|
|
703
|
+
# tickets the dev CONFIRMED for this session's day (empty when no plan).
|
|
691
704
|
focus = focus_keys or []
|
|
692
|
-
if focus:
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
tasks
|
|
705
|
+
if not focus:
|
|
706
|
+
# No confirmed plan → offer every candidate. Unchanged behaviour for
|
|
707
|
+
# users who don't use the plan, or days that aren't confirmed yet.
|
|
708
|
+
# `is_today_focus` is left unset (falsy) on every ticket.
|
|
709
|
+
return tasks
|
|
710
|
+
|
|
711
|
+
order = {key: i for i, key in enumerate(focus)}
|
|
712
|
+
|
|
713
|
+
if _PLAN_ONLY_CANDIDATES:
|
|
714
|
+
# Plan-only: the candidate set IS the confirmed plan, in declared order.
|
|
715
|
+
# Off-plan work then has no candidate to match, so the model returns
|
|
716
|
+
# `untracked` (the intended holding state) instead of being shoehorned
|
|
717
|
+
# onto an unrelated ticket.
|
|
718
|
+
in_plan = [t for t in tasks if t["task_key"] in order]
|
|
719
|
+
# GUARD: never return an empty candidate set. If the confirmed plan's
|
|
720
|
+
# tickets are all absent from the live pool (curation-excluded, closed,
|
|
721
|
+
# or not yet synced), fall back to the full set — an empty list would
|
|
722
|
+
# force EVERY session that day to `untracked`.
|
|
723
|
+
if not in_plan:
|
|
724
|
+
log.warning(
|
|
725
|
+
"plan-only candidates: confirmed plan has no live candidate "
|
|
726
|
+
"tickets (focus=%s) — falling back to full candidate set",
|
|
727
|
+
focus,
|
|
728
|
+
)
|
|
729
|
+
return tasks
|
|
730
|
+
for t in in_plan:
|
|
731
|
+
t["is_today_focus"] = True
|
|
732
|
+
in_plan.sort(key=lambda t: order[t["task_key"]])
|
|
733
|
+
return in_plan
|
|
734
|
+
|
|
735
|
+
# Legacy boost-never-filter: tag the declared tickets and float them to the
|
|
736
|
+
# top in declared order, but keep every other candidate so recall is
|
|
737
|
+
# untouched. A focus key not in `tasks` (e.g. excluded by curation) simply
|
|
738
|
+
# has no effect — we never resurrect a filtered-out ticket.
|
|
739
|
+
for t in tasks:
|
|
740
|
+
t["is_today_focus"] = t["task_key"] in order
|
|
741
|
+
tasks.sort(key=lambda t: (0, order[t["task_key"]]) if t.get("is_today_focus") else (1, 0))
|
|
697
742
|
return tasks
|
|
698
743
|
|
|
699
744
|
|
|
@@ -785,7 +830,7 @@ def _classify_one(
|
|
|
785
830
|
# session_text and a concise, high-quality prose summary in
|
|
786
831
|
# session_summary. Classify on the summary, not the multi-MB transcript:
|
|
787
832
|
# cheaper, faster, and it's already the distilled "what was done".
|
|
788
|
-
if session_raw.get("
|
|
833
|
+
if session_raw.get("coding_agent_session_uuid") and (session_raw.get("session_summary") or "").strip():
|
|
789
834
|
session_text = session_raw["session_summary"]
|
|
790
835
|
|
|
791
836
|
# db_fetch is the SOLE source of "what the model was given" — recorded
|
|
@@ -796,15 +841,64 @@ def _classify_one(
|
|
|
796
841
|
# (today's-focus keys float to the front in _fetch_pm_tasks).
|
|
797
842
|
candidate_keys = [t["task_key"] for t in pm_tasks]
|
|
798
843
|
recent_task_keys = [r.get("task_key") for r in recent if r.get("task_key")]
|
|
844
|
+
# Session identity + the app_sessions row metadata, so a trace is
|
|
845
|
+
# self-contained — you know WHICH session and its key fields (app, window
|
|
846
|
+
# titles, time span) without opening meridian.db.
|
|
847
|
+
db_span.set_attribute("session_id", session_id)
|
|
799
848
|
db_span.set_attribute("app_name", str(session_raw.get("app_name") or ""))
|
|
849
|
+
db_span.set_attribute("started_at", str(session_raw.get("started_at") or ""))
|
|
850
|
+
db_span.set_attribute("ended_at", str(session_raw.get("ended_at") or ""))
|
|
851
|
+
try:
|
|
852
|
+
_wts = json.loads(session_raw.get("window_titles") or "[]")
|
|
853
|
+
_wt_names = [str(w.get("window_name", "")) for w in _wts if w.get("window_name")]
|
|
854
|
+
except (TypeError, ValueError):
|
|
855
|
+
_wt_names = []
|
|
856
|
+
db_span.set_attribute("window_titles", " | ".join(_wt_names) if _wt_names else "-")
|
|
857
|
+
db_span.set_attribute("window_title_count", len(_wt_names))
|
|
800
858
|
db_span.set_attribute("duration_s", float(session_raw.get("duration_s") or 0.0))
|
|
801
859
|
db_span.set_attribute("text_source", str(session_raw.get("session_text_source") or ""))
|
|
802
860
|
db_span.set_attribute("session_text_chars", len(session_text))
|
|
861
|
+
# Frame-range attribution: the contiguous screenpipe frame_id window this
|
|
862
|
+
# session was built from (min..max, inclusive) plus the kept frame count.
|
|
863
|
+
# Answers "which capture window fed this classification" — the raw frames
|
|
864
|
+
# live in screenpipe keyed by these ids. Coding-agent rows have no frames
|
|
865
|
+
# (min/max = 0), so guard on a real range before stamping.
|
|
866
|
+
_min_fid = session_raw.get("min_frame_id")
|
|
867
|
+
_max_fid = session_raw.get("max_frame_id")
|
|
868
|
+
if isinstance(_min_fid, int) and isinstance(_max_fid, int) and _max_fid > 0:
|
|
869
|
+
db_span.set_attribute("min_frame_id", _min_fid)
|
|
870
|
+
db_span.set_attribute("max_frame_id", _max_fid)
|
|
871
|
+
db_span.set_attribute("frame_count", int(session_raw.get("frame_count") or 0))
|
|
872
|
+
# Coding-agent provenance: which agent conversation + segment this row came
|
|
873
|
+
# from, when the indexer sealed it, and who wrote the summary the model is
|
|
874
|
+
# classifying on. Only present on coding-agent rows (Claude Code / Codex /
|
|
875
|
+
# …); guard on coding_agent_session_uuid so screen-capture sessions stay clean.
|
|
876
|
+
_ca_uuid = session_raw.get("coding_agent_session_uuid")
|
|
877
|
+
if _ca_uuid:
|
|
878
|
+
db_span.set_attribute("coding_agent_session_uuid", str(_ca_uuid))
|
|
879
|
+
db_span.set_attribute("segment_started_at", str(session_raw.get("segment_started_at") or ""))
|
|
880
|
+
db_span.set_attribute("sealed_at", str(session_raw.get("sealed_at") or ""))
|
|
881
|
+
db_span.set_attribute("summary_source", str(session_raw.get("summary_source") or ""))
|
|
803
882
|
db_span.set_attribute("pm_tasks_count", len(pm_tasks))
|
|
804
883
|
db_span.set_attribute("today_focus_count", len(focus_keys))
|
|
805
884
|
db_span.set_attribute("recent_sessions_count", len(recent))
|
|
806
885
|
db_span.set_attribute("candidate_task_keys", ", ".join(candidate_keys) if candidate_keys else "-")
|
|
807
886
|
db_span.set_attribute("today_focus_keys", ", ".join(focus_keys) if focus_keys else "-")
|
|
887
|
+
# Which candidate-set policy actually applied for this session, so a trace
|
|
888
|
+
# explains the candidate list without re-deriving it:
|
|
889
|
+
# all → no confirmed plan; every open ticket offered
|
|
890
|
+
# plan_only → narrowed to the confirmed plan
|
|
891
|
+
# plan_fallback_all → plan confirmed but its tickets weren't live → fell back
|
|
892
|
+
# boost → legacy boost-never-filter (flag off)
|
|
893
|
+
if not focus_keys:
|
|
894
|
+
candidate_mode = "all"
|
|
895
|
+
elif not _PLAN_ONLY_CANDIDATES:
|
|
896
|
+
candidate_mode = "boost"
|
|
897
|
+
elif pm_tasks and all(t.get("is_today_focus") for t in pm_tasks):
|
|
898
|
+
candidate_mode = "plan_only"
|
|
899
|
+
else:
|
|
900
|
+
candidate_mode = "plan_fallback_all"
|
|
901
|
+
db_span.set_attribute("candidate_mode", candidate_mode)
|
|
808
902
|
db_span.set_attribute("recent_task_keys", ", ".join(recent_task_keys) if recent_task_keys else "-")
|
|
809
903
|
|
|
810
904
|
session = {
|
|
@@ -1254,6 +1348,14 @@ def _classify_one_logged_inner(
|
|
|
1254
1348
|
}
|
|
1255
1349
|
run_log.write(json.dumps(record, default=str) + "\n")
|
|
1256
1350
|
run_log.flush()
|
|
1351
|
+
# Promote app_name onto the classify_session span (the one row-per-session
|
|
1352
|
+
# span the dashboards query), so app name is a filterable column there — not
|
|
1353
|
+
# just on the child db_fetch span. session_raw is the DB row; current span
|
|
1354
|
+
# here is classify_session (db_fetch's child span has already closed).
|
|
1355
|
+
if session_raw:
|
|
1356
|
+
_cs = trace.get_current_span()
|
|
1357
|
+
if _cs.is_recording():
|
|
1358
|
+
_cs.set_attribute("app_name", str(session_raw.get("app_name") or ""))
|
|
1257
1359
|
_annotate_classification_span(result)
|
|
1258
1360
|
return result
|
|
1259
1361
|
|
|
@@ -17,6 +17,19 @@
|
|
|
17
17
|
"customMultiSelectValue": [],
|
|
18
18
|
"escapeSingleQuotes": true
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
"type": "textbox",
|
|
22
|
+
"name": "app_name",
|
|
23
|
+
"label": "App name",
|
|
24
|
+
"query_data": null,
|
|
25
|
+
"value": "",
|
|
26
|
+
"options": [],
|
|
27
|
+
"multiSelect": false,
|
|
28
|
+
"hideOnDashboard": false,
|
|
29
|
+
"selectAllValueForMultiSelect": "custom",
|
|
30
|
+
"customMultiSelectValue": [],
|
|
31
|
+
"escapeSingleQuotes": true
|
|
32
|
+
},
|
|
20
33
|
{
|
|
21
34
|
"type": "custom",
|
|
22
35
|
"name": "session_type",
|
|
@@ -141,10 +154,10 @@
|
|
|
141
154
|
"queryType": "sql",
|
|
142
155
|
"queries": [
|
|
143
156
|
{
|
|
144
|
-
"query": "SELECT to_char(to_timestamp_micros(_timestamp + 19800000000),'%Y-%m-%d %H:%M:%S') as \"Time\", session_id as \"Session\", task_key as \"Task\", session_type as \"Type\", category as \"Category\", confidence as \"Confidence\", round(CAST(elapsed_s AS DOUBLE),2) as \"Time taken (s)\", method as \"Method\", is_error as \"Error\", trace_id as \"trace_id\", encode(concat('trace_id=''', trace_id, ''''),'base64') as \"trace_filter\" FROM \"default\" WHERE operation_name='classify_session' AND ('$session_id'='' OR session_id='$session_id') AND ('$session_type'='' OR session_type='$session_type') AND ('$errors_only'='' OR is_error='$errors_only') ORDER BY _timestamp DESC",
|
|
157
|
+
"query": "SELECT to_char(to_timestamp_micros(_timestamp + 19800000000),'%Y-%m-%d %H:%M:%S') as \"Time\", session_id as \"Session\", app_name as \"App\", task_key as \"Task\", session_type as \"Type\", category as \"Category\", confidence as \"Confidence\", round(CAST(elapsed_s AS DOUBLE),2) as \"Time taken (s)\", method as \"Method\", is_error as \"Error\", trace_id as \"trace_id\", encode(concat('trace_id=''', trace_id, ''''),'base64') as \"trace_filter\" FROM \"default\" WHERE operation_name='classify_session' AND ('$session_id'='' OR session_id='$session_id') AND ('$session_type'='' OR session_type='$session_type') AND ('$errors_only'='' OR is_error='$errors_only') AND ('$app_name'='' OR app_name LIKE '%$app_name%') ORDER BY _timestamp DESC",
|
|
145
158
|
"vrlFunctionQuery": "",
|
|
146
159
|
"customQuery": true,
|
|
147
|
-
"fields": {"stream": "default", "stream_type": "traces", "x": [{"label": "Time", "alias": "Time", "column": "_timestamp", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Session", "alias": "Session", "column": "session_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Task", "alias": "Task", "column": "task_key", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Type", "alias": "Type", "column": "session_type", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Category", "alias": "Category", "column": "category", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Confidence", "alias": "Confidence", "column": "confidence", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Time taken (s)", "alias": "Time taken (s)", "column": "elapsed_s", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Method", "alias": "Method", "column": "method", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Error", "alias": "Error", "column": "is_error", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Trace ID", "alias": "trace_id", "column": "trace_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "trace_filter", "alias": "trace_filter", "column": "trace_filter", "color": null, "isDerived": false, "havingConditions": []}], "y": [], "z": [], "breakdown": [], "filter": {"filterType": "group", "logicalOperator": "AND", "conditions": []}},
|
|
160
|
+
"fields": {"stream": "default", "stream_type": "traces", "x": [{"label": "Time", "alias": "Time", "column": "_timestamp", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Session", "alias": "Session", "column": "session_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "App", "alias": "App", "column": "app_name", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Task", "alias": "Task", "column": "task_key", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Type", "alias": "Type", "column": "session_type", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Category", "alias": "Category", "column": "category", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Confidence", "alias": "Confidence", "column": "confidence", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Time taken (s)", "alias": "Time taken (s)", "column": "elapsed_s", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Method", "alias": "Method", "column": "method", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Error", "alias": "Error", "column": "is_error", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Trace ID", "alias": "trace_id", "column": "trace_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "trace_filter", "alias": "trace_filter", "column": "trace_filter", "color": null, "isDerived": false, "havingConditions": []}], "y": [], "z": [], "breakdown": [], "filter": {"filterType": "group", "logicalOperator": "AND", "conditions": []}},
|
|
148
161
|
"config": {"promql_legend": "", "layer_type": "scatter", "weight_fixed": 1}
|
|
149
162
|
}
|
|
150
163
|
],
|
|
@@ -159,10 +172,10 @@
|
|
|
159
172
|
"queryType": "sql",
|
|
160
173
|
"queries": [
|
|
161
174
|
{
|
|
162
|
-
"query": "SELECT to_char(to_timestamp_micros(_timestamp + 19800000000),'%Y-%m-%d %H:%M:%S') as \"Time\", session_id as \"Session\", task_key as \"Task\", session_type as \"Type\", method as \"Method\", trace_id as \"trace_id\", encode(concat('trace_id=''', trace_id, ''''),'base64') as \"trace_filter\" FROM \"default\" WHERE operation_name='classify_session' AND is_error='true' ORDER BY _timestamp DESC",
|
|
175
|
+
"query": "SELECT to_char(to_timestamp_micros(_timestamp + 19800000000),'%Y-%m-%d %H:%M:%S') as \"Time\", session_id as \"Session\", app_name as \"App\", task_key as \"Task\", session_type as \"Type\", method as \"Method\", trace_id as \"trace_id\", encode(concat('trace_id=''', trace_id, ''''),'base64') as \"trace_filter\" FROM \"default\" WHERE operation_name='classify_session' AND is_error='true' AND ('$app_name'='' OR app_name LIKE '%$app_name%') ORDER BY _timestamp DESC",
|
|
163
176
|
"vrlFunctionQuery": "",
|
|
164
177
|
"customQuery": true,
|
|
165
|
-
"fields": {"stream": "default", "stream_type": "traces", "x": [{"label": "Time", "alias": "Time", "column": "_timestamp", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Session", "alias": "Session", "column": "session_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Task", "alias": "Task", "column": "task_key", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Type", "alias": "Type", "column": "session_type", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Method", "alias": "Method", "column": "method", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Trace ID", "alias": "trace_id", "column": "trace_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "trace_filter", "alias": "trace_filter", "column": "trace_filter", "color": null, "isDerived": false, "havingConditions": []}], "y": [], "z": [], "breakdown": [], "filter": {"filterType": "group", "logicalOperator": "AND", "conditions": []}},
|
|
178
|
+
"fields": {"stream": "default", "stream_type": "traces", "x": [{"label": "Time", "alias": "Time", "column": "_timestamp", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Session", "alias": "Session", "column": "session_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "App", "alias": "App", "column": "app_name", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Task", "alias": "Task", "column": "task_key", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Type", "alias": "Type", "column": "session_type", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Method", "alias": "Method", "column": "method", "color": null, "isDerived": false, "havingConditions": []}, {"label": "Trace ID", "alias": "trace_id", "column": "trace_id", "color": null, "isDerived": false, "havingConditions": []}, {"label": "trace_filter", "alias": "trace_filter", "column": "trace_filter", "color": null, "isDerived": false, "havingConditions": []}], "y": [], "z": [], "breakdown": [], "filter": {"filterType": "group", "logicalOperator": "AND", "conditions": []}},
|
|
166
179
|
"config": {"promql_legend": "", "layer_type": "scatter", "weight_fixed": 1}
|
|
167
180
|
}
|
|
168
181
|
],
|
package/services/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meridian-agents"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.58.0"
|
|
8
8
|
description = "Meridian agents — MLX classifier server and Jira worklog synthesis for meridian.db"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
authors = [{ name = "Meridiona" }]
|
|
@@ -51,7 +51,7 @@ def _reconstruct_prompt(db_path: str, session_id: int) -> str | None:
|
|
|
51
51
|
recent = _fetch_recent_sessions(con, session_id)
|
|
52
52
|
pm_tasks = _fetch_pm_tasks(con)
|
|
53
53
|
session_text = raw.get("session_text") or ""
|
|
54
|
-
if raw.get("
|
|
54
|
+
if raw.get("coding_agent_session_uuid") and (raw.get("session_summary") or "").strip():
|
|
55
55
|
session_text = raw["session_summary"]
|
|
56
56
|
session = {
|
|
57
57
|
"id": session_id,
|
|
@@ -13,7 +13,7 @@ what meridian actually produced in app_sessions. Reports three layers:
|
|
|
13
13
|
Join key is the screenpipe frame_id: labeled blocks carry a frame_range; app_sessions carry
|
|
14
14
|
min_frame_id/max_frame_id. Each app_session is assigned to exactly one labeled block by its
|
|
15
15
|
midpoint frame, so fragments are never double-counted. Only screen-derived sessions
|
|
16
|
-
(
|
|
16
|
+
(coding_agent_session_uuid IS NULL) participate — coding-agent rows are a separate ingest path.
|
|
17
17
|
|
|
18
18
|
This is the measurement harness for the real-session eval (KAN-141). Re-run it after every
|
|
19
19
|
ETL fix to quantify the delta against a fixed ground-truth label set.
|
|
@@ -77,7 +77,7 @@ def _load_sessions(db_path: Path, date: str) -> list[dict]:
|
|
|
77
77
|
task_confidence, task_method
|
|
78
78
|
FROM app_sessions
|
|
79
79
|
WHERE substr(started_at, 1, 10) = ?
|
|
80
|
-
AND
|
|
80
|
+
AND coding_agent_session_uuid IS NULL
|
|
81
81
|
ORDER BY min_frame_id
|
|
82
82
|
""",
|
|
83
83
|
(date,),
|
package/ui.tar.gz
CHANGED
|
Binary file
|