lalph 0.3.61 → 0.3.63
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/cli.mjs +88 -27
- package/package.json +4 -4
- package/src/Agents/researcher.ts +31 -0
- package/src/Agents/worker.ts +20 -2
- package/src/Clanka.ts +5 -3
- package/src/Projects.ts +6 -0
- package/src/PromptGen.ts +19 -0
- package/src/commands/projects/ls.ts +3 -0
- package/src/commands/root.ts +16 -6
- package/src/domain/Project.ts +1 -0
package/dist/cli.mjs
CHANGED
|
@@ -87793,6 +87793,7 @@ var Project$2 = class extends Class$1("lalph/Project")({
|
|
|
87793
87793
|
targetBranch: Option(String$1),
|
|
87794
87794
|
concurrency: Int.check(isGreaterThanOrEqualTo(1)),
|
|
87795
87795
|
gitFlow: Literals(["pr", "commit"]),
|
|
87796
|
+
researchAgent: Boolean$2.pipe(withDecodingDefault(() => false)),
|
|
87796
87797
|
reviewAgent: Boolean$2
|
|
87797
87798
|
}) {};
|
|
87798
87799
|
//#endregion
|
|
@@ -177948,7 +177949,7 @@ var ji = Bt, Ii = Object.assign(Qe, { sync: Bt }), zi = Ut, Bi = Object.assign(e
|
|
|
177948
177949
|
});
|
|
177949
177950
|
Ze.glob = Ze;
|
|
177950
177951
|
//#endregion
|
|
177951
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
177952
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/ApplyPatch.js
|
|
177952
177953
|
/**
|
|
177953
177954
|
* @since 1.0.0
|
|
177954
177955
|
*/
|
|
@@ -192821,7 +192822,7 @@ var StreamableHTTPClientTransport = class {
|
|
|
192821
192822
|
}
|
|
192822
192823
|
};
|
|
192823
192824
|
//#endregion
|
|
192824
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
192825
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/McpClient.js
|
|
192825
192826
|
/**
|
|
192826
192827
|
* @since 1.0.0
|
|
192827
192828
|
*/
|
|
@@ -192866,7 +192867,7 @@ const layer$7 = effect$1(McpClient, gen(function* () {
|
|
|
192866
192867
|
});
|
|
192867
192868
|
}));
|
|
192868
192869
|
//#endregion
|
|
192869
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
192870
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/ExaSearch.js
|
|
192870
192871
|
/**
|
|
192871
192872
|
* @since 1.0.0
|
|
192872
192873
|
*/
|
|
@@ -207816,7 +207817,7 @@ var require_lib = /* @__PURE__ */ __commonJSMin$1(((exports) => {
|
|
|
207816
207817
|
exports.impl = impl;
|
|
207817
207818
|
}));
|
|
207818
207819
|
//#endregion
|
|
207819
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
207820
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/WebToMarkdown.js
|
|
207820
207821
|
/**
|
|
207821
207822
|
* @since 1.0.0
|
|
207822
207823
|
*/
|
|
@@ -210898,7 +210899,7 @@ const unsafeSecureJsonParse = (text) => {
|
|
|
210898
210899
|
}
|
|
210899
210900
|
};
|
|
210900
210901
|
//#endregion
|
|
210901
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
210902
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/AgentTools.js
|
|
210902
210903
|
/**
|
|
210903
210904
|
* @since 1.0.0
|
|
210904
210905
|
*/
|
|
@@ -211104,7 +211105,7 @@ const AgentToolHandlersNoDeps = AgentTools.toLayer(gen(function* () {
|
|
|
211104
211105
|
const timeout = millis(options.timeoutMs ?? 12e4);
|
|
211105
211106
|
yield* logInfo(`Calling "bash"`).pipe(annotateLogs({
|
|
211106
211107
|
...options,
|
|
211107
|
-
timeout
|
|
211108
|
+
timeoutMs: format$3(timeout)
|
|
211108
211109
|
}));
|
|
211109
211110
|
const cwd = yield* CurrentDirectory;
|
|
211110
211111
|
return yield* execute(make$39("bash", ["-c", options.command], {
|
|
@@ -211112,7 +211113,7 @@ const AgentToolHandlersNoDeps = AgentTools.toLayer(gen(function* () {
|
|
|
211112
211113
|
stdin: "ignore"
|
|
211113
211114
|
})).pipe(timeoutOrElse({
|
|
211114
211115
|
duration: timeout,
|
|
211115
|
-
onTimeout: () => die$2(/* @__PURE__ */ new Error(`Command timed out after ${timeout}`))
|
|
211116
|
+
onTimeout: () => die$2(/* @__PURE__ */ new Error(`Command timed out after ${format$3(timeout)}`))
|
|
211116
211117
|
}));
|
|
211117
211118
|
}, orDie$2),
|
|
211118
211119
|
gh: fn("AgentTools.gh")(function* (args) {
|
|
@@ -211248,7 +211249,7 @@ const AgentToolHandlers = AgentToolHandlersNoDeps.pipe(provide$3([layer$6, layer
|
|
|
211248
211249
|
AgentToolHandlersNoDeps.pipe(provide$3([mock(ExaSearch)({}), mock(WebToMarkdown)({})]));
|
|
211249
211250
|
var ApplyPatchError = class extends TaggedClass$1("ApplyPatchError") {};
|
|
211250
211251
|
//#endregion
|
|
211251
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211252
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/TypeBuilder.js
|
|
211252
211253
|
const resolveDocumentation = resolveAt("documentation");
|
|
211253
211254
|
const identifierPattern = /^[$A-Z_a-z][$0-9A-Z_a-z]*$/u;
|
|
211254
211255
|
const Precedence = {
|
|
@@ -211521,7 +211522,7 @@ const render = (schema, options) => {
|
|
|
211521
211522
|
return printNode({ text: documentation === void 0 ? rendered.text : `${renderJsDoc(documentation, 0, printerOptions)}${printerOptions.newLine}${rendered.text}` }, printerOptions);
|
|
211522
211523
|
};
|
|
211523
211524
|
//#endregion
|
|
211524
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211525
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/ToolkitRenderer.js
|
|
211525
211526
|
/**
|
|
211526
211527
|
* @since 1.0.0
|
|
211527
211528
|
*/
|
|
@@ -211543,7 +211544,7 @@ declare function ${name}(${params}): Promise<${render(tool.successSchema)}>`);
|
|
|
211543
211544
|
}) });
|
|
211544
211545
|
};
|
|
211545
211546
|
//#endregion
|
|
211546
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211547
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/AgentExecutor.js
|
|
211547
211548
|
/**
|
|
211548
211549
|
* @since 1.0.0
|
|
211549
211550
|
*/
|
|
@@ -211697,7 +211698,7 @@ var QueueWriteStream = class extends Writable {
|
|
|
211697
211698
|
}
|
|
211698
211699
|
};
|
|
211699
211700
|
//#endregion
|
|
211700
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211701
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/ScriptExtraction.js
|
|
211701
211702
|
const stripWrappingCodeFence = (script) => {
|
|
211702
211703
|
const lines = script.split(/\r?\n/);
|
|
211703
211704
|
if (lines.length < 2) return script;
|
|
@@ -213080,7 +213081,7 @@ const applySpanTransformer = (transformer, response, options) => {
|
|
|
213080
213081
|
});
|
|
213081
213082
|
};
|
|
213082
213083
|
//#endregion
|
|
213083
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
213084
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/Agent.js
|
|
213084
213085
|
/**
|
|
213085
213086
|
* @since 1.0.0
|
|
213086
213087
|
*/
|
|
@@ -213230,7 +213231,7 @@ ${content}
|
|
|
213230
213231
|
const result = yield* executeScript(currentScript);
|
|
213231
213232
|
update(prompt, concat([{
|
|
213232
213233
|
role: modelConfig.supportsAssistantPrefill ? "assistant" : "user",
|
|
213233
|
-
content: `
|
|
213234
|
+
content: `Console output from executing javascript code:\n\n${result}`
|
|
213234
213235
|
}]));
|
|
213235
213236
|
currentScript = "";
|
|
213236
213237
|
}
|
|
@@ -213409,7 +213410,8 @@ ${options.agentsMd}
|
|
|
213409
213410
|
const generateSystemTools = (toolsDts, multi) => {
|
|
213410
213411
|
return `${multi ? generateSystemMulti(toolsDts) : generateSystemSingle(toolsDts)}
|
|
213411
213412
|
|
|
213412
|
-
|
|
213413
|
+
For example, here is how you would read a file. First you would respond with
|
|
213414
|
+
javascript code that uses the "readFile" function:
|
|
213413
213415
|
|
|
213414
213416
|
\`\`\`
|
|
213415
213417
|
const content = await readFile({
|
|
@@ -213420,10 +213422,10 @@ const content = await readFile({
|
|
|
213420
213422
|
console.log(JSON.parse(content))
|
|
213421
213423
|
\`\`\`
|
|
213422
213424
|
|
|
213423
|
-
And
|
|
213425
|
+
And then you will revieve back the console output:
|
|
213424
213426
|
|
|
213425
213427
|
\`\`\`
|
|
213426
|
-
|
|
213428
|
+
Console output from executing javascript code:
|
|
213427
213429
|
|
|
213428
213430
|
[22:44:53.054] INFO (#47): Calling "readFile" { path: 'package.json' }
|
|
213429
213431
|
{
|
|
@@ -213446,10 +213448,12 @@ const systemToolsCommon = (toolsDts) => `- Use \`console.log\` to print any outp
|
|
|
213446
213448
|
- Top level await is supported.
|
|
213447
213449
|
- AVOID passing scripts into the "bash" function, and instead write javascript.
|
|
213448
213450
|
- PREFER the "search" function over "rg" for finding information or code
|
|
213451
|
+
- Do as much work as possible in a single script, using \`Promise.all\` to run multiple functions in parallel.
|
|
213449
213452
|
- Variables **are not shared** between executions, so you must include all necessary code in each script you execute.
|
|
213450
213453
|
- Make use of the "delegate" tool to delegate exploration and small research tasks. You can delegate multiple tasks in parallel with Promise.all
|
|
213451
213454
|
|
|
213452
213455
|
**When you have fully completed your task**, call the "taskComplete" function with the final output.
|
|
213456
|
+
DO NOT output the final result without wrapping it with "taskComplete".
|
|
213453
213457
|
Make sure every detail of the task is done before calling "taskComplete".
|
|
213454
213458
|
|
|
213455
213459
|
You have the following functions available to you:
|
|
@@ -224220,7 +224224,7 @@ const transformToolCallParams = /* @__PURE__ */ fnUntraced(function* (tools, too
|
|
|
224220
224224
|
})));
|
|
224221
224225
|
});
|
|
224222
224226
|
//#endregion
|
|
224223
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
224227
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/CodexAuth.js
|
|
224224
224228
|
/**
|
|
224225
224229
|
* @since 1.0.0
|
|
224226
224230
|
*/
|
|
@@ -224440,7 +224444,7 @@ var CodexAuth = class CodexAuth extends Service$1()("clanka/CodexAuth") {
|
|
|
224440
224444
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(CodexAuth.layer));
|
|
224441
224445
|
};
|
|
224442
224446
|
//#endregion
|
|
224443
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
224447
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/Codex.js
|
|
224444
224448
|
/**
|
|
224445
224449
|
* @since 1.0.0
|
|
224446
224450
|
*/
|
|
@@ -225759,7 +225763,7 @@ const getUsageDetailNumber = (details, field) => {
|
|
|
225759
225763
|
return typeof value === "number" ? value : void 0;
|
|
225760
225764
|
};
|
|
225761
225765
|
//#endregion
|
|
225762
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
225766
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/CopilotAuth.js
|
|
225763
225767
|
/**
|
|
225764
225768
|
* @since 1.0.0
|
|
225765
225769
|
*/
|
|
@@ -225950,7 +225954,7 @@ var GithubCopilotAuth = class GithubCopilotAuth extends Service$1()("clanka/Gith
|
|
|
225950
225954
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(GithubCopilotAuth.layer));
|
|
225951
225955
|
};
|
|
225952
225956
|
//#endregion
|
|
225953
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
225957
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/Copilot.js
|
|
225954
225958
|
/**
|
|
225955
225959
|
* @since 1.0.0
|
|
225956
225960
|
*/
|
|
@@ -226373,7 +226377,7 @@ Object.defineProperties(createChalk.prototype, styles);
|
|
|
226373
226377
|
const chalk = createChalk();
|
|
226374
226378
|
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
226375
226379
|
//#endregion
|
|
226376
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
226380
|
+
//#region node_modules/.pnpm/clanka@0.1.11_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_f035d538562fa33a1854fb44b7d1653e/node_modules/clanka/dist/OutputFormatter.js
|
|
226377
226381
|
/**
|
|
226378
226382
|
* @since 1.0.0
|
|
226379
226383
|
*/
|
|
@@ -234123,6 +234127,21 @@ All steps must be done before the task can be considered complete.${options.task
|
|
|
234123
234127
|
5. **After ${options.gitFlow.requiresGithubPr ? "pushing" : "committing"}** your changes, update current task to reflect any changes in the task state.
|
|
234124
234128
|
- Rewrite the notes in the description to include only the key discoveries and information that could speed up future work on other tasks. Make sure to preserve important information such as specification file references.
|
|
234125
234129
|
- If you believe the task is complete, update the \`state\` to "in-review".`;
|
|
234130
|
+
const promptResearch = (options) => `Your job is to gather all the necessary information and details to complete the task described below. Do not make any code changes yet, your job is just to research and gather information.
|
|
234131
|
+
|
|
234132
|
+
In the final report:
|
|
234133
|
+
|
|
234134
|
+
- Include key file names, line numbers, and code snippets that are relevant to the task.
|
|
234135
|
+
- Any key discoveries that will help with implementing the task.
|
|
234136
|
+
- Any other information that will help speed up the implementation of the task.
|
|
234137
|
+
- You DO NOT need to add your report to the task description, just include it in your final output.
|
|
234138
|
+
|
|
234139
|
+
# Task details
|
|
234140
|
+
|
|
234141
|
+
ID: ${options.task.id}
|
|
234142
|
+
Title: ${options.task.title}
|
|
234143
|
+
|
|
234144
|
+
${options.task.description}`;
|
|
234126
234145
|
const promptReview = (options) => `A previous engineer has completed a task from the instructions below.
|
|
234127
234146
|
|
|
234128
234147
|
You job is to meticulously review their work to ensure it meets the task requirements,
|
|
@@ -234268,6 +234287,7 @@ Make sure to setup dependencies between the tasks using the \`blockedBy\` field.
|
|
|
234268
234287
|
promptChooseClanka,
|
|
234269
234288
|
prompt,
|
|
234270
234289
|
promptClanka,
|
|
234290
|
+
promptResearch,
|
|
234271
234291
|
promptReview,
|
|
234272
234292
|
promptReviewCustom,
|
|
234273
234293
|
promptTimeout,
|
|
@@ -234437,6 +234457,10 @@ const addOrUpdateProject = fnUntraced(function* (existing) {
|
|
|
234437
234457
|
selected: existing ? existing.gitFlow === "commit" : false
|
|
234438
234458
|
}]
|
|
234439
234459
|
});
|
|
234460
|
+
const researchAgent = yield* toggle({
|
|
234461
|
+
message: "Enable research agent?",
|
|
234462
|
+
initial: existing ? existing.researchAgent : true
|
|
234463
|
+
});
|
|
234440
234464
|
const reviewAgent = yield* toggle({
|
|
234441
234465
|
message: "Enable review agent?",
|
|
234442
234466
|
initial: existing ? existing.reviewAgent : true
|
|
@@ -234447,6 +234471,7 @@ const addOrUpdateProject = fnUntraced(function* (existing) {
|
|
|
234447
234471
|
concurrency,
|
|
234448
234472
|
targetBranch,
|
|
234449
234473
|
gitFlow,
|
|
234474
|
+
researchAgent,
|
|
234450
234475
|
reviewAgent
|
|
234451
234476
|
});
|
|
234452
234477
|
yield* Settings.set(allProjects, some$2(existing ? projects.map((p) => p.id === project.id ? project : p) : [...projects, project]));
|
|
@@ -234900,7 +234925,7 @@ const runClanka = fnUntraced(function* (options) {
|
|
|
234900
234925
|
yield* log$1(`Received steer message: ${message}`);
|
|
234901
234926
|
yield* agent.steer(message);
|
|
234902
234927
|
}, fromEffectDrain)), runDrain, forkScoped);
|
|
234903
|
-
yield* stream.pipe(runDrain, catchTag$1("AgentFinished", () =>
|
|
234928
|
+
return yield* stream.pipe(runDrain, as$1(""), catchTag$1("AgentFinished", (e) => succeed$3(e.summary)));
|
|
234904
234929
|
}, scoped$1, (effect, options) => provide$1(effect, layerLocal({
|
|
234905
234930
|
directory: options.directory,
|
|
234906
234931
|
tools: options.withChoose ? TaskChooseTools : TaskTools
|
|
@@ -234915,7 +234940,19 @@ const agentWorker = fnUntraced(function* (options) {
|
|
|
234915
234940
|
directory: worktree.directory,
|
|
234916
234941
|
model: options.preset.extraArgs.join(" "),
|
|
234917
234942
|
system: options.system,
|
|
234918
|
-
prompt: options.
|
|
234943
|
+
prompt: match$8(options.research, {
|
|
234944
|
+
onNone: () => options.prompt,
|
|
234945
|
+
onSome: (research) => make$7([{
|
|
234946
|
+
role: "user",
|
|
234947
|
+
content: options.prompt
|
|
234948
|
+
}, {
|
|
234949
|
+
role: "user",
|
|
234950
|
+
content: `You have already researched the above task, **AVOID DOING MORE RESEARCH** unless information is missing. Have a bias for action.
|
|
234951
|
+
Here is your research report:
|
|
234952
|
+
|
|
234953
|
+
${research}`
|
|
234954
|
+
}])
|
|
234955
|
+
}),
|
|
234919
234956
|
stallTimeout: options.stallTimeout,
|
|
234920
234957
|
steer: options.steer
|
|
234921
234958
|
});
|
|
@@ -235160,6 +235197,20 @@ const agentTimeout = fnUntraced(function* (options) {
|
|
|
235160
235197
|
}));
|
|
235161
235198
|
});
|
|
235162
235199
|
//#endregion
|
|
235200
|
+
//#region src/Agents/researcher.ts
|
|
235201
|
+
const agentResearcher = fnUntraced(function* (options) {
|
|
235202
|
+
const worktree = yield* Worktree;
|
|
235203
|
+
const promptGen = yield* PromptGen;
|
|
235204
|
+
if (options.preset.cliAgent.command) return none$4();
|
|
235205
|
+
return yield* runClanka({
|
|
235206
|
+
directory: worktree.directory,
|
|
235207
|
+
model: options.preset.extraArgs.join(" "),
|
|
235208
|
+
system: promptGen.systemClanka(options),
|
|
235209
|
+
prompt: promptGen.promptResearch({ task: options.task }),
|
|
235210
|
+
stallTimeout: options.stallTimeout
|
|
235211
|
+
}).pipe(asSome);
|
|
235212
|
+
});
|
|
235213
|
+
//#endregion
|
|
235163
235214
|
//#region src/commands/root.ts
|
|
235164
235215
|
const run = fnUntraced(function* (options) {
|
|
235165
235216
|
const projectId = yield* CurrentProjectId;
|
|
@@ -235223,6 +235274,13 @@ const run = fnUntraced(function* (options) {
|
|
|
235223
235274
|
}));
|
|
235224
235275
|
if (yield* gen(function* () {
|
|
235225
235276
|
registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Working({ issueId: taskId })));
|
|
235277
|
+
let researchResult = none$4();
|
|
235278
|
+
if (options.research) researchResult = yield* agentResearcher({
|
|
235279
|
+
task: chosenTask.prd,
|
|
235280
|
+
specsDirectory: options.specsDirectory,
|
|
235281
|
+
stallTimeout: options.stallTimeout,
|
|
235282
|
+
preset: taskPreset
|
|
235283
|
+
});
|
|
235226
235284
|
const promptGen = yield* PromptGen;
|
|
235227
235285
|
const instructions = taskPreset.cliAgent.command ? promptGen.prompt({
|
|
235228
235286
|
specsDirectory: options.specsDirectory,
|
|
@@ -235246,6 +235304,7 @@ const run = fnUntraced(function* (options) {
|
|
|
235246
235304
|
stallTimeout: options.stallTimeout,
|
|
235247
235305
|
preset: taskPreset,
|
|
235248
235306
|
prompt: instructions,
|
|
235307
|
+
research: researchResult,
|
|
235249
235308
|
steer
|
|
235250
235309
|
}).pipe(provideService$2(CurrentTaskRef, issueRef), catchStallInReview, withSpan("Main.agentWorker"))}`);
|
|
235251
235310
|
if (options.review) {
|
|
@@ -235297,7 +235356,8 @@ const runProject = fnUntraced(function* (options) {
|
|
|
235297
235356
|
specsDirectory: options.specsDirectory,
|
|
235298
235357
|
stallTimeout: options.stallTimeout,
|
|
235299
235358
|
runTimeout: options.runTimeout,
|
|
235300
|
-
review: options.project.reviewAgent
|
|
235359
|
+
review: options.project.reviewAgent,
|
|
235360
|
+
research: options.project.researchAgent
|
|
235301
235361
|
}).pipe(provide$1(options.project.gitFlow === "commit" ? GitFlowCommit : GitFlowPR, { local: true }), withWorkerState(options.project.id))), catchTags$1({
|
|
235302
235362
|
NoMoreWork(_error) {
|
|
235303
235363
|
if (isFinite) {
|
|
@@ -235359,10 +235419,10 @@ const commandRoot = make$49("lalph", {
|
|
|
235359
235419
|
const watchTaskState = fnUntraced(function* (options) {
|
|
235360
235420
|
return yield* toStreamResult(yield* AtomRegistry, currentIssuesAtom(yield* CurrentProjectId)).pipe(retry$1(forever$1), orDie, debounce(seconds(10)), runForEach((issues) => {
|
|
235361
235421
|
const issue = issues.find((entry) => entry.id === options.issueId);
|
|
235362
|
-
if (
|
|
235422
|
+
if (issue?.state === "in-progress" || issue?.state === "in-review") return void_$1;
|
|
235363
235423
|
return fail$6(new TaskStateChanged({
|
|
235364
235424
|
issueId: options.issueId,
|
|
235365
|
-
state: issue
|
|
235425
|
+
state: issue?.state ?? "missing"
|
|
235366
235426
|
}));
|
|
235367
235427
|
}), withSpan("Main.watchTaskState"));
|
|
235368
235428
|
});
|
|
@@ -235650,7 +235710,7 @@ const commandEdit = make$49("edit").pipe(withDescription("Open the selected proj
|
|
|
235650
235710
|
const commandSource = make$49("source").pipe(withDescription("Select the issue source to use (e.g. GitHub Issues or Linear). This applies to all projects."), withHandler(() => selectIssueSource), provide(Settings.layer));
|
|
235651
235711
|
//#endregion
|
|
235652
235712
|
//#region package.json
|
|
235653
|
-
var version = "0.3.
|
|
235713
|
+
var version = "0.3.63";
|
|
235654
235714
|
//#endregion
|
|
235655
235715
|
//#region src/commands/projects/ls.ts
|
|
235656
235716
|
const commandProjectsLs = make$49("ls").pipe(withDescription("List configured projects and how they run (enabled state, concurrency, branch, git flow, review agent)."), withHandler(fnUntraced(function* () {
|
|
@@ -235670,6 +235730,7 @@ const commandProjectsLs = make$49("ls").pipe(withDescription("List configured pr
|
|
|
235670
235730
|
console.log(` Concurrency: ${project.concurrency}`);
|
|
235671
235731
|
if (isSome(project.targetBranch)) console.log(` Target Branch: ${project.targetBranch.value}`);
|
|
235672
235732
|
console.log(` Git flow: ${project.gitFlow === "pr" ? "Pull Request" : "Commit"}`);
|
|
235733
|
+
console.log(` Research agent: ${project.researchAgent ? "Enabled" : "Disabled"}`);
|
|
235673
235734
|
console.log(` Review agent: ${project.reviewAgent ? "Enabled" : "Disabled"}`);
|
|
235674
235735
|
console.log("");
|
|
235675
235736
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lalph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.63",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"@linear/sdk": "^77.0.0",
|
|
30
30
|
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
|
31
31
|
"@octokit/types": "^16.0.0",
|
|
32
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
33
|
-
"clanka": "^0.1.
|
|
32
|
+
"@typescript/native-preview": "7.0.0-dev.20260314.1",
|
|
33
|
+
"clanka": "^0.1.11",
|
|
34
34
|
"concurrently": "^9.2.1",
|
|
35
35
|
"effect": "4.0.0-beta.31",
|
|
36
36
|
"husky": "^9.1.7",
|
|
37
|
-
"lint-staged": "^16.
|
|
37
|
+
"lint-staged": "^16.4.0",
|
|
38
38
|
"octokit": "^5.0.5",
|
|
39
39
|
"oxlint": "^1.55.0",
|
|
40
40
|
"prettier": "^3.8.1",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Duration, Effect, Option } from "effect"
|
|
2
|
+
import { PromptGen } from "../PromptGen.ts"
|
|
3
|
+
import { Worktree } from "../Worktree.ts"
|
|
4
|
+
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
5
|
+
import { runClanka } from "../Clanka.ts"
|
|
6
|
+
import type { PrdIssue } from "../domain/PrdIssue.ts"
|
|
7
|
+
|
|
8
|
+
export const agentResearcher = Effect.fnUntraced(function* (options: {
|
|
9
|
+
readonly task: PrdIssue
|
|
10
|
+
readonly specsDirectory: string
|
|
11
|
+
readonly stallTimeout: Duration.Duration
|
|
12
|
+
readonly preset: CliAgentPreset
|
|
13
|
+
}) {
|
|
14
|
+
const worktree = yield* Worktree
|
|
15
|
+
const promptGen = yield* PromptGen
|
|
16
|
+
|
|
17
|
+
// use clanka
|
|
18
|
+
if (options.preset.cliAgent.command) {
|
|
19
|
+
return Option.none<string>()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return yield* runClanka({
|
|
23
|
+
directory: worktree.directory,
|
|
24
|
+
model: options.preset.extraArgs.join(" "),
|
|
25
|
+
system: promptGen.systemClanka(options),
|
|
26
|
+
prompt: promptGen.promptResearch({
|
|
27
|
+
task: options.task,
|
|
28
|
+
}),
|
|
29
|
+
stallTimeout: options.stallTimeout,
|
|
30
|
+
}).pipe(Effect.asSome)
|
|
31
|
+
})
|
package/src/Agents/worker.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Duration, Effect, Path, pipe, Stream } from "effect"
|
|
1
|
+
import { Duration, Effect, Option, Path, pipe, Stream } from "effect"
|
|
2
2
|
import { ChildProcess } from "effect/unstable/process"
|
|
3
3
|
import { Worktree } from "../Worktree.ts"
|
|
4
4
|
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
5
5
|
import { runClanka } from "../Clanka.ts"
|
|
6
6
|
import { ExitCode } from "effect/unstable/process/ChildProcessSpawner"
|
|
7
|
+
import { Prompt } from "effect/unstable/ai"
|
|
7
8
|
|
|
8
9
|
export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
9
10
|
readonly stallTimeout: Duration.Duration
|
|
10
11
|
readonly preset: CliAgentPreset
|
|
11
12
|
readonly system?: string
|
|
12
13
|
readonly prompt: string
|
|
14
|
+
readonly research: Option.Option<string>
|
|
13
15
|
readonly steer?: Stream.Stream<string>
|
|
14
16
|
}) {
|
|
15
17
|
const pathService = yield* Path.Path
|
|
@@ -21,7 +23,23 @@ export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
|
21
23
|
directory: worktree.directory,
|
|
22
24
|
model: options.preset.extraArgs.join(" "),
|
|
23
25
|
system: options.system,
|
|
24
|
-
prompt: options.
|
|
26
|
+
prompt: Option.match(options.research, {
|
|
27
|
+
onNone: () => options.prompt,
|
|
28
|
+
onSome: (research) =>
|
|
29
|
+
Prompt.make([
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: options.prompt,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
role: "user",
|
|
36
|
+
content: `You have already researched the above task, **AVOID DOING MORE RESEARCH** unless information is missing. Have a bias for action.
|
|
37
|
+
Here is your research report:
|
|
38
|
+
|
|
39
|
+
${research}`,
|
|
40
|
+
},
|
|
41
|
+
]),
|
|
42
|
+
}),
|
|
25
43
|
stallTimeout: options.stallTimeout,
|
|
26
44
|
steer: options.steer,
|
|
27
45
|
})
|
package/src/Clanka.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { TaskChooseTools, TaskTools, TaskToolsHandlers } from "./TaskTools.ts"
|
|
|
4
4
|
import { ClankaModels } from "./ClankaModels.ts"
|
|
5
5
|
import { withStallTimeout } from "./shared/stream.ts"
|
|
6
6
|
import { NodeHttpClient } from "@effect/platform-node"
|
|
7
|
+
import type { Prompt } from "effect/unstable/ai"
|
|
7
8
|
|
|
8
9
|
export const ClankaMuxerLayer = Layer.effectDiscard(
|
|
9
10
|
Effect.gen(function* () {
|
|
@@ -17,7 +18,7 @@ export const runClanka = Effect.fnUntraced(
|
|
|
17
18
|
function* (options: {
|
|
18
19
|
readonly directory: string
|
|
19
20
|
readonly model: string
|
|
20
|
-
readonly prompt:
|
|
21
|
+
readonly prompt: Prompt.RawInput
|
|
21
22
|
readonly system?: string | undefined
|
|
22
23
|
readonly stallTimeout?: Duration.Input | undefined
|
|
23
24
|
readonly steer?: Stream.Stream<string> | undefined
|
|
@@ -54,9 +55,10 @@ export const runClanka = Effect.fnUntraced(
|
|
|
54
55
|
)
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
yield* stream.pipe(
|
|
58
|
+
return yield* stream.pipe(
|
|
58
59
|
Stream.runDrain,
|
|
59
|
-
Effect.
|
|
60
|
+
Effect.as(""),
|
|
61
|
+
Effect.catchTag("AgentFinished", (e) => Effect.succeed(e.summary)),
|
|
60
62
|
)
|
|
61
63
|
},
|
|
62
64
|
Effect.scoped,
|
package/src/Projects.ts
CHANGED
|
@@ -123,6 +123,11 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
|
|
|
123
123
|
},
|
|
124
124
|
] as const,
|
|
125
125
|
})
|
|
126
|
+
|
|
127
|
+
const researchAgent = yield* Prompt.toggle({
|
|
128
|
+
message: "Enable research agent?",
|
|
129
|
+
initial: existing ? existing.researchAgent : true,
|
|
130
|
+
})
|
|
126
131
|
const reviewAgent = yield* Prompt.toggle({
|
|
127
132
|
message: "Enable review agent?",
|
|
128
133
|
initial: existing ? existing.reviewAgent : true,
|
|
@@ -134,6 +139,7 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
|
|
|
134
139
|
concurrency,
|
|
135
140
|
targetBranch,
|
|
136
141
|
gitFlow,
|
|
142
|
+
researchAgent,
|
|
137
143
|
reviewAgent,
|
|
138
144
|
})
|
|
139
145
|
yield* Settings.set(
|
package/src/PromptGen.ts
CHANGED
|
@@ -254,6 +254,24 @@ All steps must be done before the task can be considered complete.${
|
|
|
254
254
|
- Rewrite the notes in the description to include only the key discoveries and information that could speed up future work on other tasks. Make sure to preserve important information such as specification file references.
|
|
255
255
|
- If you believe the task is complete, update the \`state\` to "in-review".`
|
|
256
256
|
|
|
257
|
+
const promptResearch = (options: {
|
|
258
|
+
readonly task: PrdIssue
|
|
259
|
+
}) => `Your job is to gather all the necessary information and details to complete the task described below. Do not make any code changes yet, your job is just to research and gather information.
|
|
260
|
+
|
|
261
|
+
In the final report:
|
|
262
|
+
|
|
263
|
+
- Include key file names, line numbers, and code snippets that are relevant to the task.
|
|
264
|
+
- Any key discoveries that will help with implementing the task.
|
|
265
|
+
- Any other information that will help speed up the implementation of the task.
|
|
266
|
+
- You DO NOT need to add your report to the task description, just include it in your final output.
|
|
267
|
+
|
|
268
|
+
# Task details
|
|
269
|
+
|
|
270
|
+
ID: ${options.task.id}
|
|
271
|
+
Title: ${options.task.title}
|
|
272
|
+
|
|
273
|
+
${options.task.description}`
|
|
274
|
+
|
|
257
275
|
const promptReview = (options: {
|
|
258
276
|
readonly prompt: string
|
|
259
277
|
readonly gitFlow: GitFlow["Service"]
|
|
@@ -431,6 +449,7 @@ Make sure to setup dependencies between the tasks using the \`blockedBy\` field.
|
|
|
431
449
|
promptChooseClanka,
|
|
432
450
|
prompt,
|
|
433
451
|
promptClanka,
|
|
452
|
+
promptResearch,
|
|
434
453
|
promptReview,
|
|
435
454
|
promptReviewCustom,
|
|
436
455
|
promptTimeout,
|
|
@@ -35,6 +35,9 @@ export const commandProjectsLs = Command.make("ls").pipe(
|
|
|
35
35
|
console.log(
|
|
36
36
|
` Git flow: ${project.gitFlow === "pr" ? "Pull Request" : "Commit"}`,
|
|
37
37
|
)
|
|
38
|
+
console.log(
|
|
39
|
+
` Research agent: ${project.researchAgent ? "Enabled" : "Disabled"}`,
|
|
40
|
+
)
|
|
38
41
|
console.log(
|
|
39
42
|
` Review agent: ${project.reviewAgent ? "Enabled" : "Disabled"}`,
|
|
40
43
|
)
|
package/src/commands/root.ts
CHANGED
|
@@ -55,6 +55,7 @@ import type { PrdIssue } from "../domain/PrdIssue.ts"
|
|
|
55
55
|
import { CurrentTaskRef } from "../TaskTools.ts"
|
|
56
56
|
import type { OutputFormatter } from "clanka"
|
|
57
57
|
import { ClankaMuxerLayer } from "../Clanka.ts"
|
|
58
|
+
import { agentResearcher } from "../Agents/researcher.ts"
|
|
58
59
|
|
|
59
60
|
// Main iteration run logic
|
|
60
61
|
|
|
@@ -65,6 +66,7 @@ const run = Effect.fnUntraced(
|
|
|
65
66
|
readonly specsDirectory: string
|
|
66
67
|
readonly stallTimeout: Duration.Duration
|
|
67
68
|
readonly runTimeout: Duration.Duration
|
|
69
|
+
readonly research: boolean
|
|
68
70
|
readonly review: boolean
|
|
69
71
|
}): Effect.fn.Return<
|
|
70
72
|
void,
|
|
@@ -212,6 +214,16 @@ const run = Effect.fnUntraced(
|
|
|
212
214
|
s.transitionTo(WorkerStatus.Working({ issueId: taskId })),
|
|
213
215
|
)
|
|
214
216
|
|
|
217
|
+
let researchResult = Option.none<string>()
|
|
218
|
+
if (options.research) {
|
|
219
|
+
researchResult = yield* agentResearcher({
|
|
220
|
+
task: chosenTask.prd,
|
|
221
|
+
specsDirectory: options.specsDirectory,
|
|
222
|
+
stallTimeout: options.stallTimeout,
|
|
223
|
+
preset: taskPreset,
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
215
227
|
const promptGen = yield* PromptGen
|
|
216
228
|
const instructions = taskPreset.cliAgent.command
|
|
217
229
|
? promptGen.prompt({
|
|
@@ -243,6 +255,7 @@ const run = Effect.fnUntraced(
|
|
|
243
255
|
stallTimeout: options.stallTimeout,
|
|
244
256
|
preset: taskPreset,
|
|
245
257
|
prompt: instructions,
|
|
258
|
+
research: researchResult,
|
|
246
259
|
steer,
|
|
247
260
|
}).pipe(
|
|
248
261
|
Effect.provideService(CurrentTaskRef, issueRef),
|
|
@@ -352,6 +365,7 @@ const runProject = Effect.fnUntraced(
|
|
|
352
365
|
stallTimeout: options.stallTimeout,
|
|
353
366
|
runTimeout: options.runTimeout,
|
|
354
367
|
review: options.project.reviewAgent,
|
|
368
|
+
research: options.project.researchAgent,
|
|
355
369
|
}).pipe(
|
|
356
370
|
Effect.provide(
|
|
357
371
|
options.project.gitFlow === "commit" ? GitFlowCommit : GitFlowPR,
|
|
@@ -522,17 +536,13 @@ const watchTaskState = Effect.fnUntraced(function* (options: {
|
|
|
522
536
|
Stream.debounce(Duration.seconds(10)),
|
|
523
537
|
Stream.runForEach((issues) => {
|
|
524
538
|
const issue = issues.find((entry) => entry.id === options.issueId)
|
|
525
|
-
if (
|
|
526
|
-
!issue ||
|
|
527
|
-
issue.state === "in-progress" ||
|
|
528
|
-
issue.state === "in-review"
|
|
529
|
-
) {
|
|
539
|
+
if (issue?.state === "in-progress" || issue?.state === "in-review") {
|
|
530
540
|
return Effect.void
|
|
531
541
|
}
|
|
532
542
|
return Effect.fail(
|
|
533
543
|
new TaskStateChanged({
|
|
534
544
|
issueId: options.issueId,
|
|
535
|
-
state: issue
|
|
545
|
+
state: issue?.state ?? "missing",
|
|
536
546
|
}),
|
|
537
547
|
)
|
|
538
548
|
}),
|
package/src/domain/Project.ts
CHANGED
|
@@ -9,5 +9,6 @@ export class Project extends Schema.Class<Project>("lalph/Project")({
|
|
|
9
9
|
targetBranch: Schema.Option(Schema.String),
|
|
10
10
|
concurrency: Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)),
|
|
11
11
|
gitFlow: Schema.Literals(["pr", "commit"]),
|
|
12
|
+
researchAgent: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)),
|
|
12
13
|
reviewAgent: Schema.Boolean,
|
|
13
14
|
}) {}
|