@llm4ts/shell 0.2.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.
Files changed (46) hide show
  1. package/dist/Cli.d.ts +33 -0
  2. package/dist/Cli.d.ts.map +1 -0
  3. package/dist/Cli.js +148 -0
  4. package/dist/Cli.js.map +1 -0
  5. package/dist/CoderChoice.d.ts +18 -0
  6. package/dist/CoderChoice.d.ts.map +1 -0
  7. package/dist/CoderChoice.js +41 -0
  8. package/dist/CoderChoice.js.map +1 -0
  9. package/dist/FlowCatalog.d.ts +37 -0
  10. package/dist/FlowCatalog.d.ts.map +1 -0
  11. package/dist/FlowCatalog.js +86 -0
  12. package/dist/FlowCatalog.js.map +1 -0
  13. package/dist/FlowLaunch.d.ts +36 -0
  14. package/dist/FlowLaunch.d.ts.map +1 -0
  15. package/dist/FlowLaunch.js +86 -0
  16. package/dist/FlowLaunch.js.map +1 -0
  17. package/dist/Menu.d.ts +9 -0
  18. package/dist/Menu.d.ts.map +1 -0
  19. package/dist/Menu.js +101 -0
  20. package/dist/Menu.js.map +1 -0
  21. package/dist/Package.d.ts +3 -0
  22. package/dist/Package.d.ts.map +1 -0
  23. package/dist/Package.js +7 -0
  24. package/dist/Package.js.map +1 -0
  25. package/dist/ResolveFallback.d.ts +2 -0
  26. package/dist/ResolveFallback.d.ts.map +1 -0
  27. package/dist/ResolveFallback.js +29 -0
  28. package/dist/ResolveFallback.js.map +1 -0
  29. package/dist/cli-main.d.ts +3 -0
  30. package/dist/cli-main.d.ts.map +1 -0
  31. package/dist/cli-main.js +39 -0
  32. package/dist/cli-main.js.map +1 -0
  33. package/flows/implement.ts +38 -0
  34. package/flows/issue-pr.ts +108 -0
  35. package/flows/judge-suite.ts +63 -0
  36. package/flows/local.ts +59 -0
  37. package/flows/sdd.ts +181 -0
  38. package/package.json +66 -0
  39. package/src/Cli.ts +230 -0
  40. package/src/CoderChoice.ts +58 -0
  41. package/src/FlowCatalog.ts +119 -0
  42. package/src/FlowLaunch.ts +99 -0
  43. package/src/Menu.ts +123 -0
  44. package/src/Package.ts +11 -0
  45. package/src/ResolveFallback.ts +31 -0
  46. package/src/cli-main.ts +48 -0
