graphjin 3.20.71 → 3.20.72

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.
Files changed (2) hide show
  1. package/README.md +147 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -20,7 +20,8 @@ Works with PostgreSQL, MySQL, MongoDB, SQLite, Oracle, MSSQL, Snowflake, Redshif
20
20
  - **Smart discovery before action** - Agents start with `query_catalog(search: "<user instruction>")`, `graphql_help`, relationship evidence, examples, config recipes, and safety notes before writing or running queries.
21
21
  - **Guarded action, not raw access** - Source-mode access, query allow-lists, read-only boundaries, policy-aware MCP tools, local encrypted secrets, and `gj_config` preview/apply keep changes auditable.
22
22
  - **Operational awareness** - `gj_security`, `gj_runtime`, and the built-in console expose policy and bounded runtime status so agents can check what is safe before they act.
23
- - **Durable memory and standing questions** - Saved queries, fragments, and workflows live in the owner-scoped `gj_artifacts` store; cursor-backed watches (`gj_watch`) run standing questions under the owner's permissions, resume from persisted subscription cursors, and deliver fired events to a durable inbox (`gj_watch_event`), webhooks, or workflows. Normal watches are durable by default; explicit ephemeral watches use TTL leases.
23
+ - **Standing questions, not just answers** - Hand a cursor-paginated subscription to `gj_watch` and GraphJin keeps answering it under the owner's permissions, resumes from persisted cursors across restarts, treats absence as a first-class event, and files what it finds in a durable inbox (`gj_watch_event`), a webhook, or a workflow. Evaluation runs on database polls, not model calls - a model writes the watch once, and nothing calls one again unless you turn on optional per-watch triage. See [Watches](#watches-and-standing-questions).
24
+ - **Durable memory** - Saved queries, fragments, and workflows live in the owner-scoped `gj_artifacts` store. Normal watches are durable by default; explicit ephemeral watches use TTL leases.
24
25
 
25
26
  ## Installation
26
27
 
@@ -608,7 +609,151 @@ Instead of your client chaining `query_catalog` → `validate_where_clause` →
608
609
  - **Machine-actionable refusals:** blocked responses carry a structured `refusal` (code, reasons, unblock steps, `policy_final`/`retryable`) so a calling agent can course-correct in one step instead of guessing.
609
610
  - **Server-owned model:** `ask_graphjin_agent` always uses the provider, model, and credential environment variable configured under `agent`. Without server credentials it fails closed with `model_credentials_required`.
610
611
 
