@meridiona/meridian-darwin-arm64 1.61.0 → 1.62.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 CHANGED
@@ -1 +1 @@
1
- 1.61.0
1
+ 1.62.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.61.0",
3
+ "version": "1.62.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": {
@@ -221,6 +221,83 @@ _otlp_enabled() {
221
221
  return 1
222
222
  }
223
223
 
224
+ # Provision the bundled dashboards (services/observability/dashboards/*.json)
225
+ # into OpenObserve via its REST API. Idempotent: a dashboard is created only if
226
+ # no dashboard with the same title already exists (create endpoint always mints
227
+ # a fresh dashboardId, so a blind POST on every install would duplicate). Runs
228
+ # only once the service is up and reachable; degrades silently (never fails the
229
+ # install) when OpenObserve is unreachable or export is off.
230
+ _import_dashboards() {
231
+ local dash_dir
232
+ dash_dir="$(cd "${SCRIPT_DIR}/.." && pwd)/services/observability/dashboards"
233
+ [[ -d "${dash_dir}" ]] || return 0
234
+ OO_EMAIL="${OO_EMAIL}" OO_PASSWORD="${OO_PASSWORD}" python3 - "${dash_dir}" <<'PYEOF'
235
+ import base64, glob, json, os, sys, time, urllib.request, urllib.error
236
+
237
+ dash_dir = sys.argv[1]
238
+ base = "http://localhost:5080"
239
+ org = "default"
240
+ auth = base64.b64encode(f'{os.environ["OO_EMAIL"]}:{os.environ["OO_PASSWORD"]}'.encode()).decode()
241
+
242
+ def call(method, path, body=None):
243
+ data = json.dumps(body).encode() if body is not None else None
244
+ req = urllib.request.Request(
245
+ base + path, data=data, method=method,
246
+ headers={"Authorization": "Basic " + auth, "Content-Type": "application/json"},
247
+ )
248
+ try:
249
+ r = urllib.request.urlopen(req, timeout=15)
250
+ return r.status, r.read()
251
+ except urllib.error.HTTPError as e:
252
+ return e.code, e.read()
253
+ except Exception as e: # connection refused, DNS, timeout, …
254
+ return None, str(e).encode()
255
+
256
+ # Wait for the service to accept authenticated requests (just-kickstarted).
257
+ for _ in range(30):
258
+ st, _b = call("GET", "/config")
259
+ if st == 200:
260
+ break
261
+ time.sleep(1)
262
+ else:
263
+ print(" ⚠ OpenObserve not reachable — skipping dashboard import (import later by re-running this script)")
264
+ sys.exit(0)
265
+
266
+ st, body = call("GET", f"/api/{org}/dashboards")
267
+ if st != 200:
268
+ print(f" ⚠ could not list dashboards ({st}) — skipping dashboard import")
269
+ sys.exit(0)
270
+ existing = set()
271
+ for d in json.loads(body).get("dashboards", []):
272
+ for v in ("v1", "v2", "v3", "v4", "v5", "v6"):
273
+ if d.get(v) and d[v].get("title"):
274
+ existing.add(d[v]["title"])
275
+
276
+ created = skipped = failed = 0
277
+ for path in sorted(glob.glob(os.path.join(dash_dir, "*.json"))):
278
+ try:
279
+ dash = json.load(open(path))
280
+ except Exception as e:
281
+ print(f" ⚠ {os.path.basename(path)}: invalid JSON ({e}) — skipped")
282
+ failed += 1
283
+ continue
284
+ title = dash.get("title", "")
285
+ if title in existing:
286
+ skipped += 1
287
+ continue
288
+ st, resp = call("POST", f"/api/{org}/dashboards?folder=default", dash)
289
+ if st in (200, 201):
290
+ created += 1
291
+ print(f" ✓ imported dashboard: {title}")
292
+ else:
293
+ failed += 1
294
+ print(f" ⚠ failed to import {os.path.basename(path)} ({st}): {resp[:200].decode(errors='replace')}")
295
+
296
+ print(f"→ dashboards: {created} imported, {skipped} already present, {failed} failed")
297
+ PYEOF
298
+ return 0
299
+ }
300
+
224
301
  if [[ "${_no_creds}" -eq 0 ]] && _otlp_enabled; then
225
302
  echo "→ bootstrap ${LABEL} (OpenObserve Export is enabled in settings)"
226
303
  launchctl bootstrap "${GUI_TARGET}" "${PLIST_DEST}"
@@ -228,6 +305,8 @@ if [[ "${_no_creds}" -eq 0 ]] && _otlp_enabled; then
228
305
  launchctl kickstart -k "${GUI_TARGET}/${LABEL}"
229
306
  echo
230
307
  echo "✓ OpenObserve installed and started"
308
+ echo "→ importing bundled dashboards"
309
+ _import_dashboards || true
231
310
  else
232
311
  launchctl disable "${GUI_TARGET}/${LABEL}" 2>/dev/null || true
233
312
  echo
@@ -32,7 +32,7 @@ MLX_SERVER_MODEL = os.environ.get("MLX_SERVER_MODEL", "qwen3.5-9b-instruct")
32
32
  # Token caps. The MLX model exposes 128-262K context — a single Synthesise
33
33
  # call comfortably swallows even the heaviest hour of work.
34
34
  PM_WORKLOG_SYNTH_MAX_TOKENS = int(os.environ.get("PM_WORKLOG_SYNTH_MAX_TOKENS", "8000"))
35
- PM_WORKLOG_REQUEST_TIMEOUT_S = int(os.environ.get("PM_WORKLOG_REQUEST_TIMEOUT_S", "300"))
35
+ PM_WORKLOG_REQUEST_TIMEOUT_S = int(os.environ.get("PM_WORKLOG_REQUEST_TIMEOUT_S", "900"))
36
36
 
37
37
  # Temperature tuned for each step. Lower = more deterministic.
38
38
  PM_WORKLOG_TEMP_COLLECT = 0.0
@@ -62,6 +62,25 @@ async def _idle_evictor(mlx_module: Any) -> None:
62
62
  log.warning("server: idle-evictor error: %s", exc)
63
63
 
64
64
 
65
+ def _model_sem() -> "asyncio.Semaphore":
66
+ """Return the process-global single-slot model semaphore.
67
+
68
+ Created once in _lifespan and stored in _app_state. Every endpoint that
69
+ runs a model inference acquires this before calling run_in_threadpool so
70
+ that classify, synthesise_worklog, and summarise never compete on the GPU.
71
+ The synthesise path is indirectly serialised: /synthesise_worklog itself
72
+ does NOT hold the semaphore (agno calls /v1/chat/completions internally),
73
+ so /v1/chat/completions acquires it instead — no nested acquisition,
74
+ no deadlock.
75
+ """
76
+ import asyncio
77
+ sem = _app_state.get("model_sem")
78
+ if sem is None: # fallback if called before lifespan (e.g. tests)
79
+ sem = asyncio.Semaphore(1)
80
+ _app_state["model_sem"] = sem
81
+ return sem
82
+
83
+
65
84
  @asynccontextmanager
66
85
  async def _lifespan(app: FastAPI) -> AsyncIterator[None]:
67
86
  import asyncio
@@ -69,6 +88,7 @@ async def _lifespan(app: FastAPI) -> AsyncIterator[None]:
69
88
  import agents.run_task_linker_mlx as _mlx
70
89
  _app_state["mlx_module"] = _mlx
71
90
  _app_state["loaded_at"] = datetime.datetime.now(datetime.timezone.utc).isoformat()
91
+ _app_state["model_sem"] = asyncio.Semaphore(1)
72
92
  from agents.llm_selector import APPLE_INTELLIGENCE_ID
73
93
  evictor: "asyncio.Task | None" = None
74
94
  if _mlx._resolve_model_id() == APPLE_INTELLIGENCE_ID:
@@ -332,7 +352,8 @@ async def classify_sessions(req: ClassifySessionsRequest) -> dict:
332
352
  if _tok is not None:
333
353
  _otel_context.detach(_tok)
334
354
 
335
- results = await run_in_threadpool(_classify_all)
355
+ async with _model_sem():
356
+ results = await run_in_threadpool(_classify_all)
336
357
  return {"results": results}
337
358
 
338
359
 
@@ -489,7 +510,8 @@ async def openai_chat_completions(req: _OAIChatRequest) -> dict:
489
510
 
490
511
  t0 = _time.time()
491
512
  try:
492
- text = await run_in_threadpool(_generate)
513
+ async with _model_sem():
514
+ text = await run_in_threadpool(_generate)
493
515
  except Exception as exc: # noqa: BLE001
494
516
  log.warning("openai_chat_completions: inference error: %s", exc)
495
517
  raise HTTPException(status_code=500, detail=str(exc)) from exc
@@ -618,7 +640,8 @@ async def summarise(req: _SummariseRequest) -> _SummariseResponse:
618
640
  )
