@rse/ase 2.0.6 → 2.0.7
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/dst/ase-agent-definition-api.d.ts +2 -0
- package/dst/ase-agent-definition-core.js +24 -3
- package/dst/ase-agent-fleet.js +2 -1
- package/dst/ase-agent-runtime-engine.js +22 -4
- package/dst/ase-agent-runtime-tool.js +10 -8
- package/dst/ase-agent-runtime.js +8 -4
- package/dst/ase-man-catalog.js +1 -1
- package/dst/ase-task-store-plugin-gitea.js +3 -3
- package/dst/man/ase-agent-adhoc.md +25 -6
- package/dst/man/ase-agent-condenser.md +7 -0
- package/dst/man/ase-agent-editor.md +7 -0
- package/dst/man/ase-agent-estimator.md +7 -0
- package/dst/man/ase-agent-fleet.md +7 -4
- package/dst/man/ase-agent-implementer.md +7 -0
- package/dst/man/ase-agent-integrator.md +7 -0
- package/dst/man/ase-agent-qualifier.md +7 -0
- package/dst/man/ase-agent-rebooter.md +7 -0
- package/dst/man/ase-agent-researcher.md +7 -0
- package/package.json +5 -5
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/meta/ase-common-task.md +9 -1
- package/plugin/meta/ase-control.md +14 -0
- package/plugin/meta/ase-format-specbook.yaml +9 -9
- package/plugin/meta/ase-skill.md +7 -0
- package/plugin/mods/ase-mods-help-hint.ts +1 -1
- package/plugin/skills/ase-code-edit/SKILL.md +53 -16
- package/plugin/skills/ase-code-edit/help.md +26 -13
- package/plugin/skills/ase-code-lint/SKILL.md +7 -3
- package/plugin/skills/ase-help-intent/data.md +170 -28
- package/plugin/skills/ase-help-skill/catalog.md +1 -0
- package/plugin/skills/ase-meta-workflow/workflow.txt +2 -0
- package/plugin/skills/ase-repo-changelog/SKILL.md +29 -10
- package/plugin/skills/ase-repo-changelog/help.md +5 -1
- package/plugin/skills/ase-repo-commit/SKILL.md +4 -1
- package/plugin/skills/ase-repo-dissect/help.md +2 -1
- package/plugin/skills/ase-repo-stage/SKILL.md +459 -0
- package/plugin/skills/ase-repo-stage/help.md +120 -0
- package/plugin/skills/ase-spec-edit/SKILL.md +20 -12
- package/plugin/skills/ase-spec-edit/help.md +22 -14
|
@@ -18,6 +18,7 @@ export interface AgentDefinition {
|
|
|
18
18
|
lifecycle?: Many<string>;
|
|
19
19
|
serial?: boolean;
|
|
20
20
|
unclaimed?: boolean;
|
|
21
|
+
model?: string;
|
|
21
22
|
state?: {
|
|
22
23
|
incoming?: Many<string>;
|
|
23
24
|
activity?: string;
|
|
@@ -175,6 +176,7 @@ export interface AgentHooks {
|
|
|
175
176
|
ready?: (task: AgentHookTask, ctx: AgentHookContext) => Async<boolean | string>;
|
|
176
177
|
prepare?: (task: AgentHookTask, job: AgentHookJob, ctx: AgentHookContext) => Async<void>;
|
|
177
178
|
prompt?: (task: AgentHookTask, prompt: AgentHookPrompt, job: AgentHookJob, ctx: AgentHookContext) => Async<AgentHookPrompt | string | undefined>;
|
|
179
|
+
model?: (task: AgentHookTask, model: string, job: AgentHookJob, ctx: AgentHookContext) => Async<string | undefined>;
|
|
178
180
|
verdict?: (task: AgentHookTask, result: AgentHookResult, ctx: AgentHookContext) => Async<string | undefined>;
|
|
179
181
|
success?: (task: AgentHookTask, result: AgentHookResult, ctx: AgentHookContext) => Async<boolean | string>;
|
|
180
182
|
settle?: (task: AgentHookTask, outcome: AgentHookOutcome, ctx: AgentHookContext) => Async<AgentHookSettlement | undefined>;
|
|
@@ -92,6 +92,9 @@ export const definitionOptions = [
|
|
|
92
92
|
opt("unclaimed", "flag", "", "process the tasks of the incoming states (each adapted onto the " +
|
|
93
93
|
"task lifecycle model) without claiming them, independent of their assignee and predecessors, " +
|
|
94
94
|
"and without ever changing their status and assignee (for \"phase\" only)"),
|
|
95
|
+
opt("model", "value", "model", "model of the agent tool: a model for all tasks, or comma-separated " +
|
|
96
|
+
"\"<size>=<model>\" pairs per \"Effort:\" size (\"XS\", \"S\", \"M\", \"L\", \"XL\", or \"*\" for all other tasks) " +
|
|
97
|
+
"(default: the default model of the agent tool)"),
|
|
95
98
|
opt("params", "list", "name=value", "value of a parameter declared by the definition (repeatable)"),
|
|
96
99
|
opt("state-incoming", "list", "state", "state of the tasks to claim (mandatory for \"phase\", " +
|
|
97
100
|
"repeatable with \"--unclaimed\" or \"--state-activity\" only)"),
|
|
@@ -272,7 +275,7 @@ export const flattenDefinition = (data, where) => {
|
|
|
272
275
|
return flat;
|
|
273
276
|
};
|
|
274
277
|
/* the names of the hooks of a definition (see "AgentHooks") */
|
|
275
|
-
const hookNames = ["start", "order", "passes", "ready", "prepare", "prompt", "verdict", "success", "settle", "finish", "stop"];
|
|
278
|
+
const hookNames = ["start", "order", "passes", "ready", "prepare", "prompt", "model", "verdict", "success", "settle", "finish", "stop"];
|
|
276
279
|
/* normalize the parameter declarations <spec> of a definition (see "AgentParam"),
|
|
277
280
|
where <where> names the definition in errors */
|
|
278
281
|
const definitionParams = (spec, where) => {
|
|
@@ -741,6 +744,24 @@ export const resolveDefinition = async (opts, name) => {
|
|
|
741
744
|
if (loaded.hooks.passes !== undefined)
|
|
742
745
|
fail("definition", "hook \"passes\" is not for \"--unclaimed\" (as an unclaimed task never waits for its predecessors)");
|
|
743
746
|
}
|
|
747
|
+
/* the model of the agent tool: a plain model (for all tasks, as size "*"),
|
|
748
|
+
or the models per "Effort:" size, where none means the default of the tool */
|
|
749
|
+
const modelSpec = str("model").trim();
|
|
750
|
+
const sizes = {};
|
|
751
|
+
if (modelSpec !== "" && !modelSpec.includes("="))
|
|
752
|
+
sizes["*"] = modelSpec;
|
|
753
|
+
else if (modelSpec !== "") {
|
|
754
|
+
for (const pair of modelSpec.split(",").map((item) => item.trim())) {
|
|
755
|
+
const m = /^(XS|S|M|L|XL|\*)=(\S+)$/.exec(pair);
|
|
756
|
+
if (m === null)
|
|
757
|
+
fail("model", `invalid pair "${pair}" (expected "<size>=<model>" with size "XS", "S", "M", "L", "XL", or "*")`);
|
|
758
|
+
else if (Object.hasOwn(sizes, m[1]))
|
|
759
|
+
fail("model", `size "${m[1]}" given twice`);
|
|
760
|
+
else
|
|
761
|
+
sizes[m[1]] = m[2];
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const model = { spec: modelSpec, sizes };
|
|
744
765
|
/* whether a verdict is determined (by "--verdict-label" or the hook "verdict") */
|
|
745
766
|
const verdicting = has("verdict-label") || loaded.hooks.verdict !== undefined;
|
|
746
767
|
/* the states (see "resolveStates") */
|
|
@@ -821,10 +842,10 @@ export const resolveDefinition = async (opts, name) => {
|
|
|
821
842
|
hence the prompt of the request), resp. uses them optionally by "{prompt}" used only
|
|
822
843
|
within the conditional "{?prompt:...}", else ignores them */
|
|
823
844
|
const consumes = type === "request" && (template.required.has("prompt")
|
|
824
|
-
|| ["prepare", "prompt", "finish"].some((hook) => loaded.hooks[hook] !== undefined)) ? "required" :
|
|
845
|
+
|| ["prepare", "prompt", "model", "finish"].some((hook) => loaded.hooks[hook] !== undefined)) ? "required" :
|
|
825
846
|
type === "request" && template.names.has("prompt") ? "optional" : "ignored";
|
|
826
847
|
return {
|
|
827
|
-
name, title, description, type, workdir, lifecycles, unclaimed,
|
|
848
|
+
name, title, description, type, workdir, lifecycles, unclaimed, model,
|
|
828
849
|
serial: flag("serial"),
|
|
829
850
|
state: { incoming, activity, success, failure, phase, passed, verdict: verdicts },
|
|
830
851
|
tag: {
|
package/dst/ase-agent-fleet.js
CHANGED
|
@@ -45,7 +45,7 @@ const logLevelRe = /^([^|]*\| [^:]+: \[[^\]]+\]: )\[(ERROR|WARNING|INFO|DEBUG)\]
|
|
|
45
45
|
agents, and applied to an agent only if it supports them) */
|
|
46
46
|
const fleetKeys = ["foreground"];
|
|
47
47
|
const relayKeys = ["address", "port", "token", "cors", "tls-cert", "tls-key"];
|
|
48
|
-
const defaultKeys = ["tool", "parallel", "timeout", "repo", "tempdir", "agent-relay"];
|
|
48
|
+
const defaultKeys = ["tool", "model", "parallel", "timeout", "repo", "tempdir", "agent-relay"];
|
|
49
49
|
/* the options not allowed in the section of an agent, as the fleet decides on them */
|
|
50
50
|
const deniedKeys = ["name", "one-shot", "foreground", "help"];
|
|
51
51
|
/* the state of the planned tasks per task lifecycle model, as estimated by the estimator */
|
|
@@ -76,6 +76,7 @@ const initConfig = (tool, lifecycle) => [
|
|
|
76
76
|
# (each applied only to the agents supporting it, where an empty value omits it)
|
|
77
77
|
default:
|
|
78
78
|
tool: ${tool.padEnd(16)}# agent tool ("claude", "copilot", or "codex")
|
|
79
|
+
#model: <model> # model of the agent tool (or "<size>=<model>" pairs per "Effort:" size)
|
|
79
80
|
parallel: 1 # maximum number of tasks processed in parallel
|
|
80
81
|
timeout: 60m # maximum duration of processing a task (<number><unit> with unit "s", "m", or "h")
|
|
81
82
|
#repo: <url> # Git repository to clone temporarily for the tasks without "worktree"
|
|
@@ -45,6 +45,15 @@ const promptOf = (value, configured) => {
|
|
|
45
45
|
}
|
|
46
46
|
throw new Error("invalid prompt (expected a string, \"{ text }\", or \"{ skill, args }\")");
|
|
47
47
|
};
|
|
48
|
+
/* the model returned by the hook "model", validated, where undefined
|
|
49
|
+
keeps the configured model <configured> */
|
|
50
|
+
const modelOf = (value, configured) => {
|
|
51
|
+
if (value === undefined)
|
|
52
|
+
return configured;
|
|
53
|
+
else if (typeof value !== "string")
|
|
54
|
+
throw new Error("invalid model (expected a string)");
|
|
55
|
+
return value.trim();
|
|
56
|
+
};
|
|
48
57
|
/* whether a record of an agent of a definition succeeded (where a missing one counts as failure) */
|
|
49
58
|
const recordSuccess = (record) => record !== undefined && record.fixed === "" && record.checks.every((check) => check.ok);
|
|
50
59
|
/* escape a text for its literal use in a regular expression */
|
|
@@ -331,7 +340,7 @@ class DefinedCore {
|
|
|
331
340
|
}
|
|
332
341
|
/* prepare the job of a task in its work <work>: render the prompt (with the request
|
|
333
342
|
prompt <prompt> of a request agent), run the preparing commands, and run the hooks
|
|
334
|
-
"prepare" and "
|
|
343
|
+
"prepare", "prompt", and "model", where the work is cleaned up again on a failure, and where
|
|
335
344
|
<changed> decides preliminarily whether the plan content of a request agent changed */
|
|
336
345
|
async prepare(task, log, work, prompt, changed) {
|
|
337
346
|
try {
|
|
@@ -374,7 +383,7 @@ class DefinedCore {
|
|
|
374
383
|
throw err;
|
|
375
384
|
}
|
|
376
385
|
}
|
|
377
|
-
/* run the hooks "prepare" and "
|
|
386
|
+
/* run the hooks "prepare", "prompt", and "model", where a failed hook fails the processing */
|
|
378
387
|
const job = Object.freeze({
|
|
379
388
|
dir: work.cwd,
|
|
380
389
|
dirs: Object.freeze([...work.dirs]),
|
|
@@ -392,7 +401,7 @@ class DefinedCore {
|
|
|
392
401
|
throw new Error(`agent: hook "${name}" failed: ${reason(err)}`, { cause: err });
|
|
393
402
|
}
|
|
394
403
|
};
|
|
395
|
-
const { prepare: prepareHook, prompt: promptHook } = this.def.hooks;
|
|
404
|
+
const { prepare: prepareHook, prompt: promptHook, model: modelHook } = this.def.hooks;
|
|
396
405
|
if (prepareHook !== undefined)
|
|
397
406
|
await hooked("prepare", async () => prepareHook(this.task(task), job, ctx));
|
|
398
407
|
let spec = this.def.prompt.skill !== "" ?
|
|
@@ -401,10 +410,17 @@ class DefinedCore {
|
|
|
401
410
|
const configured = Object.freeze(spec);
|
|
402
411
|
spec = await hooked("prompt", async () => promptOf(await promptHook(this.task(task), configured, job, ctx), configured));
|
|
403
412
|
}
|
|
413
|
+
const { sizes } = this.def.model;
|
|
414
|
+
let model = sizes[TaskFormat.parseEffort(task.keys.get("Effort") ?? "")?.size ?? "*"] ?? sizes["*"] ?? "";
|
|
415
|
+
if (modelHook !== undefined) {
|
|
416
|
+
const configured = model;
|
|
417
|
+
model = await hooked("model", async () => modelOf(await modelHook(this.task(task), configured, job, ctx), configured));
|
|
418
|
+
}
|
|
404
419
|
return {
|
|
405
420
|
...("skill" in spec ?
|
|
406
421
|
{ cmd: `${spec.skill}${spec.args !== "" ? ` ${spec.args}` : ""}` } :
|
|
407
422
|
{ prompt: spec.text }),
|
|
423
|
+
model,
|
|
408
424
|
cwd: work.cwd,
|
|
409
425
|
dirs: work.dirs,
|
|
410
426
|
finish: (log, result) => this.finish(task, log, result, work, job, env, before, changed),
|
|
@@ -714,6 +730,7 @@ class DefinedPhaseAgent extends PhaseAgent {
|
|
|
714
730
|
};
|
|
715
731
|
this.presenceTitle = def.title;
|
|
716
732
|
this.presenceDesc = def.description;
|
|
733
|
+
this.modelSpec = def.model.spec;
|
|
717
734
|
this.assigned = def.assign.required;
|
|
718
735
|
this.finishing = def.finish.commit || def.finish.success !== "" || def.workdir === "target"
|
|
719
736
|
|| def.hooks.finish !== undefined;
|
|
@@ -858,6 +875,7 @@ class DefinedRequestAgent extends RequestAgent {
|
|
|
858
875
|
this.presencePrompt = def.request.prompt;
|
|
859
876
|
this.presenceTitle = def.title;
|
|
860
877
|
this.presenceDesc = def.description;
|
|
878
|
+
this.modelSpec = def.model.spec;
|
|
861
879
|
this.serial = def.serial;
|
|
862
880
|
this.worktree = def.workdir !== "project";
|
|
863
881
|
this.lifecycles = def.lifecycles;
|
|
@@ -950,7 +968,7 @@ export class DefinedAgent extends Agent {
|
|
|
950
968
|
for (const option of definitionOptions) {
|
|
951
969
|
if (option.key === "definition" && !definition)
|
|
952
970
|
continue;
|
|
953
|
-
const flags = (option.key === "definition" ? "-D, " : "") + `--${option.key}` +
|
|
971
|
+
const flags = (option.key === "definition" ? "-D, " : option.key === "model" ? "-M, " : "") + `--${option.key}` +
|
|
954
972
|
(option.kind !== "flag" ? ` <${option.arg}>` : "");
|
|
955
973
|
if (option.kind === "list")
|
|
956
974
|
cmd.option(flags, option.desc, (value, prev) => [...(prev ?? []), value]);
|
|
@@ -8,20 +8,22 @@ import { stripVTControlCharacters } from "node:util";
|
|
|
8
8
|
of the task (as an agent message can be huge, e.g. the rendering of the whole task plan,
|
|
9
9
|
which would otherwise be fed back into the next rendering of the task plan) */
|
|
10
10
|
const TEXT_MAX = 20;
|
|
11
|
+
/* the "--model" option of all tools for the model <model> (none for the default model) */
|
|
12
|
+
const modelArgs = (model) => model !== "" ? ["--model", model] : [];
|
|
11
13
|
/* the per-tool headless invocation of the rendered prompt <prompt> with access to the
|
|
12
|
-
additional directories <add> (the "--add-dir" options)
|
|
13
|
-
where risky actions are denied or automatically reviewed instead of being prompted for
|
|
14
|
+
additional directories <add> (the "--add-dir" options) and the model <model>, streaming JSONL
|
|
15
|
+
events, where risky actions are denied or automatically reviewed instead of being prompted for
|
|
14
16
|
(the variadic "--add-dir" of Claude has to precede the other options to not consume the prompt) */
|
|
15
17
|
export const toolArgs = {
|
|
16
|
-
"claude": (prompt, add) => [
|
|
17
|
-
...add, "-p", "--output-format", "stream-json", "--verbose", "--disallowedTools", "AskUserQuestion",
|
|
18
|
+
"claude": (prompt, add, model) => [
|
|
19
|
+
...add, ...modelArgs(model), "-p", "--output-format", "stream-json", "--verbose", "--disallowedTools", "AskUserQuestion",
|
|
18
20
|
"--permission-mode", "auto", "--permission-prompts", "none", prompt
|
|
19
21
|
],
|
|
20
|
-
"copilot": (prompt, add) => [
|
|
21
|
-
...add, "--allow-all-tools", "--no-ask-user", "--no-color", "--output-format", "json", "-p", prompt
|
|
22
|
+
"copilot": (prompt, add, model) => [
|
|
23
|
+
...add, ...modelArgs(model), "--allow-all-tools", "--no-ask-user", "--no-color", "--output-format", "json", "-p", prompt
|
|
22
24
|
],
|
|
23
|
-
"codex": (prompt, add) => [
|
|
24
|
-
"exec", ...add, "--json", "--approve-for-me", "--color", "never", prompt
|
|
25
|
+
"codex": (prompt, add, model) => [
|
|
26
|
+
"exec", ...add, ...modelArgs(model), "--json", "--approve-for-me", "--color", "never", prompt
|
|
25
27
|
]
|
|
26
28
|
};
|
|
27
29
|
/* the per-tool rendering of the invocation of the skill <skill> with the arguments <args>:
|
package/dst/ase-agent-runtime.js
CHANGED
|
@@ -145,6 +145,8 @@ export class Agent {
|
|
|
145
145
|
/* the title and the description of the operation of the agent, as announced in its presence (default: none) */
|
|
146
146
|
presenceTitle = "";
|
|
147
147
|
presenceDesc = "";
|
|
148
|
+
/* the configured model of the agent tool, as shown in the start log line (default: none) */
|
|
149
|
+
modelSpec = "";
|
|
148
150
|
/* whether tasks are processed serially only (clamping "--parallel" to 1, and
|
|
149
151
|
refusing multiple agents of the kind in a fleet, see "ase agent fleet") */
|
|
150
152
|
serial = false;
|
|
@@ -840,7 +842,8 @@ export class Agent {
|
|
|
840
842
|
const cli = toolSpecs[tool].cli;
|
|
841
843
|
const cmd = job.cmd ?? "";
|
|
842
844
|
const i = cmd.indexOf(" ");
|
|
843
|
-
const
|
|
845
|
+
const model = job.model ?? "";
|
|
846
|
+
const args = toolArgs[tool](job.prompt ?? skillPrompt(tool, i < 0 ? cmd : cmd.slice(0, i), i < 0 ? "" : cmd.slice(i + 1)), [...new Set(job.dirs ?? [])].filter((dir) => dir !== cwd).flatMap((dir) => ["--add-dir", dir]), model);
|
|
844
847
|
await log("info", `running: ${cli} ${args.map((arg) => arg.includes(" ") ? `"${arg}"` : arg).join(" ")}`);
|
|
845
848
|
const started = Date.now();
|
|
846
849
|
const costs = { costToken: null, costUSD: null, cread: 0, cwrite: 0, input: 0, apiMs: null };
|
|
@@ -881,7 +884,7 @@ export class Agent {
|
|
|
881
884
|
this.presence?.used(usage);
|
|
882
885
|
/* book the usage onto the task, if the AI usage accounting is enabled ("telemetry.enabled"),
|
|
883
886
|
(the AI request time falling back to the wall time and an unreported cost to the price
|
|
884
|
-
table entry of the
|
|
887
|
+
table entry of the given model, else of the tool), without any human time and costs,
|
|
885
888
|
as the headless agent tool runs unattended; the times are booked in rounded minutes,
|
|
886
889
|
with the (signed) rounding remainder carried over to the next booking onto the task,
|
|
887
890
|
where a failed booking is only reported */
|
|
@@ -894,7 +897,8 @@ export class Agent {
|
|
|
894
897
|
if (cost === null) {
|
|
895
898
|
const cfg = new Config("config", configSchema, this.log);
|
|
896
899
|
cfg.read();
|
|
897
|
-
|
|
900
|
+
const prices = parsePrices(String(cfg.get("telemetry.prices.ai") ?? ""));
|
|
901
|
+
cost = tokenCost(modelPrice(prices, model !== "" && prices.has(model) ? model : tool), tokens);
|
|
898
902
|
}
|
|
899
903
|
const carry = this.unbooked.get(taskId) ?? { aiMs: 0, realMs: 0 };
|
|
900
904
|
const aiMs = carry.aiMs + (costs.apiMs ?? walltimeMs);
|
|
@@ -1250,7 +1254,7 @@ export class Agent {
|
|
|
1250
1254
|
if (this.repo !== "")
|
|
1251
1255
|
await this.cloneRepo();
|
|
1252
1256
|
await this.write("info", this.name, `observing ${this.observing()} ` +
|
|
1253
|
-
`(tool: ${tool}, parallel: ${parallel}, timeout: ${this.timeoutSpec}${this.oneShot ? ", one-shot" : ""})`);
|
|
1257
|
+
`(tool: ${tool}${this.modelSpec !== "" ? `, model: ${this.modelSpec}` : ""}, parallel: ${parallel}, timeout: ${this.timeoutSpec}${this.oneShot ? ", one-shot" : ""})`);
|
|
1254
1258
|
let finished = false;
|
|
1255
1259
|
let failure = null;
|
|
1256
1260
|
while (!abort.signal.aborted && !finished) {
|
package/dst/ase-man-catalog.js
CHANGED
|
@@ -24,7 +24,7 @@ const skillGroups = [
|
|
|
24
24
|
["SPEC", ["ase-spec-lint", "ase-spec-edit", "ase-spec-activate"]],
|
|
25
25
|
["CODE", ["ase-code-edit", "ase-code-analyze", "ase-code-insight", "ase-code-explain", "ase-code-lint"]],
|
|
26
26
|
["REPO", ["ase-repo-review", "ase-repo-diff", "ase-repo-changelog", "ase-repo-commit",
|
|
27
|
-
"ase-repo-dissect", "ase-repo-merge", "ase-repo-resolve"]],
|
|
27
|
+
"ase-repo-dissect", "ase-repo-stage", "ase-repo-merge", "ase-repo-resolve"]],
|
|
28
28
|
["SYNC", ["ase-sync-reconcile", "ase-sync-import", "ase-sync-export"]],
|
|
29
29
|
["TASK: MANAGE", ["ase-task-list", "ase-task-rename", "ase-task-delete"]],
|
|
30
30
|
["TASK: HANDLE", ["ase-task-id", "ase-task-status", "ase-task-assign"]],
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
4
4
|
** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
|
|
5
5
|
*/
|
|
6
|
-
import { giteaApi } from "gitea-js";
|
|
6
|
+
import { giteaApi, ContentType } from "gitea-js";
|
|
7
7
|
import { LRUCache } from "lru-cache";
|
|
8
8
|
import * as TaskFormat from "./ase-task-format.js";
|
|
9
9
|
import * as TaskIssues from "./ase-task-store-issues.js";
|
|
@@ -396,7 +396,7 @@ class GiteaTaskStoragePlugin extends TaskIssues.IssueTaskStoragePlugin {
|
|
|
396
396
|
for (const blocker of after) {
|
|
397
397
|
if (have.has(blocker.number))
|
|
398
398
|
continue;
|
|
399
|
-
await this.call(loc, this.gt.repos.issueCreateIssueDependencies(loc.owner, loc.repo, String(issue.number), meta(blocker)))
|
|
399
|
+
await this.call(loc, this.gt.repos.issueCreateIssueDependencies(loc.owner, loc.repo, String(issue.number), meta(blocker), { type: ContentType.Json }))
|
|
400
400
|
.catch((err) => {
|
|
401
401
|
if (statusOf(err) === 404)
|
|
402
402
|
throw new Error(`Gitea rejected the dependency of issue #${issue.number} on issue #${blocker.number} ` +
|
|
@@ -406,7 +406,7 @@ class GiteaTaskStoragePlugin extends TaskIssues.IssueTaskStoragePlugin {
|
|
|
406
406
|
}
|
|
407
407
|
for (const blocker of current)
|
|
408
408
|
if (!want.has(blocker.number))
|
|
409
|
-
await found(this.call(loc, this.gt.repos.issueRemoveIssueDependencies(loc.owner, loc.repo, String(issue.number), meta(blocker))));
|
|
409
|
+
await found(this.call(loc, this.gt.repos.issueRemoveIssueDependencies(loc.owner, loc.repo, String(issue.number), meta(blocker), { type: ContentType.Json })));
|
|
410
410
|
}
|
|
411
411
|
/* synchronize the comments with the attachments, touching changed ones only
|
|
412
412
|
(see the common issue tracker parts) */
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
\[`--lifecycle` *model*\]
|
|
20
20
|
\[`--serial`\]
|
|
21
21
|
\[`--unclaimed`\]
|
|
22
|
+
\[`-M`|`--model` *model*\]
|
|
22
23
|
\[`--params` *name*`=`*value*\]
|
|
23
24
|
\[`--state-`*item* *state*\]
|
|
24
25
|
\[`--tag-`*item* *tag*\]
|
|
@@ -169,12 +170,12 @@ tags (except the request state tag) and, by default, gets its previous
|
|
|
169
170
|
assignee back. An agent consumes the request prompts if its prompt
|
|
170
171
|
template references `{prompt}` (except within the conditional
|
|
171
172
|
`{?prompt:`*text*`}` only, which makes the prompt *optional*) or it
|
|
172
|
-
has a hook `prepare`, `prompt`, or `finish` (which receive
|
|
173
|
-
prompt in their *job*), where it then refuses a request
|
|
174
|
-
prompt as failed, else it accepts requests with an empty
|
|
175
|
-
an agent with an optional prompt still passes on if
|
|
176
|
-
announces this to the agent relay, so the task boards
|
|
177
|
-
prompt for its requests, too.
|
|
173
|
+
has a hook `prepare`, `prompt`, `model`, or `finish` (which receive
|
|
174
|
+
the request prompt in their *job*), where it then refuses a request
|
|
175
|
+
with an empty prompt as failed, else it accepts requests with an empty
|
|
176
|
+
prompt (which an agent with an optional prompt still passes on if
|
|
177
|
+
non-empty), and announces this to the agent relay, so the task boards
|
|
178
|
+
accept an empty prompt for its requests, too.
|
|
178
179
|
|
|
179
180
|
Only the prompt (and `--state-incoming` for `--type phase`) is
|
|
180
181
|
mandatory, while all other options default to the safe *annotate*
|
|
@@ -431,6 +432,16 @@ and `--prompt-skill` with `--prompt-args`, and `--tag-retry` and
|
|
|
431
432
|
`passes`, and `--workdir changeset` resp. `target` (as the task can
|
|
432
433
|
be claimed by another agent meanwhile).
|
|
433
434
|
|
|
435
|
+
- \[`-M`|`--model` *model*\]:
|
|
436
|
+
The model of the agent tool, passed to it as `--model` *model*
|
|
437
|
+
verbatim (e.g., an alias like `sonnet` or a full model name), either a
|
|
438
|
+
*model* for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
439
|
+
`Effort:` size of the task (`XS`, `S`, `M`, `L`, `XL`, or `*` for all
|
|
440
|
+
other tasks, e.g., `XS=haiku,S=haiku,M=sonnet,*=opus`), where a task
|
|
441
|
+
without a matching pair gets the default model of the agent tool (the
|
|
442
|
+
default for all tasks). The hook `model` can override it per task (see
|
|
443
|
+
**HOOKS**).
|
|
444
|
+
|
|
434
445
|
- \[`--params` *name*`=`*value*\]:
|
|
435
446
|
(repeatable) The value of the parameter *name* declared by the
|
|
436
447
|
definition (see **PARAMETERS**), where a later value of the same
|
|
@@ -986,6 +997,14 @@ invocation:
|
|
|
986
997
|
`{ text }`, a plain prompt text, or `undefined` to keep the
|
|
987
998
|
configured one, where a thrown error fails the processing.
|
|
988
999
|
|
|
1000
|
+
- `model(task, model, job, ctx)`:
|
|
1001
|
+
The model of the agent tool for the job, given the configured *model*
|
|
1002
|
+
of `--model` for the `Effort:` size of the task (empty for the default
|
|
1003
|
+
model of the agent tool): a model (empty for the default one), or
|
|
1004
|
+
`undefined` to keep the configured one, where a thrown error fails the
|
|
1005
|
+
processing. This allows choosing the model per task by any means,
|
|
1006
|
+
e.g., by asking a cheap model via `ctx.exec`.
|
|
1007
|
+
|
|
989
1008
|
- `verdict(task, result, ctx)`:
|
|
990
1009
|
(after a successful agent tool only) The verdict of the result (an
|
|
991
1010
|
upper-case word, accepted only if listed by `--verdict-allow`), an
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
\[`-T`|`--timeout` *duration*\]
|
|
10
10
|
\[`-o`|`--one-shot`\]
|
|
11
11
|
\[`--agent-relay` *url*\]
|
|
12
|
+
\[`-M`|`--model` *model*\]
|
|
12
13
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
13
14
|
\[`-f`|`--foreground`\]
|
|
14
15
|
|
|
@@ -145,6 +146,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
145
146
|
(`phase` only). Built-in: not set. Not allowed, as the condenser
|
|
146
147
|
claims the tasks into its activity state.
|
|
147
148
|
|
|
149
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
150
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
151
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
152
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
153
|
+
model of the agent tool. Built-in: none.
|
|
154
|
+
|
|
148
155
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
149
156
|
declared by the definition (repeatable). Built-in: none declared.
|
|
150
157
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
\[`--agent-relay` *url*\]
|
|
12
12
|
\[`-r`|`--repo` *url*\]
|
|
13
13
|
\[`-d`|`--tempdir` *dir*\]
|
|
14
|
+
\[`-M`|`--model` *model*\]
|
|
14
15
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
15
16
|
\[`-f`|`--foreground`\]
|
|
16
17
|
|
|
@@ -192,6 +193,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
192
193
|
(`phase` only). Built-in: not set. Not allowed, as the editor is
|
|
193
194
|
of type `request`.
|
|
194
195
|
|
|
196
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
197
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
198
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
199
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
200
|
+
model of the agent tool. Built-in: none.
|
|
201
|
+
|
|
195
202
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
196
203
|
declared by the definition (repeatable). Built-in: none declared.
|
|
197
204
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
\[`-o`|`--one-shot`\]
|
|
11
11
|
\[`--agent-relay` *url*\]
|
|
12
12
|
\[`-m`|`--mode` `phase`|`request`\]
|
|
13
|
+
\[`-M`|`--model` *model*\]
|
|
13
14
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
14
15
|
\[`-f`|`--foreground`\]
|
|
15
16
|
|
|
@@ -204,6 +205,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
204
205
|
(`phase` only). Built-in: enabled (mode `phase`) resp. not set
|
|
205
206
|
(mode `request`).
|
|
206
207
|
|
|
208
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
209
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
210
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
211
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
212
|
+
model of the agent tool. Built-in: none.
|
|
213
|
+
|
|
207
214
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
208
215
|
declared by the definition (repeatable). Built-in: none declared.
|
|
209
216
|
|
|
@@ -79,7 +79,7 @@ members) or `ase agent fleet stop`.
|
|
|
79
79
|
(with all its options commented out, so they fall back to
|
|
80
80
|
`project.relay.url`, `project.relay.crt`, and `project.relay.key`),
|
|
81
81
|
the section `default` (with `tool`, `parallel: 1`, and `timeout: 60m`,
|
|
82
|
-
plus `repo
|
|
82
|
+
plus `model`, `repo`, and `tempdir` commented out), the edit request agent
|
|
83
83
|
`editor`, the effort estimation agent `estimator` (mode `phase`,
|
|
84
84
|
estimating the planned tasks, i.e., the `OPEN` tasks for `solo`, the
|
|
85
85
|
`PLANNING` tasks for `team`, and the `PLANNED` tasks for `enterprise`,
|
|
@@ -201,8 +201,9 @@ value omits an option, and a list repeats an option:
|
|
|
201
201
|
`project.relay.url` selecting HTTPS requires both.
|
|
202
202
|
|
|
203
203
|
- `default`:
|
|
204
|
-
(optional) The default options of all agents: `tool`, `
|
|
205
|
-
`timeout`, `repo`, `tempdir`, and `agent-relay` (see
|
|
204
|
+
(optional) The default options of all agents: `tool`, `model`,
|
|
205
|
+
`parallel`, `timeout`, `repo`, `tempdir`, and `agent-relay` (see
|
|
206
|
+
`ase-agent`(1) and `ase-agent-adhoc`(1)),
|
|
206
207
|
each one applied only to the agents supporting it (e.g., `repo` not to
|
|
207
208
|
`rebooter`), and overridden by the section of an agent. The option
|
|
208
209
|
`agent-relay` is not allowed together with the section `relay`.
|
|
@@ -315,7 +316,8 @@ $ ase agent fleet stop
|
|
|
315
316
|
```
|
|
316
317
|
|
|
317
318
|
A configuration `.ase/fleet.yaml` with the agent relay, the built-in
|
|
318
|
-
agents
|
|
319
|
+
agents (with an implementer using cheaper models for smaller tasks),
|
|
320
|
+
two editors of different agent tools, an agent of the
|
|
319
321
|
definition file `.ase/agents/reviewer.mts`, and an ad-hoc request
|
|
320
322
|
agent:
|
|
321
323
|
|
|
@@ -329,6 +331,7 @@ default:
|
|
|
329
331
|
rebooter:
|
|
330
332
|
implementer:
|
|
331
333
|
parallel: 2
|
|
334
|
+
model: XS=haiku,S=haiku,*=sonnet
|
|
332
335
|
editor-claude:
|
|
333
336
|
kind: editor
|
|
334
337
|
editor-codex:
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
\[`-r`|`--repo` *url*\]
|
|
13
13
|
\[`-d`|`--tempdir` *dir*\]
|
|
14
14
|
\[`-m`|`--mode` `implement`|`draft`\]
|
|
15
|
+
\[`-M`|`--model` *model*\]
|
|
15
16
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
16
17
|
\[`-f`|`--foreground`\]
|
|
17
18
|
|
|
@@ -260,6 +261,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
260
261
|
(`phase` only). Built-in: not set. Not allowed, as the implementer
|
|
261
262
|
claims the tasks into its activity state.
|
|
262
263
|
|
|
264
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
265
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
266
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
267
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
268
|
+
model of the agent tool. Built-in: none.
|
|
269
|
+
|
|
263
270
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
264
271
|
declared by the definition (repeatable). Built-in: `effort-wait`
|
|
265
272
|
(`true` or `false`, default: `true`), whether to wait for the
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
\[`-r`|`--repo` *url*\]
|
|
13
13
|
\[`-d`|`--tempdir` *dir*\]
|
|
14
14
|
\[`-m`|`--mode` `merge`|`rebase`|`squash`\]
|
|
15
|
+
\[`-M`|`--model` *model*\]
|
|
15
16
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
16
17
|
\[`-f`|`--foreground`\]
|
|
17
18
|
|
|
@@ -206,6 +207,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
206
207
|
(`phase` only). Built-in: not set. Not allowed, as the integrator
|
|
207
208
|
claims the tasks into its activity state.
|
|
208
209
|
|
|
210
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
211
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
212
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
213
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
214
|
+
model of the agent tool. Built-in: none.
|
|
215
|
+
|
|
209
216
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
210
217
|
declared by the definition (repeatable). Built-in: none declared.
|
|
211
218
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
\[`-r`|`--repo` *url*\]
|
|
13
13
|
\[`-d`|`--tempdir` *dir*\]
|
|
14
14
|
\[`-m`|`--mode` `judge`|`qualify`\]
|
|
15
|
+
\[`-M`|`--model` *model*\]
|
|
15
16
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
16
17
|
\[`-f`|`--foreground`\]
|
|
17
18
|
|
|
@@ -187,6 +188,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
187
188
|
(`phase` only). Built-in: not set. Not allowed, as the qualifier
|
|
188
189
|
claims the tasks into its activity state.
|
|
189
190
|
|
|
191
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
192
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
193
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
194
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
195
|
+
model of the agent tool. Built-in: none.
|
|
196
|
+
|
|
190
197
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
191
198
|
declared by the definition (repeatable). Built-in: none declared.
|
|
192
199
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
\[`-T`|`--timeout` *duration*\]
|
|
10
10
|
\[`-o`|`--one-shot`\]
|
|
11
11
|
\[`--agent-relay` *url*\]
|
|
12
|
+
\[`-M`|`--model` *model*\]
|
|
12
13
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
13
14
|
\[`-f`|`--foreground`\]
|
|
14
15
|
|
|
@@ -145,6 +146,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
145
146
|
(`phase` only). Built-in: not set. Not allowed, as the rebooter
|
|
146
147
|
claims the tasks into its activity state.
|
|
147
148
|
|
|
149
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
150
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
151
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
152
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
153
|
+
model of the agent tool. Built-in: none.
|
|
154
|
+
|
|
148
155
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
149
156
|
declared by the definition (repeatable). Built-in: none declared.
|
|
150
157
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
\[`-r`|`--repo` *url*\]
|
|
13
13
|
\[`-d`|`--tempdir` *dir*\]
|
|
14
14
|
\[`-m`|`--mode` `phase`|`request`\]
|
|
15
|
+
\[`-M`|`--model` *model*\]
|
|
15
16
|
\[`--`*group*`-`*item* *value* \[...\]\]
|
|
16
17
|
\[`-f`|`--foreground`\]
|
|
17
18
|
|
|
@@ -246,6 +247,12 @@ All other options belong to the sub-commands (see **COMMANDS**).
|
|
|
246
247
|
- \[`--unclaimed`\]: Process the tasks of the incoming states
|
|
247
248
|
without claiming them (`phase` only). Built-in: not set.
|
|
248
249
|
|
|
250
|
+
- \[`-M`|`--model` *model*\]: The model of the agent tool: a model
|
|
251
|
+
for all tasks, or comma-separated *size*`=`*model* pairs per
|
|
252
|
+
`Effort:` size (`XS`, `S`, `M`, `L`, `XL`, or `*` for all other
|
|
253
|
+
tasks), see `ase-agent-adhoc`(1). Generic default: the default
|
|
254
|
+
model of the agent tool. Built-in: none.
|
|
255
|
+
|
|
249
256
|
- \[`--params` *name*`=`*value*\]: The value of a parameter
|
|
250
257
|
declared by the definition (repeatable). Built-in: none declared.
|
|
251
258
|
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "https://ase.tools",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "https://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "2.0.
|
|
9
|
+
"version": "2.0.7",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"string-width": "8.3.0",
|
|
87
87
|
"react": "19.3.1",
|
|
88
88
|
"chokidar": "6.0.0",
|
|
89
|
-
"marked": "18.1.
|
|
90
|
-
"shiki": "4.
|
|
89
|
+
"marked": "18.1.3",
|
|
90
|
+
"shiki": "4.6.0",
|
|
91
91
|
"cli-table3": "0.6.5",
|
|
92
92
|
"chalk": "6.0.1",
|
|
93
93
|
"pretty-ms": "10.0.0",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"zod": "4.6.7",
|
|
98
98
|
"which": "7.0.0",
|
|
99
99
|
"update-notifier": "7.3.1",
|
|
100
|
-
"semver": "7.8.
|
|
100
|
+
"semver": "7.8.6",
|
|
101
101
|
"shell-quote": "1.12.0",
|
|
102
102
|
"get-stdin": "10.0.0",
|
|
103
103
|
"proper-lockfile": "4.1.2",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"undici": "8.12.3",
|
|
109
109
|
"picomatch": "4.0.7",
|
|
110
110
|
"lru-cache": "11.5.3",
|
|
111
|
-
"@rse/specbook": "1.6.
|
|
111
|
+
"@rse/specbook": "1.6.2",
|
|
112
112
|
"markdownlint": "0.42.0",
|
|
113
113
|
"tail": "2.2.6",
|
|
114
114
|
"source-code-error": "1.2.0",
|