611
- It is an RLM loop — the model writes JavaScript that calls the discovery tools, and the typed result is parsed from `key: value` output. It needs strong **code generation**, not provider tool-calling. Ax requests structured JSON for typed stages, choosing the mechanism from the named deployment profile (`agent.provider`) and its rules for the selected model; `agent.structured_output_mode: auto` is the default, with `native`, `function`, and `json_object` available as overrides. See [AGENTIC.md](AGENTIC.md#server-side-agent) and [CONFIG.md](CONFIG.md#agent-configuration).
612
+ It is an RLM loop — the model writes JavaScript that calls the discovery tools, and the typed result is parsed from `key: value` output. It needs strong **code generation**, not provider tool-calling. Ax requests structured JSON for typed stages, choosing the mechanism from the named deployment profile (`agent.provider`) and its rules for the selected model; `agent.structured_output_mode: auto` is the default, with `native`, `function`, and `json_object` available as overrides. `agent.service_tier` similarly defaults to provider-delegated `auto`, with portable `standard`, `flex`, and `priority` requests available when the profile/model supports them. See [AGENTIC.md](AGENTIC.md#server-side-agent) and [CONFIG.md](CONFIG.md#agent-configuration).
613
+
614
+ ## Watches And Standing Questions
615
+
616
+ Asking is a pull: it only produces value when someone thinks to ask. A watch is the
617
+ push direction. You hand `gj_watch` a cursor-paginated subscription once, and GraphJin
618
+ keeps answering it against live data, under the owner's stored identity and role.
619
+
620
+ ```graphql
621
+ mutation {
622
+ gj_watch(insert: {
623
+ name: "failed_invoices"
624
+ description: "Alert when a failed invoice changes."
625
+ query: "subscription failed_invoices { invoices(where: {status: {eq: \"failed\"}}, first: 25, after: $cursor) { id account_id status attempts } invoices_cursor }"
626
+ }) { id name status enabled }
627
+ }
628
+ ```
629
+
630
+ - **It costs database polls, not model calls.** The runner rides GraphJin's existing
631
+ cursor-backed subscriptions, compares a hash of each result, and writes a cursor
632
+ checkpoint even when nothing changed. No model is consulted to decide whether
633
+ something happened. A model writes the watch once; after that the only optional model
634
+ cost is per-watch triage in `enrich_json`, which is off by default and capped per day.
635
+ - **Absence is a first-class event.** A watch with `absence_json` fires when the
636
+ expected thing *does not* arrive, so silence stops being indistinguishable from
637
+ health.
638
+ - **It survives restarts.** Cursors are persisted, so a watch resumes where it left off
639
+ rather than replaying or skipping.
640
+ - **It cannot outrun its owner.** A watch only ever sees what its owner could already
641
+ query, and both `gj_watch` and `gj_watch_event` are owner-scoped.
642
+ - **Waking you and acting are different permissions.** Inbox delivery is immediate;
643
+ autonomous webhook or workflow delivery stays paused until the exact current
644
+ `action_hash` is approved. Alerts fail open, actions fail closed.
645
+
646
+ The built-in demo registers four standing questions on a first run (declared in
647
+ `examples/saas-ops/seed/watches.yml`), three of which have already fired by the time the
648
+ console opens. Management, review, cleanup, and MCP resource subscriptions are covered
649
+ under [MCP Tools](#mcp-tools); the full model is in
650
+ [AGENTIC.md](AGENTIC.md#watches-standing-questions-with-a-durable-inbox).
651
+
652
+ ## Train And Measure Agents On Your Own Graph
653
+
654
+ The same machinery that grades GraphJin's public benchmark can grade agents on
655
+ *your* data, and serve as a reinforcement-learning environment for tuning small
656
+ models on it.
657
+
658
+ ```bash
659
+ # Generate a verified task suite from your catalog, with a train/eval split
660
+ graphjin eval create --demo --writable --scale 500 --composition coverage \
661
+ --verify-concurrency 8 --split 0.8
662
+
663
+ # Serve it: pooled isolated worlds, one graded episode per request
664
+ graphjin env serve --path ./graphjin-demo --suite eval/suite.yml --pool 4 \
665
+ --split eval/suite.split.json --side train --freeze-time 2026-08-01T12:00:00Z
666
+ ```
667
+
668
+ - **Tasks come from your schema.** Each carries a hidden oracle — a read-only
669
+ query that computes the answer in the database — so being plausible earns
670
+ nothing. Writes are graded by the state the database ended in *and* by every
671
+ other row staying put.
672
+ - **Worlds are isolated and resettable.** An episode leases one, so a task that
673
+ writes changes only the world it was given.
674
+ - **Your policy plugs in by configuration**, not code: point `agent.base_url` at
675
+ any OpenAI-compatible endpoint.
676
+ - **Your real schema, without your real data.** `graphjin env clone --url
677
+ <server>` learns a running GraphJin server's schema from its catalog and
678
+ writes a local SQLite copy filled with synthetic rows. No data is read: the
679
+ only real values that cross over are the closed sets the catalog already
680
+ publishes. The clone is writable and resettable, so write tasks and training
681
+ work against it while production is never touched.
682
+ - **Nothing memorable to overfit.** `graphjin env new-world` writes a fresh
683
+ organization — schema, data and all — deterministically from a seed, so you
684
+ can train on some companies and measure on others. Worlds can be asked for the
685
+ awkwardness real schemas have: one word meaning two things, a stale column
686
+ that still looks authoritative, fields that are usually null.
687
+ - **Any industry, not three.** `graphjin env new-world --describe "genome
688
+ sequencing lab"` asks a capable model to name the records that business would
689
+ actually keep, checks every name, and saves the description as
690
+ `world-pack.json` inside the world. From then on the world is rebuilt from
691
+ that file with `--pack`: deterministic, and with no model involved.
692
+ - **A big model writes the questions a schema cannot derive.** Counting and
693
+ filtering follow from column statistics; knowing that *failed invoices are
694
+ worth alerting on* does not. `graphjin eval author` asks a capable model —
695
+ configured separately from the small one being trained, via `GJ_GENERATOR_*` —
696
+ to choose what is worth watching and phrase it as a colleague would. Every
697
+ table, column and value it names must exist, and every task it produces is
698
+ verified against the live database before it counts.
699
+ - **Questions no single source answers.** Real answers are often half in the
700
+ database and half in something somebody wrote down. Clones carry over the
701
+ document sources the original served — the names only, never a file — and
702
+ authoring plants the standard it grades against in a document of its own, so
703
+ the ground truth is true by construction rather than assumed.
704
+ - **Runs export as training data.** `graphjin eval export` writes trajectories
705
+ as JSONL, marking the programs GraphJin's runtime wrote itself so they are not
706
+ mistaken for the policy's.
707
+ - **Collecting is not measuring.** `graphjin eval sample --repeats 8
708
+ --temperature 0.8` draws many attempts at each task instead of judging one.
709
+ It reaches no verdict and promotes nothing, because a temperature raised on
710
+ purpose loses against a greedy baseline every time — and it records which side
711
+ of the split it drew from, so `eval export` can refuse to build a training
712
+ corpus out of held-out work.
713
+
714
+ ```bash
715
+ # Learn a real server's schema; write a local synthetic copy
716
+ graphjin env clone --url https://graphjin.internal --out ./clone-acme
717
+
718
+ # Have a capable model author the richer families for it
719
+ export GJ_GENERATOR_MODEL=<a-strong-model>
720
+ graphjin eval author --demo --path ./clone-acme --kinds watch,confirmation,file --yes
721
+ ```
722
+
723
+ ### Driving Episodes Your Own Way
724
+
725
+ Three ways in, all grading through the same contract, so a number from one is a
726
+ number from any:
727
+
728
+ - **Let GraphJin call your endpoint** — the default. Point `agent.base_url` at
729
+ anything OpenAI-compatible.
730
+ - **Supply each completion yourself** — `env serve --step`. The episode runs
731
+ normally, but when the model is needed the call is parked and handed to you as
732
+ an observation; you post the completion back and it resumes. Useful when the
733
+ weights being updated live inside your training process and standing up an
734
+ inference server just to be called back is machinery you do not want.
735
+ - **Bring your own agent entirely** — `env serve --external`. You get the task,
736
+ an MCP endpoint and a deadline, do the work with your own scaffold, and post
737
+ an answer. The server records every tool call, so the method and behavior
738
+ rules apply exactly as they do to a hosted run — an answer with no work behind
739
+ it scores zero.
740
+
741
+ An agent run is several model calls with different jobs, and they need not all
742
+ be the policy's. `--support-model` (or `GJ_SUPPORT_MODEL`) puts a fixed capable
743
+ model in front of the distiller and responder stages while the policy answers
744
+ the executor, so a small model is measured on the work being trained rather than
745
+ through bottlenecks it did not create. The stages that write the final answer
746
+ stay with the policy: letting a stronger model write those would score its care
747
+ as the policy's grounding.
748
+
749
+ ```bash
750
+ # Train only the executor; a fixed model condenses and phrases
751
+ graphjin env serve --path ./clone-acme --suite eval/suite.yml --pool 4 \
752
+ --step --support-model <a-fast-model>
753
+ ```
754
+
755
+ See [training/README.md](training/README.md) for the client, an example policy
756
+ server, and what to record alongside a result.
612
757
 
613
758
  ## JS Workflows (GraphQL + REST)
614
759
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphjin",
3
- "version": "3.20.71",
3
+ "version": "3.20.72",
4
4
  "description": "GraphJin — one governed graph for AI agents: GraphQL + MCP over your databases, files, APIs, and code",
5
5
  "bin": {
6
6
  "graphjin": "bin/graphjin.js"