@pentatonic-ai/ai-agent-sdk 0.10.4 → 0.10.5

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/dist/index.cjs CHANGED
@@ -878,7 +878,7 @@ function fireAndForgetEmit(clientConfig, sessionOpts, messages, result, model) {
878
878
  }
879
879
 
880
880
  // src/telemetry.js
881
- var VERSION = "0.10.4";
881
+ var VERSION = "0.10.5";
882
882
  var TELEMETRY_URL = "https://sdk-telemetry.philip-134.workers.dev";
883
883
  function machineId() {
884
884
  const raw = typeof process !== "undefined" ? `${process.env?.USER || process.env?.USERNAME || "u"}:${process.platform || "x"}:${process.arch || "x"}` : "browser";
package/dist/index.js CHANGED
@@ -847,7 +847,7 @@ function fireAndForgetEmit(clientConfig, sessionOpts, messages, result, model) {
847
847
  }
848
848
 
849
849
  // src/telemetry.js
850
- var VERSION = "0.10.4";
850
+ var VERSION = "0.10.5";
851
851
  var TELEMETRY_URL = "https://sdk-telemetry.philip-134.workers.dev";
852
852
  function machineId() {
853
853
  const raw = typeof process !== "undefined" ? `${process.env?.USER || process.env?.USERNAME || "u"}:${process.platform || "x"}:${process.arch || "x"}` : "browser";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pentatonic-ai/ai-agent-sdk",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "description": "TES SDK — LLM observability and lifecycle tracking via Pentatonic Thing Event System. Track token usage, tool calls, and conversations. Manage things through event-sourced lifecycle stages with AI enrichment and vector search.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -761,6 +761,25 @@ SKIP_ATTRIBUTE_SOURCES = set(
761
761
  )
762
762
  DISTILL_MAX_AGE_DAYS = int(os.environ.get("DISTILL_MAX_AGE_DAYS", "90"))
763
763
 
764
+ # Layer-1 content pre-filter (cascade tier 1 — the cheap deterministic gate in
765
+ # front of the student/7B). Skips events with NO extractable signal BEFORE the
766
+ # LLM, so GPU is spent only on text that can yield facts.
767
+ # - bytes-garbage: a binary doc (raw PDF bytes) stored as text decodes to a
768
+ # wall of U+FFFD replacement chars. `build_event_block` feeds `content` to
769
+ # the LLM, so it sees the garbage and extracts nothing (live 2026-06-10:
770
+ # 35,296/39,453 pentatonic-team `doc` events are bytes-garbage). HIGH
771
+ # PRECISION — real text effectively never crosses a 5–10% replacement-char
772
+ # ratio, so this is a zero-quality-loss skip. (Durable fix = extract PDF
773
+ # text at INGEST; this stops the GPU waste meanwhile.)
774
+ # - too-short: trivially short content (one-line acks / emoji) has no facts.
775
+ # Conservative and OFF by default (0) to guarantee zero quality loss; tune
776
+ # up once layer-2 (the student model) owns the borderline cases.
777
+ SKIP_BYTES_GARBAGE = os.environ.get(
778
+ "DISTILL_SKIP_BYTES_GARBAGE", "true"
779
+ ).strip().lower() not in ("false", "0", "no", "off")
780
+ GARBAGE_CHAR_RATIO = float(os.environ.get("DISTILL_GARBAGE_CHAR_RATIO", "0.10"))
781
+ MIN_CONTENT_CHARS = int(os.environ.get("DISTILL_MIN_CONTENT_CHARS", "0"))
782
+
764
783
 
765
784
  def claim_next_batch(conn: psycopg.Connection) -> list[dict[str, Any]]:
766
785
  """Atomically claim up to BATCH_SIZE pending items. SKIP LOCKED so
@@ -843,6 +862,43 @@ def claim_next_batch(conn: psycopg.Connection) -> list[dict[str, Any]]:
843
862
  """,
844
863
  (DISTILL_MAX_AGE_DAYS, DISTILL_MAX_AGE_DAYS),
845
864
  )
865
+ # Pre-filter: bytes-garbage content. A binary doc (raw PDF bytes)
866
+ # stored as text decodes to mostly U+FFFD (chr(65533)); the LLM
867
+ # extracts nothing from it. Skip when the replacement-char ratio
868
+ # exceeds GARBAGE_CHAR_RATIO — real text never crosses it, so no
869
+ # quality loss. Scoped to the pending set; one cheap UPDATE/cycle.
870
+ if SKIP_BYTES_GARBAGE:
871
+ cur.execute(
872
+ """
873
+ UPDATE distillation_queue dq SET
874
+ status = 'done',
875
+ completed_at = NOW(),
876
+ last_error = 'filtered: bytes_garbage'
877
+ FROM events e
878
+ WHERE dq.event_id = e.id
879
+ AND dq.status = 'pending'
880
+ AND length(e.content) > 0
881
+ AND (length(e.content) - length(replace(e.content, chr(65533), '')))::float
882
+ / length(e.content) > %s
883
+ """,
884
+ (GARBAGE_CHAR_RATIO,),
885
+ )
886
+ # Pre-filter: trivially-short content (one-line acks / emoji). OFF by
887
+ # default (MIN_CONTENT_CHARS=0) so it never costs a fact unless tuned on.
888
+ if MIN_CONTENT_CHARS > 0:
889
+ cur.execute(
890
+ """
891
+ UPDATE distillation_queue dq SET
892
+ status = 'done',
893
+ completed_at = NOW(),
894
+ last_error = 'filtered: too_short'
895
+ FROM events e
896
+ WHERE dq.event_id = e.id
897
+ AND dq.status = 'pending'
898
+ AND length(trim(e.content)) < %s
899
+ """,
900
+ (MIN_CONTENT_CHARS,),
901
+ )
846
902
 
847
903
  with conn.cursor(row_factory=psycopg.rows.dict_row) as cur:
848
904
  cur.execute(