jev-devtools 0.2.0 → 0.4.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/README.md +50 -6
- package/lib/flow/index.d.ts +143 -0
- package/lib/flow/index.js +1029 -0
- package/lib/flow/runtime.d.ts +5 -0
- package/lib/flow/runtime.js +81 -0
- package/lib/server/flows.d.ts +28 -0
- package/lib/server/flows.js +187 -0
- package/lib/server/index.d.ts +14 -1
- package/lib/server/index.js +100 -1
- package/lib/server/recorder.d.ts +4 -1
- package/lib/server/recorder.js +19 -3
- package/lib/src/ChoiceProbabilities.js +1 -1
- package/lib/src/ConnectedInspector.js +13 -4
- package/lib/src/DiagramContent.d.ts +6 -0
- package/lib/src/DiagramContent.js +32 -0
- package/lib/src/FlowDetailsPanel.d.ts +8 -0
- package/lib/src/FlowDetailsPanel.js +79 -0
- package/lib/src/FlowOverview.d.ts +8 -0
- package/lib/src/FlowOverview.js +440 -0
- package/lib/src/JevDevtools.d.ts +6 -1
- package/lib/src/JevDevtools.js +18 -4
- package/lib/src/TraceDiagram.d.ts +4 -1
- package/lib/src/TraceDiagram.js +30 -12
- package/lib/src/condition-inputs.d.ts +9 -0
- package/lib/src/condition-inputs.js +109 -0
- package/lib/src/flow-condition.d.ts +4 -0
- package/lib/src/flow-condition.js +48 -0
- package/lib/src/flow-model.d.ts +7 -2
- package/lib/src/flow-model.js +2 -11
- package/lib/src/flow-protocol.d.ts +93 -0
- package/lib/src/flow-protocol.js +1 -0
- package/lib/src/flow-stream.d.ts +8 -0
- package/lib/src/flow-stream.js +80 -0
- package/lib/src/inspector-styles.js +1 -1
- package/lib/src/inspector.css +746 -8
- package/lib/src/protocol.d.ts +5 -0
- package/lib/src/useDiagramViewport.d.ts +5 -1
- package/lib/src/useDiagramViewport.js +31 -9
- package/package.json +11 -4
- package/skills/setup-jev-devtools/SKILL.md +8 -4
- package/skills/setup-jev-devtools/references/flows.md +227 -0
- package/skills/setup-jev-devtools/references/nextjs.md +3 -1
- package/skills/setup-jev-devtools/references/react-node.md +2 -2
- package/skills/setup-jev-devtools/references/verify.md +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Jev DevTools
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/jev-devtools/v/0.4.0)
|
|
4
4
|
|
|
5
5
|
A React drawer and Node adapter for inspecting TypeSafe Jev requests with animated diagrams. Includes request history, context, questions, typed answers, transport attempts, and raw snapshots.
|
|
6
6
|
|
|
7
|
-
**Experimental
|
|
7
|
+
**0.4.0 — pending publication.** Use a packed checkout until publication is confirmed in the changelog. **Experimental (pre-1.0).** React 18/19 and Node 22.12+ are supported. APIs may change before 1.0. Verification uses sample responses through the real TypeSafe SDK, not live inference.
|
|
8
8
|
|
|
9
9
|
[Changelog and release history](https://github.com/diegoag64/jev-devtools/blob/main/CHANGELOG.md) — published versions and unreleased work.
|
|
10
10
|
|
|
@@ -34,17 +34,17 @@ The [setup skill](https://github.com/diegoag64/jev-devtools/blob/main/packages/j
|
|
|
34
34
|
Install from npm:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
npm install jev-devtools
|
|
37
|
+
npm install jev-devtools @typesafe-ai/sdk
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
To try
|
|
40
|
+
To install this checkout before publication or try later local changes:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
43
|
# From the jev-devtools repository root:
|
|
44
44
|
npm ci
|
|
45
45
|
npm run pack:devtools
|
|
46
46
|
# From the consuming app:
|
|
47
|
-
npm install /absolute/path/to/jev-devtools-0.
|
|
47
|
+
npm install /absolute/path/to/jev-devtools-0.4.0.tgz
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Mount once:
|
|
@@ -73,10 +73,54 @@ app.use(inspector.middleware); // Mount at root, before fallback handlers.
|
|
|
73
73
|
|
|
74
74
|
Only calls through that client are captured. The React component subscribes via same-origin SSE, receiving an initial snapshot followed by changed traces. Older client/server combinations remain compatible through full snapshots. Both sides default to disabled. API keys remain server-side. Browser code is SSR-safe. The drawer uses a Shadow DOM boundary and its own stylesheet so host page selectors cannot alter its internal layout. Existing stylesheet imports remain supported; no Tailwind or shadcn installation is required. Drag the Flow canvas to pan, scroll/pinch to zoom, or use Fit.
|
|
75
75
|
|
|
76
|
-
History is bounded to 50 calls in memory by default. API routes and inspector endpoints must share an adapter instance; distributed processes and edge runtimes are not supported.
|
|
76
|
+
History is bounded to 50 calls in memory by default. API routes and inspector endpoints must share an adapter instance; distributed processes and edge runtimes are not supported. Without `authorize`, the middleware accepts only loopback connections; Web Request handlers can't see the connection's address, so run those servers on `127.0.0.1`. Captures include bounded/redacted context and answers, not hidden model reasoning.
|
|
77
77
|
|
|
78
78
|
For Next.js App Router, use `getJevDevtools(appKey, optionsFactory)` from `/server` to share an adapter across server reloads, expose `handleNodeRoute` through an optional catch-all Route Handler, and mount the root component in a client boundary. See the [Next.js guide](https://github.com/diegoag64/jev-devtools/blob/main/docs/nextjs.md) and runnable example. No Next dependency is required by this package.
|
|
79
79
|
|
|
80
80
|
[Full integration guide](https://github.com/diegoag64/jev-devtools/blob/main/docs/integration.md) · [Repository and playground](https://github.com/diegoag64/jev-devtools)
|
|
81
81
|
|
|
82
82
|
MIT for project code. See bundled LICENSE and THIRD_PARTY_NOTICES.txt for original design attribution and TypeSafe branding.
|
|
83
|
+
|
|
84
|
+
## Connected Jev flows with `jev-devtools/flow`
|
|
85
|
+
|
|
86
|
+
Define calls, conditions, parallel checks, and named outcomes with `jev-devtools/flow`. **0.4.0 adds** server function steps (`task`), runtime request factories, bounded collections (`map`), returning conditionals (`if`), stateful iteration (`loop`), and strict numeric `.gt()` comparisons. The drawer connects request diagrams, function results, selected paths, collection items, and loop iterations on one canvas. Existing single-request integrations remain supported.
|
|
87
|
+
|
|
88
|
+
On the server, reuse the instrumented `jev` client and `inspector` from the setup above:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { defineJevFlow } from 'jev-devtools/flow';
|
|
92
|
+
|
|
93
|
+
const review = defineJevFlow<{ message: string }>('review', (flow) => {
|
|
94
|
+
const decision = flow.jev('readiness', {
|
|
95
|
+
state: flow.input,
|
|
96
|
+
questions: { ready: { type: 'noul', instructions: 'Is this ready for review?' } },
|
|
97
|
+
}, { title: 'Assess readiness' });
|
|
98
|
+
|
|
99
|
+
return flow.branch('route', {
|
|
100
|
+
when: decision.answer('ready').noul.gte(0.9), // Your application's policy.
|
|
101
|
+
then: (path) => path.output('ready', { probability: decision.answer('ready').noul }, {
|
|
102
|
+
title: 'Ready for review', description: 'Return readiness to the application.',
|
|
103
|
+
}),
|
|
104
|
+
else: (path) => path.output('manual-review', undefined, { title: 'Needs manual review' }),
|
|
105
|
+
}, { title: 'Require at least 90% readiness' });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = await review.run({ message: 'Please review my ticket.' }, {
|
|
109
|
+
client: jev,
|
|
110
|
+
devtools: inspector,
|
|
111
|
+
});
|
|
112
|
+
// Handle result.outcome in your app. The flow does not execute business actions.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Define once in a Node module and run per request. Use `flow.parallel` for concurrent named lanes; downstream calls wait for every lane to succeed. `flow.branch` is terminal in its block; use `flow.if` when selected values feed shared downstream work. Tasks execute application code on Node with JSON-compatible inputs/results; maps and loops have explicit bounds. Runs have SDK retries and cooperative cancellation, with bounded in-memory inspector history. They do not provide durable or distributed execution. Keep the 0.4.0 server and drawer together to inspect its new step kinds.
|
|
116
|
+
|
|
117
|
+
[Full flow guide](https://github.com/diegoag64/jev-devtools/blob/main/docs/flows.md) · [AI flow recipe](https://github.com/diegoag64/jev-devtools/blob/main/packages/jev-devtools/skills/setup-jev-devtools/references/flows.md)
|
|
118
|
+
|
|
119
|
+
To have your coding agent add a flow after installation:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
Read node_modules/jev-devtools/skills/setup-jev-devtools/SKILL.md and references/flows.md.
|
|
123
|
+
Build a flow for the scenario I describe using the shared server client/inspector.
|
|
124
|
+
Preserve my routing policies, add clear step titles/descriptions, and verify with
|
|
125
|
+
labeled samples before using live inference. Ask for any missing decision rules.
|
|
126
|
+
```
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { Questions, ResultFor, SystemOneRequest, TypeSafeClient } from "@typesafe-ai/sdk";
|
|
2
|
+
import type { FlowDefinition, FlowDisplay, FlowRun } from "../src/flow-protocol.js";
|
|
3
|
+
export type { FlowDisplay, FlowDefinition, FlowRun, FlowStep, } from "../src/flow-protocol.js";
|
|
4
|
+
type Ast = {
|
|
5
|
+
op: "input";
|
|
6
|
+
} | {
|
|
7
|
+
op: "ref";
|
|
8
|
+
id: string;
|
|
9
|
+
} | {
|
|
10
|
+
op: "get";
|
|
11
|
+
from: Ast;
|
|
12
|
+
key: string;
|
|
13
|
+
} | {
|
|
14
|
+
op: "literal";
|
|
15
|
+
value: unknown;
|
|
16
|
+
} | {
|
|
17
|
+
op: "eq" | "lt" | "gt" | "gte" | "all" | "any" | "not";
|
|
18
|
+
args: Ast[];
|
|
19
|
+
};
|
|
20
|
+
/** Inspectable expression, not an application callback. Use get() for input fields. */
|
|
21
|
+
export declare class FlowExpression<T> {
|
|
22
|
+
readonly ast: Ast;
|
|
23
|
+
private readonly valueType;
|
|
24
|
+
constructor(ast: Ast, owner?: object);
|
|
25
|
+
get<K extends keyof T & (string | number)>(key: K): FlowExpression<T[K]>;
|
|
26
|
+
eq(value: T | FlowExpression<T>): FlowExpression<boolean>;
|
|
27
|
+
lt(this: FlowExpression<number>, value: number | FlowExpression<number>): FlowExpression<boolean>;
|
|
28
|
+
gt(this: FlowExpression<number>, value: number | FlowExpression<number>): FlowExpression<boolean>;
|
|
29
|
+
gte(this: FlowExpression<number>, value: number | FlowExpression<number>): FlowExpression<boolean>;
|
|
30
|
+
}
|
|
31
|
+
export declare const all: (...conditions: FlowExpression<boolean>[]) => FlowExpression<boolean>;
|
|
32
|
+
export declare const any: (...conditions: FlowExpression<boolean>[]) => FlowExpression<boolean>;
|
|
33
|
+
export declare const not: (condition: FlowExpression<boolean>) => FlowExpression<boolean>;
|
|
34
|
+
export type FlowOutcome = {
|
|
35
|
+
outcome: string;
|
|
36
|
+
value?: unknown;
|
|
37
|
+
};
|
|
38
|
+
type AnswerRefs<Q extends Questions> = {
|
|
39
|
+
/** All answers, including question names created by a runtime request factory. */
|
|
40
|
+
readonly answers: FlowExpression<{
|
|
41
|
+
[K in keyof Q]: ResultFor<Q[K]>;
|
|
42
|
+
}>;
|
|
43
|
+
answer<K extends keyof Q & string>(name: K): {
|
|
44
|
+
[F in keyof ResultFor<Q[K]>]: FlowExpression<ResultFor<Q[K]>[F]>;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
type Request<Q extends Questions> = Omit<SystemOneRequest<Q>, "state"> & {
|
|
48
|
+
state: unknown;
|
|
49
|
+
};
|
|
50
|
+
/** Resolve nested references before invoking a server callback. */
|
|
51
|
+
export type Resolved<T> = T extends FlowExpression<infer V> ? V : T extends readonly unknown[] ? {
|
|
52
|
+
[K in keyof T]: Resolved<T[K]>;
|
|
53
|
+
} : T extends object ? {
|
|
54
|
+
[K in keyof T]: Resolved<T[K]>;
|
|
55
|
+
} : T;
|
|
56
|
+
export type TaskContext = {
|
|
57
|
+
signal: AbortSignal;
|
|
58
|
+
runId: string;
|
|
59
|
+
stepId: string;
|
|
60
|
+
executionId: string;
|
|
61
|
+
};
|
|
62
|
+
export type FlowTask<I, O> = {
|
|
63
|
+
input: I;
|
|
64
|
+
run: (input: Resolved<I>, context: TaskContext) => O | Promise<O>;
|
|
65
|
+
timeoutMs?: number;
|
|
66
|
+
};
|
|
67
|
+
export type FlowRequestFactory<I, Q extends Questions> = {
|
|
68
|
+
input: I;
|
|
69
|
+
/** Synchronous construction only; the runner executes the SDK request. */
|
|
70
|
+
request: (input: Resolved<I>) => SystemOneRequest<Q>;
|
|
71
|
+
};
|
|
72
|
+
/** Observer contract used by createJevDevtools; execution never depends on successful recording. */
|
|
73
|
+
export type FlowObserver = {
|
|
74
|
+
startFlow(definition: FlowDefinition, run: FlowRun): {
|
|
75
|
+
update(run: FlowRun): void;
|
|
76
|
+
request<T>(link: {
|
|
77
|
+
runId: string;
|
|
78
|
+
stepId: string;
|
|
79
|
+
executionId: string;
|
|
80
|
+
}, onTrace: (id: string) => void, callback: () => T): T;
|
|
81
|
+
} | undefined;
|
|
82
|
+
};
|
|
83
|
+
export type FlowRunOptions = {
|
|
84
|
+
client: Pick<TypeSafeClient, "systemOne">;
|
|
85
|
+
devtools?: FlowObserver;
|
|
86
|
+
signal?: AbortSignal;
|
|
87
|
+
};
|
|
88
|
+
export declare class FlowLoopLimitError extends Error {
|
|
89
|
+
readonly name = "FlowLoopLimitError";
|
|
90
|
+
constructor();
|
|
91
|
+
}
|
|
92
|
+
export interface FlowBuilder<T> {
|
|
93
|
+
readonly input: FlowExpression<T>;
|
|
94
|
+
jev<const Q extends Questions>(id: string, request: Request<Q>, display?: FlowDisplay): AnswerRefs<Q>;
|
|
95
|
+
jev<I, const Q extends Questions>(id: string, request: FlowRequestFactory<I, Q>, display?: FlowDisplay): AnswerRefs<Q>;
|
|
96
|
+
task<I, O>(id: string, task: FlowTask<I, O>, display?: FlowDisplay): FlowExpression<Awaited<O>>;
|
|
97
|
+
/** Execute a reusable item program with bounded concurrency; return results in input order. */
|
|
98
|
+
map<I, C, O>(id: string, options: {
|
|
99
|
+
items: FlowExpression<readonly I[]> | readonly I[];
|
|
100
|
+
input: C;
|
|
101
|
+
concurrency?: number;
|
|
102
|
+
maxItems: number;
|
|
103
|
+
}, build: (item: FlowBuilder<{
|
|
104
|
+
item: I;
|
|
105
|
+
index: number;
|
|
106
|
+
context: Resolved<C>;
|
|
107
|
+
}>) => FlowExpression<O>, display?: FlowDisplay): FlowExpression<O[]>;
|
|
108
|
+
/** Pre-test loop with JSON state, explicit context and a required iteration limit. */
|
|
109
|
+
loop<S, C>(id: string, options: {
|
|
110
|
+
initial: S | FlowExpression<S>;
|
|
111
|
+
input: C;
|
|
112
|
+
while: (state: FlowExpression<NoInfer<S>>) => FlowExpression<boolean>;
|
|
113
|
+
maxIterations: number;
|
|
114
|
+
}, build: (iteration: FlowBuilder<{
|
|
115
|
+
state: S;
|
|
116
|
+
index: number;
|
|
117
|
+
context: Resolved<C>;
|
|
118
|
+
}>) => FlowExpression<NoInfer<S>>, display?: FlowDisplay): FlowExpression<S>;
|
|
119
|
+
/** Execute one value-returning path, then continue with its typed result. */
|
|
120
|
+
if<A, B>(id: string, paths: {
|
|
121
|
+
when: FlowExpression<boolean>;
|
|
122
|
+
then: (path: FlowBuilder<T>) => FlowExpression<A>;
|
|
123
|
+
else: (path: FlowBuilder<T>) => FlowExpression<B>;
|
|
124
|
+
}, display?: FlowDisplay): FlowExpression<A | B>;
|
|
125
|
+
/** Terminal decision: each callback must return output() or another branch(). */
|
|
126
|
+
branch(id: string, paths: {
|
|
127
|
+
when: FlowExpression<boolean>;
|
|
128
|
+
then: (path: FlowBuilder<T>) => FlowExpression<FlowOutcome>;
|
|
129
|
+
else: (path: FlowBuilder<T>) => FlowExpression<FlowOutcome>;
|
|
130
|
+
}, display?: FlowDisplay): FlowExpression<FlowOutcome>;
|
|
131
|
+
parallel<const B extends Record<string, (lane: FlowBuilder<T>) => FlowExpression<unknown>>>(id: string, lanes: B, display?: FlowDisplay): {
|
|
132
|
+
[K in keyof B]: ReturnType<B[K]>;
|
|
133
|
+
};
|
|
134
|
+
output(name: string, value?: unknown, display?: FlowDisplay): FlowExpression<FlowOutcome>;
|
|
135
|
+
}
|
|
136
|
+
export declare function defineJevFlow<T>(name: string, build: (flow: FlowBuilder<T>) => FlowExpression<FlowOutcome>): {
|
|
137
|
+
definition: FlowDefinition;
|
|
138
|
+
run(data: T, options: FlowRunOptions): Promise<{
|
|
139
|
+
runId: string;
|
|
140
|
+
outcome: string;
|
|
141
|
+
value?: unknown;
|
|
142
|
+
}>;
|
|
143
|
+
};
|