@meridiona/meridian-darwin-arm64 1.57.0 → 1.58.1
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/scripts/install-screenpipe-daemon.sh +25 -3
- package/services/agents/run_task_linker_mlx.py +102 -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.1
|
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.1",
|
|
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": {
|
|
@@ -127,10 +127,32 @@ while launchctl print "${GUI_TARGET}/${LABEL}" >/dev/null 2>&1; do
|
|
|
127
127
|
done
|
|
128
128
|
|
|
129
129
|
echo "→ bootstrap ${LABEL}"
|
|
130
|
+
# `meridian stop` runs `launchctl disable` to clear the KeepAlive intent, which
|
|
131
|
+
# persists in launchd's per-user override DB. bootstrap REFUSES a disabled label
|
|
132
|
+
# with EIO (errno 5), so the override must be cleared FIRST — otherwise a plain
|
|
133
|
+
# reinstall (install-dev.sh) can't revive a service that was `meridian stop`-ped.
|
|
130
134
|
launchctl enable "${GUI_TARGET}/${LABEL}" 2>/dev/null || true
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
# bootstrap is genuinely flaky: it EIOs when the prior domain entry hasn't fully
|
|
136
|
+
# cleared even after the bootout-wait above. Do NOT let one transient failure
|
|
137
|
+
# abort the whole install under `set -e` (that's what left screenpipe down after
|
|
138
|
+
# a stop). Retry, re-enabling each round, and treat "already loaded" as success.
|
|
139
|
+
_bs_try=0
|
|
140
|
+
until launchctl bootstrap "${GUI_TARGET}" "${PLIST_DEST}" 2>/dev/null; do
|
|
141
|
+
if launchctl print "${GUI_TARGET}/${LABEL}" >/dev/null 2>&1; then
|
|
142
|
+
break # already in the domain — bootstrap only "failed" because it's present
|
|
143
|
+
fi
|
|
144
|
+
_bs_try=$(( _bs_try + 1 ))
|
|
145
|
+
if [[ "${_bs_try}" -ge 5 ]]; then
|
|
146
|
+
echo "⚠ bootstrap ${LABEL} failed after ${_bs_try} attempts — see launchctl print" >&2
|
|
147
|
+
break
|
|
148
|
+
fi
|
|
149
|
+
launchctl enable "${GUI_TARGET}/${LABEL}" 2>/dev/null || true
|
|
150
|
+
sleep 1
|
|
151
|
+
done
|
|
152
|
+
# Always finish with enable + kickstart, even if bootstrap was a no-op above, so a
|
|
153
|
+
# disabled-but-loaded service ends up enabled AND running.
|
|
154
|
+
launchctl enable "${GUI_TARGET}/${LABEL}" 2>/dev/null || true
|
|
155
|
+
launchctl kickstart -k "${GUI_TARGET}/${LABEL}" 2>/dev/null || true
|
|
134
156
|
|
|
135
157
|
echo
|
|
136
158
|
echo "✓ screenpipe installed and started"
|
|
@@ -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,8 @@ 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,"
|
|
583
598
|
" min_frame_id, max_frame_id, frame_count"
|
|
584
599
|
" FROM app_sessions WHERE id = ?",
|
|
585
600
|
(session_id,),
|
|
@@ -684,17 +699,46 @@ def _fetch_pm_tasks(
|
|
|
684
699
|
rows = con.execute(base_cols).fetchall()
|
|
685
700
|
tasks = [dict(r) for r in rows]
|
|
686
701
|
|
|
687
|
-
#
|
|
688
|
-
#
|
|
689
|
-
# BOOST, never a filter — every other candidate still follows, so recall is
|
|
690
|
-
# untouched. A focus key that isn't in `tasks` (e.g. excluded by curation)
|
|
691
|
-
# 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).
|
|
692
704
|
focus = focus_keys or []
|
|
693
|
-
if focus:
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
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))
|
|
698
742
|
return tasks
|
|
699
743
|
|
|
700
744
|
|
|
@@ -786,7 +830,7 @@ def _classify_one(
|
|
|
786
830
|
# session_text and a concise, high-quality prose summary in
|
|
787
831
|
# session_summary. Classify on the summary, not the multi-MB transcript:
|
|
788
832
|
# cheaper, faster, and it's already the distilled "what was done".
|
|
789
|
-
if session_raw.get("
|
|
833
|
+
if session_raw.get("coding_agent_session_uuid") and (session_raw.get("session_summary") or "").strip():
|
|
790
834
|
session_text = session_raw["session_summary"]
|
|
791
835
|
|
|
792
836
|
# db_fetch is the SOLE source of "what the model was given" — recorded
|
|
@@ -797,7 +841,20 @@ def _classify_one(
|
|
|
797
841
|
# (today's-focus keys float to the front in _fetch_pm_tasks).
|
|
798
842
|
candidate_keys = [t["task_key"] for t in pm_tasks]
|
|
799
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)
|
|
800
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))
|
|
801
858
|
db_span.set_attribute("duration_s", float(session_raw.get("duration_s") or 0.0))
|
|
802
859
|
db_span.set_attribute("text_source", str(session_raw.get("session_text_source") or ""))
|
|
803
860
|
db_span.set_attribute("session_text_chars", len(session_text))
|
|
@@ -812,11 +869,36 @@ def _classify_one(
|
|
|
812
869
|
db_span.set_attribute("min_frame_id", _min_fid)
|
|
813
870
|
db_span.set_attribute("max_frame_id", _max_fid)
|
|
814
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 ""))
|
|
815
882
|
db_span.set_attribute("pm_tasks_count", len(pm_tasks))
|
|
816
883
|
db_span.set_attribute("today_focus_count", len(focus_keys))
|
|
817
884
|
db_span.set_attribute("recent_sessions_count", len(recent))
|
|
818
885
|
db_span.set_attribute("candidate_task_keys", ", ".join(candidate_keys) if candidate_keys else "-")
|
|
819
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)
|
|
820
902
|
db_span.set_attribute("recent_task_keys", ", ".join(recent_task_keys) if recent_task_keys else "-")
|
|
821
903
|
|
|
822
904
|
session = {
|
|
@@ -1266,6 +1348,14 @@ def _classify_one_logged_inner(
|
|
|
1266
1348
|
}
|
|
1267
1349
|
run_log.write(json.dumps(record, default=str) + "\n")
|
|
1268
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 ""))
|
|
1269
1359
|
_annotate_classification_span(result)
|
|
1270
1360
|
return result
|
|
1271
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.1"
|
|
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
|