From 7156ffba5e2ead0a45bc77a34d2027d5d0b6ec54 Mon Sep 17 00:00:00 2001 From: Roberto Montalti Date: Sat, 19 Sep 2026 21:39:33 +0200 Subject: [PATCH 1/2] feat: add Jev decision and tree SDK --- .github/workflows/ci.yml | 13 + README.md | 117 +---- ...typed-decision-program-sdk-requirements.md | 149 ++++++ docs/guide.md | 52 +- ...2026-09-19-001-feat-hybrid-propose-plan.md | 479 ------------------ ...-09-19-002-feat-typed-decision-sdk-plan.md | 155 ++++++ docs/sdk.md | 187 +++++++ examples/dependency-tree.ts | 73 +++ examples/router.ts | 40 ++ package.json | 20 +- src/action-map.ts | 75 --- src/bash-ast.ts | 46 +- src/cli.ts | 36 +- src/config.ts | 13 +- src/decisions.ts | 183 +++---- src/env.ts | 1 - src/eval.ts | 4 +- src/generation.ts | 16 +- src/harness.ts | 57 +-- src/index.ts | 7 +- src/program-map.ts | 132 ----- src/propose/tool.ts | 96 ---- src/propose/types.ts | 9 - src/propose/validate.ts | 80 --- src/providers/catalog.ts | 75 --- src/providers/credentials.ts | 39 -- src/providers/index.ts | 58 --- src/providers/oauth.ts | 224 -------- src/providers/setup.ts | 202 -------- src/providers/types.ts | 66 --- src/providers/wire.ts | 151 ------ src/sdk/decisions.ts | 275 ++++++++++ src/sdk/index.ts | 67 +++ src/sdk/program.ts | 466 +++++++++++++++++ src/sdk/resources.ts | 250 +++++++++ src/sdk/router.ts | 68 +++ src/sdk/tree.ts | 241 +++++++++ src/sdk/types.ts | 145 ++++++ src/sdk/validation.ts | 23 + src/summary.ts | 4 - src/text-plan.ts | 2 +- src/transcript.ts | 3 - src/types.ts | 13 +- test/action-map.test.ts | 47 -- test/cli.test.ts | 22 + test/config.test.ts | 9 +- test/decisions.test.ts | 18 + test/fixtures/events-baseline.jsonl | 4 +- test/fixtures/package-consumer/bundler.mts | 21 + .../fixtures/package-consumer/deep-import.mjs | 1 + .../fixtures/package-consumer/deep-import.mts | 3 + test/fixtures/package-consumer/nodenext.mts | 20 + test/fixtures/package-consumer/runtime.mjs | 18 + .../package-consumer/tsconfig.bundler.json | 11 + .../package-consumer/tsconfig.nodenext.json | 11 + test/generation.test.ts | 9 +- test/harness.test.ts | 134 +---- test/helpers.ts | 3 +- test/package-contract.contract.ts | 109 ++++ test/program-map.test.ts | 175 ------- test/propose-e2e.test.ts | 151 ------ test/propose-tool.test.ts | 227 --------- test/propose-validate.test.ts | 87 ---- test/providers-catalog.test.ts | 27 - test/providers-credentials.test.ts | 57 --- test/providers-oauth.test.ts | 395 --------------- test/providers-setup.test.ts | 307 ----------- test/providers-wire.test.ts | 207 -------- test/render-plain.test.ts | 14 - test/scored-grid.test.ts | 6 +- test/sdk-decisions.test.ts | 157 ++++++ test/sdk-program.test.ts | 270 ++++++++++ test/sdk-router.test.ts | 69 +++ test/sdk-tree.test.ts | 232 +++++++++ test/tools.test.ts | 10 - test/transcript.test.ts | 29 -- 76 files changed, 3330 insertions(+), 3942 deletions(-) create mode 100644 docs/brainstorms/2026-09-19-typed-decision-program-sdk-requirements.md delete mode 100644 docs/plans/2026-09-19-001-feat-hybrid-propose-plan.md create mode 100644 docs/plans/2026-09-19-002-feat-typed-decision-sdk-plan.md create mode 100644 docs/sdk.md create mode 100644 examples/dependency-tree.ts create mode 100644 examples/router.ts delete mode 100644 src/action-map.ts delete mode 100644 src/program-map.ts delete mode 100644 src/propose/tool.ts delete mode 100644 src/propose/types.ts delete mode 100644 src/propose/validate.ts delete mode 100644 src/providers/catalog.ts delete mode 100644 src/providers/credentials.ts delete mode 100644 src/providers/index.ts delete mode 100644 src/providers/oauth.ts delete mode 100644 src/providers/setup.ts delete mode 100644 src/providers/types.ts delete mode 100644 src/providers/wire.ts create mode 100644 src/sdk/decisions.ts create mode 100644 src/sdk/index.ts create mode 100644 src/sdk/program.ts create mode 100644 src/sdk/resources.ts create mode 100644 src/sdk/router.ts create mode 100644 src/sdk/tree.ts create mode 100644 src/sdk/types.ts create mode 100644 src/sdk/validation.ts delete mode 100644 test/action-map.test.ts create mode 100644 test/cli.test.ts create mode 100644 test/fixtures/package-consumer/bundler.mts create mode 100644 test/fixtures/package-consumer/deep-import.mjs create mode 100644 test/fixtures/package-consumer/deep-import.mts create mode 100644 test/fixtures/package-consumer/nodenext.mts create mode 100644 test/fixtures/package-consumer/runtime.mjs create mode 100644 test/fixtures/package-consumer/tsconfig.bundler.json create mode 100644 test/fixtures/package-consumer/tsconfig.nodenext.json create mode 100644 test/package-contract.contract.ts delete mode 100644 test/program-map.test.ts delete mode 100644 test/propose-e2e.test.ts delete mode 100644 test/propose-tool.test.ts delete mode 100644 test/propose-validate.test.ts delete mode 100644 test/providers-catalog.test.ts delete mode 100644 test/providers-credentials.test.ts delete mode 100644 test/providers-oauth.test.ts delete mode 100644 test/providers-setup.test.ts delete mode 100644 test/providers-wire.test.ts create mode 100644 test/sdk-decisions.test.ts create mode 100644 test/sdk-program.test.ts create mode 100644 test/sdk-router.test.ts create mode 100644 test/sdk-tree.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00cb184..f5bd692 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,3 +20,16 @@ jobs: - run: npm run typecheck - run: npm test - run: npm run build + package-contract: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [22, 24] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - run: npm ci + - run: npm run test:package diff --git a/README.md b/README.md index 22d61ca..fac15c8 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,30 @@ ## NAME -jev-code - coding agent and decision pipe driven by Jev, the decision-only model from [typesafe.ai](https://typesafe.ai) +jev-code - typed routing, decision programs, and validated formal trees driven by Jev, the decision-only model from [typesafe.ai](https://typesafe.ai) -## SYNOPSIS +## SDK + +`jev-code` is first a Jev-only TypeScript library. Applications supply finite alternatives and keep ownership of effects; Jev selects among those alternatives. The public ESM API provides validated decision sessions, typed routers, immutable programs, and bounded formal-tree construction. The coding harness and CLI are built on the same contracts. + +```typescript +import { DecisionSession, defineRouter, route } from 'jev-code'; + +const router = defineRouter({ + inspect: route('Read state without changing it', { effect: 'read' } as const), + modify: route('Change application state', { effect: 'write' } as const), +}); + +const selected = await router.select( + new DecisionSession(provider), + { request: 'Show the current status' }, + 'Choose the application route.', +); +``` + +See [the SDK guide](docs/sdk.md) and the executable [router](examples/router.ts) and [dependency-tree](examples/dependency-tree.ts) examples. Import from the package root; implementation paths are intentionally private. + +## CLI SYNOPSIS ``` jev-code [options] ["task"] @@ -17,7 +38,6 @@ jev-code decide --score "criteria" [--lines] jev-code decide --spec file.json jev-code replay run-id [--speed x] [--plain] jev-code login | logout -jev-code provider login [id] | logout [id] | list [--json] | models [id] [--json] | use [id|none] [--model id] [--base-url url] jev-code ast install module | ast list | ast remove id ``` @@ -52,8 +72,6 @@ The interactive session is a transcript of cards. Each tool call is one card: a `decide` uses the same model on standard input. A shell script can branch on the exit code without parsing. -jev-code is a hybrid. Jev is the only policy. With a generation provider configured, `write_file` and Python `write_files` ask the LLM to map a source task into meaningful subproblems and compatible code options. Jev approves the map, chooses implementations, and reviews the assembled program. Language validators check it before writing; the harness then runs applicable verification. The LLM proposes structure and code but cannot approve a plan, choose tools, write files, or end a run. `propose` remains available for explanations and other file formats. See PROVIDERS. - ## FIRST RUN The first interactive run asks for your typesafe.ai API key. jev-code saves the key in `~/.config/jev-code/config.json` with mode 600. @@ -76,11 +94,6 @@ jev-code | `jev-code replay ` | Render a saved journal through the same transcript. | | `jev-code login` | Enter the API key and save it. | | `jev-code logout` | Remove the saved API key. | -| `jev-code provider login [id]` | Configure the generation provider: provider, authentication, model. Without `id` a picker opens. | -| `jev-code provider logout [id]` | Remove the stored credential of a provider. | -| `jev-code provider list [--json]` | List the providers, their authentication methods, the active one, and which are signed in. | -| `jev-code provider models [id] [--json]` | List the bundled and discovered models of a provider. | -| `jev-code provider use [id\|none] [--model ] [--base-url ]` | Select the active provider. Without `id` a picker opens; missing model or base URL are asked for on a terminal. Flags skip the prompts. `none` turns mapping and `propose` off. | | `jev-code ast install ` | Install an AST adapter module from a local path or an npm package. | | `jev-code ast list` | List the installed AST adapters. | | `jev-code ast remove ` | Remove an installed AST adapter. | @@ -124,81 +137,6 @@ Every language below is built in. jev-code selects the grammar from the file ext A validator must be on `PATH` before Jev writes a file in that language. A missing validator stops the write with a message that names the tool. Each rendered program of the shared core is checked by its real toolchain: a fuzz suite in `test/lang-fuzz.test.ts` drives every dialect with random productions and compiles the result. -## PROVIDERS - -Program mapping and `propose` use the same generation provider. The first interactive run asks whether to configure one. `Not now` records the choice and does not ask again. `jev-code provider login` opens the same setup at any time: - -```text -Select generation provider: -> OpenAI - Anthropic - Google - OpenRouter - OpenAI-compatible - Local - -Authentication: -> Sign in with OAuth (vendor terms apply) - Use API key - -Model: -> gpt-5-nano - gpt-5-mini - gpt-4.1-nano -``` - -| Provider | Authentication | Wire | Models | -| --- | --- | --- | --- | -| `openai` | OAuth (browser, port 1455) or API key | Chat completions with a key; Responses on the ChatGPT backend with OAuth | `gpt-5-nano`, `gpt-5-mini`, `gpt-4.1-nano`, live list with a key | -| `anthropic` | OAuth (paste the code) or API key | Messages | `claude-haiku-4-5`, `claude-3-5-haiku` | -| `google` | API key | OpenAI-compatible endpoint | `gemini-2.5-flash-lite`, `gemini-2.5-flash`, live list | -| `openrouter` | OAuth (browser) or API key | Chat completions | small models from several vendors, live list | -| `openai-compatible` | API key | Chat completions at the base URL you enter | live list | -| `local` | none | Chat completions at `http://localhost:11434/v1` | live list from the server | - -Use small, cheap, fast models. The generator only writes candidates; Jev does the judging. API keys are the supported path. OAuth with a consumer subscription is a convenience the vendor can withdraw; jev-code shows that in the picker label. Google OAuth is not implemented. - -For a source file with a registered language adapter, `write_file` uses a program map: at most eight steps, each with one to three code options explained in task terms. For Fibonacci, the decisions concern the starting pair, advancing the sequence, and printing the requested count—not choosing AST nodes. Jev can reject the map or any piece, triggering a bounded remap. Each piece is at most 2 KB, and every candidate combination considered by Jev passes the language adapter's source check. Without a provider, the existing grammar builders remain available. `write_files` uses maps with a destination path per step and validates the assembled Python project, including local imports. Existing single-file rewrites load the destination source (up to 16 KB) and preserve behavior unrelated to the requested change. - -If tool calls repeat without progress, the same provider proposes concrete next actions with paths or commands. Jev selects or rejects them; ordinary permissions still apply. Recovery cannot supply source contents directly and shares the proposal budget. - - -The Python prompt “a simple python fibonaci program writing the first 10” completed in a live run on September 19, 2026: 3 turns, 13 Jev requests, about 20 seconds, and output `0 1 1 2 3 5 8 13 21 34`. This is a smoke test, not a general benchmark. - -How one `propose` call runs: - -1. Jev fills the request: `kind` (`file` or `text`), `objective`, `constraints`, `count` (1 to 5), `path`. -2. The provider returns `count` candidates. One refresh of an expired OAuth token covers the whole batch. -3. Validators drop candidates that are truncated, empty, too large, unchanged, duplicates of an earlier candidate, a JSON wrapper around the content, or fail the language validator of the file type. -4. Jev selects one label or `reject`. The selection is one decision with `field=candidate`. -5. A `file` candidate is written atomically. A `text` candidate is returned as the output. - -A run recorded against an OpenAI-compatible gateway (`gpt-5.5` behind LiteLLM) with a scripted Jev stand-in: - -```text -✓ propose haiku.py · 6.0 s · 61 req - │ +print("Moon pulls the tide in") - │ +print("Salt wind combs the sleeping waves") - │ +print("Dawn shells gleam softly") -── turn 2 · 1 file - │ Moon pulls the tide in - │ Salt wind combs the sleeping waves - │ Dawn shells gleam softly -✓ bash 'python3' 'haiku.py' · exit 0 · 18 ms · 5 req -``` - -The journal record of that call: - -```json -{"provider":"openai-compatible","model":"gpt-5.5", - "candidates":[{"label":"A","valid":true,"bytes":109}, - {"label":"B","valid":true,"bytes":109}, - {"label":"C","valid":true,"bytes":112}], - "selected":"A","confidence":0.81} -``` - -One failed request drops only its own candidate; the others still reach Jev. Limits: `--max-proposals ` caps generator calls per run (default 20). Each generator request times out after 60 s. `propose` counts as a write for `--confirm-writes`; the approval covers the request, and the content is shown in the diff card after the write. The current file and the objective are sent to the configured provider. - ## DECIDE `decide` reads all of stdin, asks Jev one question, prints the answer, and exits. It never runs tools. It never writes files. @@ -324,9 +262,8 @@ git diff | jev-code decide --true "safe to commit" && git commit -am wip | Path | Content | | --- | --- | -| `~/.config/jev-code/config.json` | The saved typesafe.ai API key and the `generation` settings (provider, model, auth, base URL). Mode 600. `XDG_CONFIG_HOME` and `JEV_CODE_CONFIG_DIR` change the directory. | -| `~/.config/jev-code/credentials.json` | Generation provider secrets: API keys, OAuth access and refresh tokens, keyed by provider id. Mode 600. Never copied into events, journals, or child processes. | -| `.env` | Optional. `TYPESAFE_API_KEY=...` in the current directory. Loaded before the saved key. `JEV_GENERATION_API_KEY=...` overrides the stored generation credential. | +| `~/.config/jev-code/config.json` | The saved typesafe.ai API key. Mode 600. `XDG_CONFIG_HOME` and `JEV_CODE_CONFIG_DIR` change the directory. | +| `.env` | Optional. `TYPESAFE_API_KEY=...` in the current directory. Loaded before the saved key. | | `.jev/runs/.jsonl` | One journal per run: every event as one JSON line. Input for `replay`. | | `.jev/eval/` | Eval records and journals from `npm run dev -- eval`. | @@ -346,4 +283,6 @@ Jev has a 32k context and selects from bounded lists. Small programs complete. L ## SEE ALSO -[docs/guide.md](docs/guide.md) - session, output formats, AST adapters, options, journals, eval results. +[docs/sdk.md](docs/sdk.md) - public decisions, routers, programs, formal trees, limits, and package contract. + +[docs/guide.md](docs/guide.md) - CLI sessions, output formats, AST adapters, options, journals, and eval results. diff --git a/docs/brainstorms/2026-09-19-typed-decision-program-sdk-requirements.md b/docs/brainstorms/2026-09-19-typed-decision-program-sdk-requirements.md new file mode 100644 index 0000000..e90d283 --- /dev/null +++ b/docs/brainstorms/2026-09-19-typed-decision-program-sdk-requirements.md @@ -0,0 +1,149 @@ +--- +date: 2026-09-19 +topic: jev-decision-tree-sdk +--- + +# Jev Decision and Tree SDK + +## Summary + +Create a Jev-only TypeScript SDK for typed routing, decision programs, and bounded construction of validated formal trees. `jev-code` will use the same public contracts and will remove every LLM generation, proposal, mapping, and provider-setup path. + +--- + +## Problem Frame + +Jev supplies typed choices, probabilities, and scores, but complex consumers must currently build their own orchestration, budgets, cancellation, dependency ordering, tree traversal, validation, and event streams. `jev-code` contains working versions of these ideas, but they are coupled to a coding harness rather than presented as a coherent reusable library. + +The experiment with LLM-produced code chunks obscures the distinctive product. This project is a Jev decision harness: every uncertain branch is a bounded Jev decision over alternatives supplied by deterministic host code. General-purpose formal tree construction—not LLM generation—is the reusable center. Code and shell ASTs are reference applications of that model. + +--- + +## Actors + +- A1. SDK consumer: Defines typed routers, decision programs, or formal tree grammars. +- A2. Host application: Supplies input, finite alternatives, validators, and any effects performed after a decision. +- A3. Jev decision provider: Selects among offered alternatives and returns typed decision metadata. +- A4. `jev-code`: Proves the public SDK against coding actions and constrained AST construction. + +--- + +## Key Flows + +- F1. **Typed routing:** A host offers finite typed routes, Jev selects one, and the SDK returns the route plus metadata without executing its handler. +- F2. **Decision program:** A host composes sequential, parallel, and data-dependent decisions; the runtime enforces shared limits and returns a typed outcome. +- F3. **Formal tree construction:** A grammar exposes valid productions for a pending slot; Jev selects one; the runtime expands child slots, validates the completed tree, and stops within node/depth/request bounds. +- F4. **Jev Code dogfooding:** `jev-code` routes actions and builds code/command trees through public SDK contracts, then retains application-owned permissions and effects. + +--- + +## Requirements + +**Jev-only authority** + +- R1. Every uncertain selection must be made by Jev from a finite set of host-supplied alternatives. +- R2. The project must contain no LLM candidate producer, `propose` tool, program mapper, action mapper, generation-provider configuration, OAuth/API-key setup for generation providers, or documentation advertising those features. +- R3. The SDK must not define an LLM/provider abstraction other than the Jev decision-provider boundary supplied by `@typesafe-ai/sdk`. +- R4. Deterministic host logic may validate, eliminate, or auto-resolve a structurally forced singleton, but it may not make a semantic choice that belongs to Jev. + +**Decision programs** + +- R5. The SDK must expose typed routers and immutable typed programs with typed input and output. +- R6. Programs must support sequential transformation, bounded parallel composition, and data-dependent continuation. +- R7. Program definitions must be concurrently reusable; each run owns isolated state while nested work shares run budgets and cancellation. +- R8. Runs must return discriminated completed, failed, invalid, cancelled, and exhausted outcomes. +- R9. Runs must emit versioned, monotonically ordered, bounded events suitable for logs, UI, and host persistence. + +**Formal tree construction** + +- R10. The SDK must let consumers define a domain-neutral formal tree grammar made of named slots and finite productions. +- R11. A production may complete a slot with a typed node or introduce typed child slots whose results are assembled into a parent node. +- R12. The tree runtime must expose only structurally valid productions, ask Jev to choose among semantic alternatives, and validate every completed node and final tree. +- R13. Independent child slots may expand concurrently while sharing request, node, depth, time, and concurrency limits. +- R14. Invalid grammars, duplicate identities, cycles, missing dependencies, depth overflow, and node exhaustion must fail clearly without presenting a partial tree as complete. +- R15. Tree definitions and events must remain domain-neutral; source code, files, paths, commands, and language-specific node kinds belong to consumers. + +**Host boundary and testing** + +- R16. The SDK must not own filesystem, shell, network, authorization, credentials, UI, persistence, or application completion semantics. +- R17. Deterministic Jev providers must make routers, programs, and trees fully testable without network access. +- R18. Decision results must expose selected values and normalized metadata without leaking raw provider responses. + +**Reference application and distribution** + +- R19. `jev-code` must use public SDK contracts for action routing and at least one real AST/command tree construction path. +- R20. Existing permissions, workspace policy, journals, replay, CLI rendering, budgets, cancellation, and no-partial-write guarantees must remain application behavior. +- R21. The package must expose a deliberate ESM public API with declarations and packed-artifact tests; unrelated implementation modules must not become public accidentally. +- R22. Documentation must include a small typed router, a non-code tree, and the `jev-code` tree integration. + +--- + +## Acceptance Examples + +- AE1. **Covers R1, R5, R18.** A three-route ticket router returns one typed Jev-selected route and metadata but never invokes the route handler. +- AE2. **Covers R6-R9.** Two independent child programs run within one concurrency limit; their dependent continuation waits for both and all events have increasing sequence numbers. +- AE3. **Covers R10-R14.** A menu grammar expands categories and items into a validated tree; invalid productions are absent before Jev chooses, and node/depth limits prevent unbounded expansion. +- AE4. **Covers R11-R13.** A selected parent production introduces two child slots, they expand concurrently, and their typed results assemble into the parent. +- AE5. **Covers R8, R14.** A final tree validator rejects the assembly and the run returns non-completed evidence without a completed value. +- AE6. **Covers R2-R3.** Repository and packed-package searches contain no generation-provider, proposal, mapper, or LLM-facing public feature. +- AE7. **Covers R17.** Router and tree tests run entirely with a deterministic local Jev provider. +- AE8. **Covers R19-R20.** `jev-code` selects an action through the SDK, then its existing authorization layer can deny execution; a real AST path builds through the public tree contract before the application writes anything. + +--- + +## Success Criteria + +- A useful typed router fits in roughly one screen of TypeScript. +- A non-code example demonstrates recursive, validated, data-dependent tree construction. +- `jev-code` contains no optional LLM generation feature or setup surface. +- At least one production `jev-code` AST/command builder consumes the public tree API rather than a private duplicate. +- All SDK behavior is testable with deterministic providers and all existing non-LLM CLI behavior remains green. +- The packed tarball supports documented ESM imports and declaration consumers without loading UI modules. + +--- + +## Scope Boundaries + +### Deferred for later + +- Persistent/resumable tree runs and cross-process scheduling. +- Interactive graph visualization beyond the event stream. +- Additional convenience grammars after the core tree contract is proven. +- Actual npm publication pending owner-controlled package naming and license decisions. + +### Outside this product's identity + +- LLM-powered generation, proposal, mapping, judging, or recovery. +- A general-purpose agent framework that owns tools, memory, permissions, or effects. +- A hosted workflow/model service or credential manager. +- A universal parser generator; the SDK selects among consumer-defined productions but does not parse grammar notation. +- Coding-specific AST definitions as core SDK concepts. + +--- + +## Key Decisions + +- Jev-only is a product boundary, not a default mode: LLM generation support is deleted rather than retained behind flags. +- Typed decision programs are the orchestration layer; formal tree construction is the main reusable higher-level capability. +- Tree grammars expose finite valid productions one slot at a time; Jev supplies semantic policy while deterministic code guarantees structural validity. +- Effects remain with hosts, making the same kernel suitable for routers, configuration trees, plans, code ASTs, and command trees. +- `jev-code` dogfooding is mandatory so the public contracts are shaped by a demanding real application. + +--- + +## Dependencies / Assumptions + +- The initial audience is TypeScript/Node.js developers building complex applications with Jev. +- `@typesafe-ai/sdk` remains the only model dependency. +- Existing hand-written Python, Bash, and shared-language AST builders provide migration patterns and behavioral baselines. +- Program and tree definitions can keep rich typed values locally while projecting JSON-safe context to Jev. + +--- + +## Outstanding Questions + +### Deferred to Planning + +- Select the smallest tree grammar API that preserves TypeScript inference for recursive child slots. +- Choose the first `jev-code` AST/command builder to migrate with the lowest compatibility risk. +- Decide whether the existing package root or a dedicated subpath best communicates the SDK contract without a package split. diff --git a/docs/guide.md b/docs/guide.md index 5ef9b39..d34450f 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,6 +1,8 @@ # Jev Code -A TypeScript coding harness built from Jev's typed decisions. Each action is a turn: choose a tool, construct its arguments, execute it, observe its real result, then decide what to do next. Python files and Bash commands use constrained AST productions; paths and text use choices. Completion summaries come from observed tool results. +`jev-code` is a Jev-only TypeScript SDK for typed routing, composable decision programs, and validated formal trees. The coding harness documented here is one application of that public API. It keeps tools, authorization, workspace policy, journals, and execution in application code while Jev makes bounded choices over alternatives supplied by deterministic code. Start with the [SDK guide](sdk.md) for library use. + +The CLI is a coding harness built from those typed decisions. Each action is a turn: choose a tool, construct its arguments, execute it, observe its real result, then decide what to do next. Python files and Bash commands use constrained AST productions; paths and text use choices. Completion summaries come from observed tool results. This is an experimental harness with tested execution plumbing. Jev is a decision model, not a text model: general code generation quality remains an empirical question. Accepting arbitrary tasks does **not** guarantee it can solve every task. Use actual compiler/test outcomes to assess generated code. @@ -71,7 +73,6 @@ Interactive rendering runs on Ink, React, and `ink-text-input` at runtime; `--pr | `edit_file` | Replace one unambiguous exact match; fail without mutation otherwise. | | `bash` | Execute an arbitrary Bash command with bounded output and an explicit exit status. | | `set_plan` | Record/revise the active plan and progress. | -| `propose` | Ask the configured generation model for candidates, filter them, let Jev select one or reject all, then write the file or return the text. Registered only when a provider is configured. See Propose. | | `finish` | End the run, gated by a separate task-scoped Jev completion choice. | | `blocked` | Explain a missing prerequisite or user decision. | @@ -106,41 +107,6 @@ Limits are explicit: 50 action turns, 512 Jev requests, 256 AST productions or e Run statuses are `completed`, `blocked`, `limited`, `cancelled`, or `error`. Only `completed` exits with code 0; cancellation exits with 130, other failures with 1. Interactive mode carries a bounded conversation summary and inspects the current workspace on each run. New API-side instructions can be queued during a run and are applied at the next turn boundary. -## Program mapping - -With a generation provider, `write_file` resolves the destination first and uses the registered language adapter to validate a mapped program. It no longer asks Jev to choose individual AST productions for this route. The LLM proposes a JSON map containing an observable goal, verification checks, ordered subproblems, input/output names, and compatible code options. Jev reviews the map against the original task, selects each implementation by its meaning and code, and reviews the assembled result. The generator has no tool access or authority to approve its own plan. - -Maps contain at most eight steps and three options per step. Each option is at most 2 KB; the map is at most 32 KB. For each option, validation assembles the selected earlier pieces, that option, and the first option from each remaining step. This checks compatibility before Jev selects; those later pieces remain tentative. An invalid default later piece can require remapping. Jev rejection or source validation failure returns feedback to the mapper. There are at most three mapping attempts per draft, sharing `--max-proposals` with `propose`. Jev reviews and selections share the normal request and generation-step budgets. Errors never fall back silently to token-by-token grammar generation, and no draft is written before approval and validation finish. - -The journal and trace mark these decisions with `phase: "program_map"`: `review_plan`, `choose_step`, and `review_program`. Progress displays the subproblem and the meaning of the selected implementation. Language validation is not proof of runtime behavior; the harness must still run applicable verification. The current adapter's validation determines which syntax or static checks are available. - -Repeated calls with unchanged results trigger action mapping. The provider proposes at most four concrete actions; unknown tools, invalid arguments, repeated calls, and embedded source contents are filtered out. Jev selects or rejects the remaining options in `phase: "action_map"`. The selected action still passes ordinary authorization. Source writes go through program mapping; recovery shares `--max-proposals` with code maps and `propose`. A successful write resets the repetition window. - - -Python `write_files` uses the same mapping flow with a safe relative `.py` path per step. Fragments are joined per file, and candidate projects pass cross-file import validation. For single-file rewrites, the mapper receives the actual destination source, capped at 16 KB; larger files require focused edits. Both generator and review are scoped to the destination file, while task completion still covers every requested change and verification. Without a configured generation provider, both write tools retain their grammar builders. Free text still uses `propose text`. Library hosts enable mapping by passing `generationProvider` in `HarnessOptions`; the CLI shares its configured provider with mapping and `propose`. - -## Propose - -Jev cannot write open-ended text. `propose` gives it a bounded way to get some: a small autoregressive model produces candidates, TypeScript filters them, and Jev selects. The generator is not an agent. It does not see the tool list, the plan, or the history. It receives one objective, optional constraints, the path, and the current file content. It returns text. - -The request fields are filled by Jev through the normal argument generator: `kind` (`file` or `text`), `objective`, `constraints` (may be empty), `count` (1 to 5, default 3), `path` (required for `file`; for `text` an optional existing file whose content is given to the generator as context and left unchanged). The provider returns `count` completions from `count` parallel single-completion requests. Validators run in a fixed order and stop at the first failure: `generation failed` (the request itself failed), `truncated` (the model hit its output limit), `empty`, `too large` (over 16 KB), `unchanged` (equal to the current file after whitespace normalization), `json wrapper` (a JSON object or array standing in for a non-JSON file), `duplicate of