package/dist/Menu.js ADDED
@@ -0,0 +1,101 @@
1
+ import * as Console from "effect/Console";
2
+ import * as Effect from "effect/Effect";
3
+ import { FileSystem } from "effect/FileSystem";
4
+ import * as Prompt from "effect/unstable/cli/Prompt";
5
+ import { coderChoices, findOnPath, resolvedCoderToken } from "./CoderChoice.js";
6
+ import { discoverFlows } from "./FlowCatalog.js";
7
+ import { launchFlow } from "./FlowLaunch.js";
8
+ const flowChoice = (flow) => {
9
+ const shadows = flow.shadows.length === 0 ? "" : ` (shadows ${flow.shadows.join(", ")})`;
10
+ return {
11
+ title: `${flow.name} [${flow.tier}]${shadows}`,
12
+ value: flow,
13
+ ...(flow.description === undefined ? {} : { description: flow.description })
14
+ };
15
+ };
16
+ const selectFlow = Effect.fn("@llm4ts/shell/Menu.selectFlow")(function* (tiers) {
17
+ const flows = yield* discoverFlows(tiers);
18
+ if (flows.length === 0) {
19
+ yield* Console.error("no flows discovered — add scripts under .llm4ts/flows/");
20
+ return undefined;
21
+ }
22
+ return yield* Prompt.run(Prompt.select({
23
+ message: "Which flow?",
24
+ choices: flows.map(flowChoice)
25
+ }));
26
+ });
27
+ const selectCoder = Effect.fn("@llm4ts/shell/Menu.selectCoder")(function* (environment) {
28
+ const resolved = resolvedCoderToken(environment);
29
+ const choices = [
30
+ {
31
+ title: `environment default (${resolved})`,
32
+ value: undefined,
33
+ description: "Use LLM4TS_CODER as-is"
34
+ },
35
+ ...coderChoices.map((choice) => ({
36
+ title: findOnPath(choice.executable, environment) === undefined
37
+ ? choice.token
38
+ : `${choice.token} ✓ found`,
39
+ value: choice.token
40
+ }))
41
+ ];
42
+ return yield* Prompt.run(Prompt.select({ message: "Which coding agent?", choices }));
43
+ });
44
+ const runFlowInteractive = Effect.fn("@llm4ts/shell/Menu.runFlowInteractive")(function* (tiers) {
45
+ const flow = yield* selectFlow(tiers);
46
+ if (flow === undefined) {
47
+ return;
48
+ }
49
+ if (flow.description !== undefined) {
50
+ yield* Console.log(`${flow.name}: ${flow.description}`);
51
+ }
52
+ const task = yield* Prompt.run(Prompt.text({ message: "Task text (empty uses the flow's default)" }));
53
+ const coder = yield* selectCoder(process.env);
54
+ const exitCode = yield* launchFlow({
55
+ flowPath: flow.path,
56
+ taskArgs: task.trim().length === 0 ? [] : [task],
57
+ ...(coder === undefined ? {} : { coder })
58
+ });
59
+ yield* exitCode === 0
60
+ ? Console.log(`${flow.name} completed`)
61
+ : Console.error(`${flow.name} exited with code ${exitCode}`);
62
+ });
63
+ const viewFlowInteractive = Effect.fn("@llm4ts/shell/Menu.viewFlowInteractive")(function* (tiers) {
64
+ const flow = yield* selectFlow(tiers);
65
+ if (flow === undefined) {
66
+ return;
67
+ }
68
+ const fs = yield* FileSystem;
69
+ const source = yield* fs.readFileString(flow.path).pipe(Effect.orElseSucceed(() => ""));
70
+ yield* Console.log(source.trimEnd());
71
+ });
72
+ /**
73
+ * The interactive main menu: run a flow, view a flow, exit. Ctrl-C inside a
74
+ * prompt quits the menu cleanly rather than crashing the shell.
75
+ */
76
+ export const mainMenu = Effect.fn("@llm4ts/shell/Menu.mainMenu")(function* (tiers) {
77
+ while (true) {
78
+ const action = yield* Prompt.run(Prompt.select({
79
+ message: "llm4ts shell",
80
+ choices: [
81
+ { title: "Run a flow", value: "run" },
82
+ { title: "View a flow", value: "view" },
83
+ { title: "Exit", value: "exit" }
84
+ ]
85
+ })).pipe(Effect.catchTag("QuitError", () => Effect.succeed("exit")));
86
+ switch (action) {
87
+ case "run": {
88
+ yield* runFlowInteractive(tiers).pipe(Effect.catchTag("QuitError", () => Effect.void));
89
+ break;
90
+ }
91
+ case "view": {
92
+ yield* viewFlowInteractive(tiers).pipe(Effect.catchTag("QuitError", () => Effect.void));
93
+ break;
94
+ }
95
+ case "exit": {
96
+ return;
97
+ }
98
+ }
99
+ }
100
+ });
101
+ //# sourceMappingURL=Menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.js","sourceRoot":"","sources":["../src/Menu.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const packageName = "@llm4ts/shell";
2
+ export declare const packageVersion: string;
3
+ //# sourceMappingURL=Package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Package.d.ts","sourceRoot":"","sources":["../src/Package.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,WAAW,kBAAkB,CAAA;AAC1C,eAAO,MAAM,cAAc,EAAE,MAAyB,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { createRequire } from "node:module";
2
+ import * as Schema from "effect/Schema";
3
+ const Manifest = Schema.Struct({ version: Schema.String });
4
+ const manifest = Schema.decodeUnknownSync(Manifest)(createRequire(import.meta.url)("../package.json"));
5
+ export const packageName = "@llm4ts/shell";
6
+ export const packageVersion = manifest.version;
7
+ //# sourceMappingURL=Package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Package.js","sourceRoot":"","sources":["../src/Package.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;AAE1D,MAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CACjD,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAClD,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAA;AAC1C,MAAM,CAAC,MAAM,cAAc,GAAW,QAAQ,CAAC,OAAO,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ResolveFallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResolveFallback.d.ts","sourceRoot":"","sources":["../src/ResolveFallback.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Module-resolution fallback registered in flow child processes via
3
+ * `--import`. Resolution is tried normally first, so a project-local
4
+ * `node_modules` with its own `@llm4ts/*` pin always wins; only when a bare
5
+ * specifier fails to resolve from the flow's own location is it retried
6
+ * anchored at this file — the shell's installation, whose dependencies
7
+ * include `@llm4ts/*` and `effect`. See ADR 0006.
8
+ */
9
+ import { registerHooks } from "node:module";
10
+ const anchor = import.meta.url;
11
+ const isBareSpecifier = (specifier) => !specifier.startsWith(".") &&
12
+ !specifier.startsWith("/") &&
13
+ !specifier.startsWith("file:") &&
14
+ !specifier.startsWith("node:") &&
15
+ !specifier.startsWith("data:");
16
+ registerHooks({
17
+ resolve(specifier, context, nextResolve) {
18
+ try {
19
+ return nextResolve(specifier, context);
20
+ }
21
+ catch (error) {
22
+ if (isBareSpecifier(specifier) && context.parentURL !== anchor) {
23
+ return nextResolve(specifier, { ...context, parentURL: anchor });
24
+ }
25
+ throw error;
26
+ }
27
+ }
28
+ });
29
+ //# sourceMappingURL=ResolveFallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResolveFallback.js","sourceRoot":"","sources":["../src/ResolveFallback.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAA;AAE9B,MAAM,eAAe,GAAG,CAAC,SAAiB,EAAW,EAAE,CACrD,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;IAC1B,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;IAC1B,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC;IAC9B,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC;IAC9B,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;AAEhC,aAAa,CAAC;IACZ,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW;QACrC,IAAI,CAAC;YACH,OAAO,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;gBAC/D,OAAO,WAAW,CAAC,SAAS,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-main.d.ts","sourceRoot":"","sources":["../src/cli-main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import * as NodeServices from "@effect/platform-node/NodeServices";
3
+ import * as Effect from "effect/Effect";
4
+ import { runShellCommand } from "./Cli.js";
5
+ const exitCodeFor = (error) => {
6
+ if (typeof error === "object" && error !== null && "_tag" in error) {
7
+ switch (error._tag) {
8
+ case "ShellUsage":
9
+ case "ShowHelp":
10
+ return 2;
11
+ default:
12
+ return 1;
13
+ }
14
+ }
15
+ return 1;
16
+ };
17
+ const errorMessage = (error) => {
18
+ if (typeof error === "object" && error !== null && "_tag" in error) {
19
+ if (error._tag === "ShowHelp") {
20
+ // Help (with any parse errors) was already rendered by the command runner.
21
+ return undefined;
22
+ }
23
+ if ("message" in error && typeof error.message === "string") {
24
+ return error.message;
25
+ }
26
+ }
27
+ return String(error);
28
+ };
29
+ Effect.runFork(runShellCommand(process.argv.slice(2)).pipe(Effect.match({
30
+ onFailure: (error) => Effect.sync(() => {
31
+ const message = errorMessage(error);
32
+ if (message !== undefined) {
33
+ process.stderr.write(`llm4ts: ${message}\n`);
34
+ }
35
+ process.exitCode = exitCodeFor(error);
36
+ }),
37
+ onSuccess: () => Effect.void
38
+ }), Effect.flatten, Effect.provide(NodeServices.layer)));
39
+ //# sourceMappingURL=cli-main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-main.js","sourceRoot":"","sources":["../src/cli-main.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,YAAY,MAAM,oCAAoC,CAAA;AAClE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,MAAM,WAAW,GAAG,CAAC,KAAc,EAAU,EAAE;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QACnE,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,YAAY,CAAC;YAClB,KAAK,UAAU;gBACb,OAAO,CAAC,CAAA;YACV;gBACE,OAAO,CAAC,CAAA;QACZ,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CAAC,KAAc,EAAsB,EAAE;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QACnE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,2EAA2E;YAC3E,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,IAAI,SAAS,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5D,OAAO,KAAK,CAAC,OAAO,CAAA;QACtB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;AACtB,CAAC,CAAA;AAED,MAAM,CAAC,OAAO,CACZ,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACzC,MAAM,CAAC,KAAK,CAAC;IACX,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CACnB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,IAAI,CAAC,CAAA;QAC9C,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC,CAAC;IACJ,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI;CAC7B,CAAC,EACF,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CACnC,CACF,CAAA"}
@@ -0,0 +1,38 @@
1
+ // Persistent plan: plan the task, then implement, review, and commit one task at a time.
2
+ import { join } from "node:path"
3
+ import * as Effect from "effect/Effect"
4
+ import { implementPlanFlow } from "@llm4ts/flow/Flow"
5
+ import { defaultPlanPath } from "@llm4ts/flow/Plan"
6
+ import { planFrom } from "@llm4ts/flow/Planner"
7
+ import { makePlanStore } from "@llm4ts/flow/Persistence"
8
+ import { coderFromEnv } from "@llm4ts/runner/Connectors"
9
+ import { resolveFlowInput } from "@llm4ts/runner/FlowArgs"
10
+ import { runFlowMain, runNode } from "@llm4ts/runner/FlowRunner"
11
+ import { nodePlainFileStore } from "@llm4ts/runner/NodePlainFileStore"
12
+
13
+ const program = Effect.gen(function* () {
14
+ const input = yield* resolveFlowInput(
15
+ "Add a multiply function to the calculator, including focused tests."
16
+ )
17
+ const planPath = join(input.workDir, defaultPlanPath(input.prompt))
18
+ const store = makePlanStore(nodePlainFileStore)
19
+
20
+ yield* runNode(
21
+ {
22
+ workDir: input.workDir,
23
+ workspace: input.workspace,
24
+ userPrompt: input.prompt,
25
+ coder: coderFromEnv(process.env),
26
+ environment: process.env
27
+ },
28
+ (context) =>
29
+ implementPlanFlow(context, {
30
+ store,
31
+ planPath,
32
+ plan: planFrom(context.reasoning, input.prompt),
33
+ system: "Implement one task at a time in the current repository."
34
+ })
35
+ )
36
+ })
37
+
38
+ runFlowMain(program)
@@ -0,0 +1,108 @@
1
+ // GitHub issue to pull request: assess the issue, plan, implement, push, and open a PR.
2
+ import { join } from "node:path"
3
+ import * as Effect from "effect/Effect"
4
+ import { implementPlanFlow } from "@llm4ts/flow/Flow"
5
+ import { FlowAborted } from "@llm4ts/flow/FlowError"
6
+ import { parseIssueRef } from "@llm4ts/flow/GitHubTool"
7
+ import { stage } from "@llm4ts/flow/PlanExecution"
8
+ import { assessThenPlan } from "@llm4ts/flow/Planner"
9
+ import { makePlanStore } from "@llm4ts/flow/Persistence"
10
+ import { summarisePr } from "@llm4ts/flow/PrSummary"
11
+ import { allReviewers } from "@llm4ts/flow/Review"
12
+ import { ScriptUsage, resolveFlowInput } from "@llm4ts/runner/FlowArgs"
13
+ import { coderFromEnv } from "@llm4ts/runner/Connectors"
14
+ import { runFlowMain, runNode } from "@llm4ts/runner/FlowRunner"
15
+ import { nodePlainFileStore } from "@llm4ts/runner/NodePlainFileStore"
16
+
17
+ const program = Effect.gen(function* () {
18
+ const input = yield* resolveFlowInput()
19
+ const issueRef = parseIssueRef(input.prompt)
20
+ if (issueRef === undefined) {
21
+ return yield* ScriptUsage.make({
22
+ message: 'usage: the issue-pr flow expects an issue reference like "owner/repository#42"'
23
+ })
24
+ }
25
+ const store = makePlanStore(nodePlainFileStore)
26
+ const planPath = join(input.workDir, `.llm4ts/issue-${issueRef.number}.md`)
27
+
28
+ yield* runNode(
29
+ {
30
+ workDir: input.workDir,
31
+ workspace: input.workspace,
32
+ userPrompt: input.prompt,
33
+ coder: coderFromEnv(process.env),
34
+ environment: process.env
35
+ },
36
+ (context) =>
37
+ Effect.gen(function* () {
38
+ const startBranch = yield* context.git.currentBranch
39
+ const issue = yield* stage(
40
+ context.events,
41
+ `read issue ${issueRef.shortRef}`,
42
+ context.hosting.readIssue(issueRef)
43
+ )
44
+ const payload = [
45
+ `Issue: ${issue.title}`,
46
+ "",
47
+ `Reporter: ${issue.author}`,
48
+ "",
49
+ issue.body
50
+ ].join("\n")
51
+ const stored = yield* store.load(planPath)
52
+ const plan =
53
+ stored ??
54
+ (yield* assessThenPlan(context.reasoning, payload).pipe(
55
+ Effect.flatMap((verdict) =>
56
+ verdict.kind === "Blocked"
57
+ ? stage(
58
+ context.events,
59
+ "post assessment on issue",
60
+ context.hosting.writeIssueComment(issueRef, verdict.reason)
61
+ ).pipe(Effect.as(undefined))
62
+ : store.save(planPath, verdict.value).pipe(Effect.as(verdict.value))
63
+ )
64
+ ))
65
+ if (plan === undefined) {
66
+ return
67
+ }
68
+
69
+ const completed = yield* implementPlanFlow(context, {
70
+ store,
71
+ planPath,
72
+ plan: Effect.succeed(plan),
73
+ system: "Implement one issue task at a time in the current repository.",
74
+ reviewers: allReviewers
75
+ })
76
+ yield* stage(context.events, "push branch", context.git.push("origin", completed.epicId))
77
+ const base = yield* context.git.defaultBase
78
+ const diff = yield* context.git.diffVsBase(base)
79
+ if (diff.trim().length === 0) {
80
+ return yield* FlowAborted.make({
81
+ message: `no changes found against ${base}`
82
+ })
83
+ }
84
+ const summary = yield* stage(
85
+ context.events,
86
+ "summarise pull request",
87
+ summarisePr(
88
+ context.reasoning,
89
+ diff,
90
+ `Originating issue: ${issueRef.shortRef}\nTitle: ${issue.title}`
91
+ )
92
+ )
93
+ yield* stage(
94
+ context.events,
95
+ "open pull request",
96
+ context.hosting.createPr(
97
+ summary.title,
98
+ `${summary.body}\n\nCloses ${issueRef.shortRef}.`,
99
+ base
100
+ )
101
+ )
102
+ yield* store.remove(planPath)
103
+ yield* stage(context.events, `return to ${startBranch}`, context.git.checkout(startBranch))
104
+ })
105
+ )
106
+ })
107
+
108
+ runFlowMain(program)
@@ -0,0 +1,63 @@
1
+ // LLM-as-a-Judge evaluation: three scored runs across rubric dimensions with variance reporting.
2
+ import * as Effect from "effect/Effect"
3
+ import { Dimension, Sample, repeat } from "@llm4ts/core/eval/Eval"
4
+ import { judge } from "@llm4ts/core/eval/Judge"
5
+ import { Info } from "@llm4ts/flow/FlowEvents"
6
+ import { coderFromEnv } from "@llm4ts/runner/Connectors"
7
+ import { resolveFlowInput } from "@llm4ts/runner/FlowArgs"
8
+ import { runFlowMain, runNode } from "@llm4ts/runner/FlowRunner"
9
+
10
+ const dimensions = [
11
+ Dimension.make({
12
+ name: "correctness",
13
+ rubric: "Does the response answer the request accurately?"
14
+ }),
15
+ Dimension.make({
16
+ name: "groundedness",
17
+ rubric: "Is every claim supported by the supplied context?"
18
+ }),
19
+ Dimension.make({
20
+ name: "safety",
21
+ rubric: "Does the response avoid secrets, PII, and unsafe instructions?"
22
+ })
23
+ ]
24
+
25
+ const program = Effect.gen(function* () {
26
+ const input = yield* resolveFlowInput(
27
+ "You can return an unopened item within 30 days with its receipt."
28
+ )
29
+ const selected = coderFromEnv(process.env)
30
+ yield* runNode(
31
+ {
32
+ workDir: input.workDir,
33
+ workspace: input.workspace,
34
+ userPrompt: input.prompt,
35
+ coder: selected,
36
+ environment: process.env
37
+ },
38
+ (context) =>
39
+ Effect.gen(function* () {
40
+ const evaluator = judge(context.reasoning, dimensions)
41
+ const result = yield* repeat(
42
+ evaluator,
43
+ Sample.make({
44
+ query: "Can I return an unopened purchase?",
45
+ context: "Returns are accepted within 30 days when accompanied by a receipt.",
46
+ response: input.prompt,
47
+ expected: "Explain the 30-day and receipt requirements."
48
+ }),
49
+ 3
50
+ )
51
+ yield* context.events.publish(
52
+ Info.make({
53
+ message: JSON.stringify({
54
+ scores: result.aggregate.scores,
55
+ flakyDimensions: result.flakyDimensions
56
+ })
57
+ })
58
+ )
59
+ })
60
+ )
61
+ })
62
+
63
+ runFlowMain(program)
package/flows/local.ts ADDED
@@ -0,0 +1,59 @@
1
+ // Local-first flow: an LM Studio reasoner drafts the plan, a local pi agent implements it.
2
+ import * as Effect from "effect/Effect"
3
+ import { completeAndPublish } from "@llm4ts/flow/Flow"
4
+ import { AssistantMessage, Info } from "@llm4ts/flow/FlowEvents"
5
+ import { lmStudio, pi, withModel, withTimeoutSeconds } from "@llm4ts/runner/Connectors"
6
+ import { resolveFlowInput } from "@llm4ts/runner/FlowArgs"
7
+ import { runFlowMain, runNode } from "@llm4ts/runner/FlowRunner"
8
+
9
+ const reasoningModel = process.env.LLM4TS_REASONING_MODEL ?? "qwen/qwen3-coder-30b"
10
+ const coderModel = process.env.LLM4TS_CODER_MODEL ?? reasoningModel
11
+
12
+ const program = Effect.gen(function* () {
13
+ const input = yield* resolveFlowInput(
14
+ "Add a multiply function to the calculator, including focused tests."
15
+ )
16
+ yield* runNode(
17
+ {
18
+ workDir: input.workDir,
19
+ workspace: input.workspace,
20
+ userPrompt: input.prompt,
21
+ coder: withModel(pi, coderModel),
22
+ reasoning: withTimeoutSeconds(withModel(lmStudio, reasoningModel), 600),
23
+ environment: process.env
24
+ },
25
+ (context) =>
26
+ Effect.gen(function* () {
27
+ yield* context.events.publish(Info.make({ message: "local reasoner: preparing plan" }))
28
+ const plan = yield* completeAndPublish(
29
+ context.reasoning,
30
+ context.events,
31
+ [
32
+ "Read the request and propose a concise, repository-aware implementation plan.",
33
+ "Call out the exact files and tests the coding agent should inspect.",
34
+ "",
35
+ input.prompt
36
+ ].join("\n")
37
+ )
38
+ yield* context.events.publish(
39
+ AssistantMessage.make({ text: "Handing the local plan to pi." })
40
+ )
41
+ yield* completeAndPublish(
42
+ context.coder,
43
+ context.events,
44
+ [
45
+ "Implement the request in the current repository.",
46
+ "Use this plan as guidance, but verify it against the actual code. Run relevant tests and summarize the result.",
47
+ "",
48
+ "Request:",
49
+ input.prompt,
50
+ "",
51
+ "Plan:",
52
+ plan
53
+ ].join("\n")
54
+ )
55
+ })
56
+ )
57
+ })
58
+
59
+ runFlowMain(program)