619
641
 
620
642
  try:
621
- raw = await run_in_threadpool(_generate)
643
+ async with _model_sem():
644
+ raw = await run_in_threadpool(_generate)
622
645
  obj = _SummarySchema.model_validate_json(raw)
623
646
  except Exception as exc: # noqa: BLE001
624
647
  log.warning("summarise: inference/parse error: %s", exc)
@@ -832,6 +855,9 @@ async def synthesise_worklog(req: _SynthWorklogRequest) -> dict:
832
855
  except Exception as exc: # noqa: BLE001 — never crash the shared server
833
856
  last_detail = f"agent run raised {type(exc).__name__}: {exc}"
834
857
  log.warning("synthesise_worklog: attempt %d %s", attempt, last_detail)
858
+ if attempt < 3:
859
+ import time as _t
860
+ _t.sleep(5 * attempt) # 5s, 10s between retries
835
861
  continue
836
862
  raw = getattr(response, "content", response)
837
863
  if raw is None:
@@ -0,0 +1,621 @@
1
+ {
2
+ "version": 8,
3
+ "title": "Coding-Agent Summariser — Continuity",
4
+ "description": "Every sealed coding-agent segment turned into a prose summary, newest first. The continuity signal: `prior_present=true` means the segment was summarised WITH the previous burst's summary injected as context (a resumed session reading as one story); `prior_chars` is how much context carried over. Backed by the `summarise_segment` spans (service meridian — the Rust daemon's in-process summariser). Copy a row's trace_id and open it in Traces for the full span. Filter by session UUID or agent above; use Continuity = 'with prior' to see only resumed-session summaries.",
5
+ "tabs": [
6
+ {
7
+ "tabId": "default",
8
+ "name": "Default",
9
+ "panels": [
10
+ {
11
+ "id": "stat_total",
12
+ "type": "metric",
13
+ "title": "Segments summarised",
14
+ "description": "Total summarise_segment spans in range",
15
+ "config": {
16
+ "show_legends": false,
17
+ "legends_position": null,
18
+ "decimals": 0.0,
19
+ "base_map": null,
20
+ "map_view": null,
21
+ "no_value_replacement": "0"
22
+ },
23
+ "queryType": "sql",
24
+ "queries": [
25
+ {
26
+ "query": "SELECT count(*) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment'",
27
+ "vrlFunctionQuery": "",
28
+ "customQuery": true,
29
+ "fields": {
30
+ "stream": "default",
31
+ "stream_type": "traces",
32
+ "x": [],
33
+ "y": [
34
+ {
35
+ "label": "Segments",
36
+ "alias": "y_axis_1",
37
+ "column": "y_axis_1",
38
+ "type": "custom",
39
+ "color": "#5960b2",
40
+ "args": [],
41
+ "isDerived": false,
42
+ "havingConditions": []
43
+ }
44
+ ],
45
+ "z": [],
46
+ "breakdown": [],
47
+ "filter": {
48
+ "filterType": "group",
49
+ "logicalOperator": "AND",
50
+ "conditions": []
51
+ }
52
+ },
53
+ "config": {
54
+ "promql_legend": "",
55
+ "layer_type": "scatter",
56
+ "weight_fixed": 1.0
57
+ }
58
+ }
59
+ ],
60
+ "layout": {
61
+ "x": 0,
62
+ "y": 0,
63
+ "w": 32,
64
+ "h": 18,
65
+ "i": 1
66
+ }
67
+ },
68
+ {
69
+ "id": "stat_with_prior",
70
+ "type": "metric",
71
+ "title": "With continuity",
72
+ "description": "Segments summarised with the prior burst's summary as context",
73
+ "config": {
74
+ "show_legends": false,
75
+ "legends_position": null,
76
+ "decimals": 0.0,
77
+ "base_map": null,
78
+ "map_view": null,
79
+ "no_value_replacement": "0"
80
+ },
81
+ "queryType": "sql",
82
+ "queries": [
83
+ {
84
+ "query": "SELECT count(*) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment' AND prior_present='true'",
85
+ "vrlFunctionQuery": "",
86
+ "customQuery": true,
87
+ "fields": {
88
+ "stream": "default",
89
+ "stream_type": "traces",
90
+ "x": [],
91
+ "y": [
92
+ {
93
+ "label": "With continuity",
94
+ "alias": "y_axis_1",
95
+ "column": "y_axis_1",
96
+ "type": "custom",
97
+ "color": "#59b27a",
98
+ "args": [],
99
+ "isDerived": false,
100
+ "havingConditions": []
101
+ }
102
+ ],
103
+ "z": [],
104
+ "breakdown": [],
105
+ "filter": {
106
+ "filterType": "group",
107
+ "logicalOperator": "AND",
108
+ "conditions": []
109
+ }
110
+ },
111
+ "config": {
112
+ "promql_legend": "",
113
+ "layer_type": "scatter",
114
+ "weight_fixed": 1.0
115
+ }
116
+ }
117
+ ],
118
+ "layout": {
119
+ "x": 32,
120
+ "y": 0,
121
+ "w": 32,
122
+ "h": 18,
123
+ "i": 2
124
+ }
125
+ },
126
+ {
127
+ "id": "stat_continuity_rate",
128
+ "type": "metric",
129
+ "title": "Continuity rate %",
130
+ "description": "Share of segments that carried prior-burst context",
131
+ "config": {
132
+ "show_legends": false,
133
+ "legends_position": null,
134
+ "unit": "percent",
135
+ "decimals": 1.0,
136
+ "base_map": null,
137
+ "map_view": null,
138
+ "no_value_replacement": "0"
139
+ },
140
+ "queryType": "sql",
141
+ "queries": [
142
+ {
143
+ "query": "SELECT round(100.0 * sum(CASE WHEN prior_present='true' THEN 1 ELSE 0 END) / count(*), 1) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment'",
144
+ "vrlFunctionQuery": "",
145
+ "customQuery": true,
146
+ "fields": {
147
+ "stream": "default",
148
+ "stream_type": "traces",
149
+ "x": [],
150
+ "y": [
151
+ {
152
+ "label": "Continuity rate",
153
+ "alias": "y_axis_1",
154
+ "column": "y_axis_1",
155
+ "type": "custom",
156
+ "color": "#b29959",
157
+ "args": [],
158
+ "isDerived": false,
159
+ "havingConditions": []
160
+ }
161
+ ],
162
+ "z": [],
163
+ "breakdown": [],
164
+ "filter": {
165
+ "filterType": "group",
166
+ "logicalOperator": "AND",
167
+ "conditions": []
168
+ }
169
+ },
170
+ "config": {
171
+ "promql_legend": "",
172
+ "layer_type": "scatter",
173
+ "weight_fixed": 1.0
174
+ }
175
+ }
176
+ ],
177
+ "layout": {
178
+ "x": 64,
179
+ "y": 0,
180
+ "w": 32,
181
+ "h": 18,
182
+ "i": 3
183
+ }
184
+ },
185
+ {
186
+ "id": "stat_fallback",
187
+ "type": "metric",
188
+ "title": "MLX fallback %",
189
+ "description": "Share summarised by the MLX fallback (primary agent CLI unavailable) — primary-engine health",
190
+ "config": {
191
+ "show_legends": false,
192
+ "legends_position": null,
193
+ "decimals": 1.0,
194
+ "base_map": null,
195
+ "map_view": null,
196
+ "no_value_replacement": "0",
197
+ "unit": "percent"
198
+ },
199
+ "queryType": "sql",
200
+ "queries": [
201
+ {
202
+ "query": "SELECT round(100.0 * sum(CASE WHEN summary_source='mlx' THEN 1 ELSE 0 END) / count(*), 1) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment'",
203
+ "vrlFunctionQuery": "",
204
+ "customQuery": true,
205
+ "fields": {
206
+ "stream": "default",
207
+ "stream_type": "traces",
208
+ "x": [],
209
+ "y": [
210
+ {
211
+ "label": "MLX fallback %",
212
+ "alias": "y_axis_1",
213
+ "column": "y_axis_1",
214
+ "type": "custom",
215
+ "color": "#9959b2",
216
+ "args": [],
217
+ "isDerived": false,
218
+ "havingConditions": []
219
+ }
220
+ ],
221
+ "z": [],
222
+ "breakdown": [],
223
+ "filter": {
224
+ "filterType": "group",
225
+ "logicalOperator": "AND",
226
+ "conditions": []
227
+ }
228
+ },
229
+ "config": {
230
+ "promql_legend": "",
231
+ "layer_type": "scatter",
232
+ "weight_fixed": 1.0
233
+ }
234
+ }
235
+ ],
236
+ "layout": {
237
+ "x": 96,
238
+ "y": 0,
239
+ "w": 32,
240
+ "h": 18,
241
+ "i": 4
242
+ }
243
+ },
244
+ {
245
+ "id": "stat_avg_summary",
246
+ "type": "metric",
247
+ "title": "Avg summary chars",
248
+ "description": "Mean length of produced summaries (successful only)",
249
+ "config": {
250
+ "show_legends": false,
251
+ "legends_position": null,
252
+ "decimals": 0.0,
253
+ "base_map": null,
254
+ "map_view": null,
255
+ "no_value_replacement": "0"
256
+ },
257
+ "queryType": "sql",
258
+ "queries": [
259
+ {
260
+ "query": "SELECT round(avg(CAST(summary_chars AS DOUBLE))) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment' AND is_error='false'",
261
+ "vrlFunctionQuery": "",
262
+ "customQuery": true,
263
+ "fields": {
264
+ "stream": "default",
265
+ "stream_type": "traces",
266
+ "x": [],
267
+ "y": [
268
+ {
269
+ "label": "Avg summary chars",
270
+ "alias": "y_axis_1",
271
+ "column": "y_axis_1",
272
+ "type": "custom",
273
+ "color": "#59a0b2",
274
+ "args": [],
275
+ "isDerived": false,
276
+ "havingConditions": []
277
+ }
278
+ ],
279
+ "z": [],
280
+ "breakdown": [],
281
+ "filter": {
282
+ "filterType": "group",
283
+ "logicalOperator": "AND",
284
+ "conditions": []
285
+ }
286
+ },
287
+ "config": {
288
+ "promql_legend": "",
289
+ "layer_type": "scatter",
290
+ "weight_fixed": 1.0
291
+ }
292
+ }
293
+ ],
294
+ "layout": {
295
+ "x": 128,
296
+ "y": 0,
297
+ "w": 32,
298
+ "h": 18,
299
+ "i": 5
300
+ }
301
+ },
302
+ {
303
+ "id": "stat_errors",
304
+ "type": "metric",
305
+ "title": "Errors",
306
+ "description": "Segments that failed to summarise (is_error=true)",
307
+ "config": {
308
+ "show_legends": false,
309
+ "legends_position": null,
310
+ "decimals": 0.0,
311
+ "base_map": null,
312
+ "map_view": null,
313
+ "no_value_replacement": "0"
314
+ },
315
+ "queryType": "sql",
316
+ "queries": [
317
+ {
318
+ "query": "SELECT count(*) as \"y_axis_1\" FROM \"default\" WHERE operation_name='summarise_segment' AND is_error='true'",
319
+ "vrlFunctionQuery": "",
320
+ "customQuery": true,
321
+ "fields": {
322
+ "stream": "default",
323
+ "stream_type": "traces",
324
+ "x": [],
325
+ "y": [
326
+ {
327
+ "label": "Errors",
328
+ "alias": "y_axis_1",
329
+ "column": "y_axis_1",
330
+ "type": "custom",
331
+ "color": "#b25959",
332
+ "args": [],
333
+ "isDerived": false,
334
+ "havingConditions": []
335
+ }
336
+ ],
337
+ "z": [],
338
+ "breakdown": [],
339
+ "filter": {
340
+ "filterType": "group",
341
+ "logicalOperator": "AND",
342
+ "conditions": []
343
+ }
344
+ },
345
+ "config": {
346
+ "promql_legend": "",
347
+ "layer_type": "scatter",
348
+ "weight_fixed": 1.0
349
+ }
350
+ }
351
+ ],
352
+ "layout": {
353
+ "x": 160,
354
+ "y": 0,
355
+ "w": 32,
356
+ "h": 18,
357
+ "i": 6
358
+ }
359
+ },
360
+ {
361
+ "id": "table_all",
362
+ "type": "table",
363
+ "title": "All segments (newest first)",
364
+ "description": "Filter with the Session UUID / Agent / Continuity variables above. 'Prior' = whether the previous burst's summary was injected; 'Prior chars' = how much context carried over. Click any row → opens that trace's spans.",
365
+ "config": {
366
+ "show_legends": false,
367
+ "legends_position": null,
368
+ "base_map": null,
369
+ "map_view": null,
370
+ "drilldown": [
371
+ {
372
+ "name": "Open this trace's spans",
373
+ "type": "byUrl",
374
+ "targetBlank": true,
375
+ "findBy": "name",
376
+ "data": {
377
+ "url": "/web/traces?org_identifier=default&stream=default&search_type=ui&search_mode=spans&period=30d&query=${row.field.trace_filter}",
378
+ "folder": "",
379
+ "dashboard": "",
380
+ "tab": "",
381
+ "passAllVariables": false,
382
+ "variables": []
383
+ }
384
+ }
385
+ ],
386
+ "wrap_table_cells": false,
387
+ "table_dynamic_columns": false
388
+ },
389
+ "queryType": "sql",
390
+ "queries": [
391
+ {
392
+ "query": "SELECT to_char(to_timestamp_micros(_timestamp + 19800000000),'%Y-%m-%d %H:%M:%S') as \"Time\", substr(session_uuid,1,8) as \"Session\", agent as \"Agent\", prior_present as \"Prior\", prior_chars as \"Prior chars\", transcript_chars as \"Transcript chars\", prompt_chars as \"Prompt chars\", summary_chars as \"Summary chars\", summary_source as \"Engine\", is_error as \"Error\", round(CAST(duration AS DOUBLE)/1000000,2) as \"Time taken (s)\", trace_id as \"trace_id\", encode(concat('trace_id=''', trace_id, ''''),'base64') as \"trace_filter\" FROM \"default\" WHERE operation_name='summarise_segment' AND ('$session_uuid'='' OR session_uuid LIKE '%$session_uuid%') AND ('$agent'='' OR agent LIKE '%$agent%') AND ('$continuity'='' OR prior_present='$continuity') ORDER BY _timestamp DESC",
393
+ "vrlFunctionQuery": "",
394
+ "customQuery": true,
395
+ "fields": {
396
+ "stream": "default",
397
+ "stream_type": "traces",
398
+ "x": [
399
+ {
400
+ "label": "Time",
401
+ "alias": "Time",
402
+ "column": "_timestamp",
403
+ "type": "custom",
404
+ "color": null,
405
+ "args": [],
406
+ "isDerived": false,
407
+ "havingConditions": []
408
+ },
409
+ {
410
+ "label": "Session",
411
+ "alias": "Session",
412
+ "column": "session_uuid",
413
+ "type": "custom",
414
+ "color": null,
415
+ "args": [],
416
+ "isDerived": false,
417
+ "havingConditions": []
418
+ },
419
+ {
420
+ "label": "Agent",
421
+ "alias": "Agent",
422
+ "column": "agent",
423
+ "type": "custom",
424
+ "color": null,
425
+ "args": [],
426
+ "isDerived": false,
427
+ "havingConditions": []
428
+ },
429
+ {
430
+ "label": "Prior",
431
+ "alias": "Prior",
432
+ "column": "prior_present",
433
+ "type": "custom",
434
+ "color": null,
435
+ "args": [],
436
+ "isDerived": false,
437
+ "havingConditions": []
438
+ },
439
+ {
440
+ "label": "Prior chars",
441
+ "alias": "Prior chars",
442
+ "column": "prior_chars",
443
+ "type": "custom",
444
+ "color": null,
445
+ "args": [],
446
+ "isDerived": false,
447
+ "havingConditions": []
448
+ },
449
+ {
450
+ "label": "Transcript chars",
451
+ "alias": "Transcript chars",
452
+ "column": "transcript_chars",
453
+ "type": "custom",
454
+ "color": null,
455
+ "args": [],
456
+ "isDerived": false,
457
+ "havingConditions": []
458
+ },
459
+ {
460
+ "label": "Prompt chars",
461
+ "alias": "Prompt chars",
462
+ "column": "prompt_chars",
463
+ "type": "custom",
464
+ "color": null,
465
+ "args": [],
466
+ "isDerived": false,
467
+ "havingConditions": []
468
+ },
469
+ {
470
+ "label": "Summary chars",
471
+ "alias": "Summary chars",
472
+ "column": "summary_chars",
473
+ "type": "custom",
474
+ "color": null,
475
+ "args": [],
476
+ "isDerived": false,
477
+ "havingConditions": []
478
+ },
479
+ {
480
+ "label": "Engine",
481
+ "alias": "Engine",
482
+ "column": "summary_source",
483
+ "type": "custom",
484
+ "color": null,
485
+ "args": [],
486
+ "isDerived": false,
487
+ "havingConditions": []
488
+ },
489
+ {
490
+ "label": "Error",
491
+ "alias": "Error",
492
+ "column": "is_error",
493
+ "type": "custom",
494
+ "color": null,
495
+ "args": [],
496
+ "isDerived": false,
497
+ "havingConditions": []
498
+ },
499
+ {
500
+ "label": "Time taken (s)",
501
+ "alias": "Time taken (s)",
502
+ "column": "duration",
503
+ "type": "custom",
504
+ "color": null,
505
+ "args": [],
506
+ "isDerived": false,
507
+ "havingConditions": []
508
+ },
509
+ {
510
+ "label": "Trace ID",
511
+ "alias": "trace_id",
512
+ "column": "trace_id",
513
+ "type": "custom",
514
+ "color": null,
515
+ "args": [],
516
+ "isDerived": false,
517
+ "havingConditions": []
518
+ },
519
+ {
520
+ "label": "trace_filter",
521
+ "alias": "trace_filter",
522
+ "column": "trace_filter",
523
+ "type": "custom",
524
+ "color": null,
525
+ "args": [],
526
+ "isDerived": false,
527
+ "havingConditions": []
528
+ }
529
+ ],
530
+ "y": [],
531
+ "z": [],
532
+ "breakdown": [],
533
+ "filter": {
534
+ "filterType": "group",
535
+ "logicalOperator": "AND",
536
+ "conditions": []
537
+ }
538
+ },
539
+ "config": {
540
+ "promql_legend": "",
541
+ "layer_type": "scatter",
542
+ "weight_fixed": 1.0
543
+ }
544
+ }
545
+ ],
546
+ "layout": {
547
+ "x": 0,
548
+ "y": 18,
549
+ "w": 192,
550
+ "h": 40,
551
+ "i": 7
552
+ }
553
+ }
554
+ ]
555
+ }
556
+ ],
557
+ "variables": {
558
+ "list": [
559
+ {
560
+ "type": "textbox",
561
+ "name": "session_uuid",
562
+ "label": "Session UUID",
563
+ "query_data": null,
564
+ "value": "",
565
+ "options": [],
566
+ "multiSelect": false,
567
+ "hideOnDashboard": false,
568
+ "selectAllValueForMultiSelect": "custom",
569
+ "customMultiSelectValue": [],
570
+ "escapeSingleQuotes": true
571
+ },
572
+ {
573
+ "type": "textbox",
574
+ "name": "agent",
575
+ "label": "Agent",
576
+ "query_data": null,
577
+ "value": "",
578
+ "options": [],
579
+ "multiSelect": false,
580
+ "hideOnDashboard": false,
581
+ "selectAllValueForMultiSelect": "custom",
582
+ "customMultiSelectValue": [],
583
+ "escapeSingleQuotes": true
584
+ },
585
+ {
586
+ "type": "custom",
587
+ "name": "continuity",
588
+ "label": "Continuity",
589
+ "query_data": null,
590
+ "value": "",
591
+ "options": [
592
+ {
593
+ "label": "All",
594
+ "value": "",
595
+ "selected": true
596
+ },
597
+ {
598
+ "label": "With prior",
599
+ "value": "true",
600
+ "selected": false
601
+ },
602
+ {
603
+ "label": "Fresh burst",
604
+ "value": "false",
605
+ "selected": false
606
+ }
607
+ ],
608
+ "multiSelect": false,
609
+ "hideOnDashboard": false,
610
+ "selectAllValueForMultiSelect": "custom",
611
+ "customMultiSelectValue": [],
612
+ "escapeSingleQuotes": true
613
+ }
614
+ ],
615
+ "showDynamicFilters": true
616
+ },
617
+ "defaultDatetimeDuration": {
618
+ "type": "relative",
619
+ "relativeTimePeriod": "12h"
620
+ }
621
+ }
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meridian-agents"
7
- version = "1.61.0"
7
+ version = "1.62.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" }]
package/ui.tar.gz CHANGED
Binary file