@xn-intenton-z2a/agentic-lib 7.1.55 → 7.1.56
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/agentic-lib.toml +15 -1
- package/package.json +1 -1
- package/src/actions/agentic-step/config-loader.js +65 -1
- package/src/actions/agentic-step/copilot.js +12 -4
- package/src/actions/agentic-step/tasks/discussions.js +8 -7
- package/src/actions/agentic-step/tasks/enhance-issue.js +7 -4
- package/src/actions/agentic-step/tasks/fix-code.js +2 -0
- package/src/actions/agentic-step/tasks/maintain-features.js +6 -4
- package/src/actions/agentic-step/tasks/maintain-library.js +3 -1
- package/src/actions/agentic-step/tasks/resolve-issue.js +2 -0
- package/src/actions/agentic-step/tasks/review-issue.js +13 -9
- package/src/actions/agentic-step/tasks/supervise.js +5 -3
- package/src/actions/agentic-step/tasks/transform.js +14 -7
- package/src/seeds/zero-package.json +1 -1
package/agentic-lib.toml
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
[schedule]
|
|
9
9
|
supervisor = "daily" # off | weekly | daily | hourly | continuous
|
|
10
|
-
model = "gpt-5-mini" # gpt-5-mini | claude-sonnet-4 | gpt-4.1
|
|
11
10
|
|
|
12
11
|
[paths]
|
|
13
12
|
mission = "test/MISSION.md" #@dist "MISSION.md"
|
|
@@ -35,5 +34,20 @@ attempts-per-issue = 2
|
|
|
35
34
|
features-limit = 2
|
|
36
35
|
library-limit = 32
|
|
37
36
|
|
|
37
|
+
[tuning]
|
|
38
|
+
# Profile sets defaults for all tuning knobs: min | recommended | max
|
|
39
|
+
# min = fast & cheap (CI testing), recommended = balanced, max = thorough
|
|
40
|
+
profile = "min" #@dist "recommended"
|
|
41
|
+
model = "gpt-5-mini" # gpt-5-mini | claude-sonnet-4 | gpt-4.1
|
|
42
|
+
# Override individual knobs below. Omit or comment out to use profile defaults.
|
|
43
|
+
# reasoning-effort = "low" # low | medium | high | xhigh
|
|
44
|
+
infinite-sessions = false # set to true for long sessions with compaction
|
|
45
|
+
# features-scan = 3 # feature files to include in prompts
|
|
46
|
+
# source-scan = 3 # source files to include
|
|
47
|
+
# source-content = 1000 # max chars per source file
|
|
48
|
+
# issues-scan = 5 # open issues to include
|
|
49
|
+
# document-summary = 500 # max chars for document summaries
|
|
50
|
+
# discussion-comments = 5 # discussion comments to include
|
|
51
|
+
|
|
38
52
|
[bot]
|
|
39
53
|
log-file = "test/intentïon.md" #@dist "intentïon.md"
|
package/package.json
CHANGED
|
@@ -60,6 +60,40 @@ const LIMIT_DEFAULTS = {
|
|
|
60
60
|
library: 32,
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
// Tuning profiles: min (fast/cheap), recommended (balanced), max (thorough)
|
|
64
|
+
const TUNING_PROFILES = {
|
|
65
|
+
min: {
|
|
66
|
+
reasoningEffort: "low",
|
|
67
|
+
infiniteSessions: false,
|
|
68
|
+
featuresScan: 3,
|
|
69
|
+
sourceScan: 3,
|
|
70
|
+
sourceContent: 1000,
|
|
71
|
+
issuesScan: 5,
|
|
72
|
+
documentSummary: 500,
|
|
73
|
+
discussionComments: 5,
|
|
74
|
+
},
|
|
75
|
+
recommended: {
|
|
76
|
+
reasoningEffort: "medium",
|
|
77
|
+
infiniteSessions: true,
|
|
78
|
+
featuresScan: 10,
|
|
79
|
+
sourceScan: 10,
|
|
80
|
+
sourceContent: 5000,
|
|
81
|
+
issuesScan: 20,
|
|
82
|
+
documentSummary: 2000,
|
|
83
|
+
discussionComments: 10,
|
|
84
|
+
},
|
|
85
|
+
max: {
|
|
86
|
+
reasoningEffort: "high",
|
|
87
|
+
infiniteSessions: true,
|
|
88
|
+
featuresScan: 50,
|
|
89
|
+
sourceScan: 50,
|
|
90
|
+
sourceContent: 20000,
|
|
91
|
+
issuesScan: 100,
|
|
92
|
+
documentSummary: 10000,
|
|
93
|
+
discussionComments: 25,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
63
97
|
/**
|
|
64
98
|
* Read package.json from the project root, returning empty string if not found.
|
|
65
99
|
* @param {string} tomlPath - Path to the TOML config (used to derive project root)
|
|
@@ -76,6 +110,33 @@ function readPackageJson(tomlPath, depsRelPath) {
|
|
|
76
110
|
}
|
|
77
111
|
}
|
|
78
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Resolve tuning configuration: start from profile defaults, apply explicit overrides.
|
|
115
|
+
*/
|
|
116
|
+
function resolveTuning(tuningSection) {
|
|
117
|
+
const profileName = tuningSection.profile || "recommended";
|
|
118
|
+
const profile = TUNING_PROFILES[profileName] || TUNING_PROFILES.recommended;
|
|
119
|
+
const tuning = { ...profile };
|
|
120
|
+
|
|
121
|
+
if (tuningSection["reasoning-effort"]) tuning.reasoningEffort = tuningSection["reasoning-effort"];
|
|
122
|
+
if (tuningSection["infinite-sessions"] === true || tuningSection["infinite-sessions"] === false) {
|
|
123
|
+
tuning.infiniteSessions = tuningSection["infinite-sessions"];
|
|
124
|
+
}
|
|
125
|
+
const numericOverrides = {
|
|
126
|
+
"features-scan": "featuresScan",
|
|
127
|
+
"source-scan": "sourceScan",
|
|
128
|
+
"source-content": "sourceContent",
|
|
129
|
+
"issues-scan": "issuesScan",
|
|
130
|
+
"document-summary": "documentSummary",
|
|
131
|
+
"discussion-comments": "discussionComments",
|
|
132
|
+
};
|
|
133
|
+
for (const [tomlKey, jsKey] of Object.entries(numericOverrides)) {
|
|
134
|
+
if (tuningSection[tomlKey] > 0) tuning[jsKey] = tuningSection[tomlKey];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return tuning;
|
|
138
|
+
}
|
|
139
|
+
|
|
79
140
|
/**
|
|
80
141
|
* Load configuration from agentic-lib.toml.
|
|
81
142
|
*
|
|
@@ -132,12 +193,15 @@ export function loadConfig(configPath) {
|
|
|
132
193
|
paths.features.limit = limits["features-limit"] || LIMIT_DEFAULTS.features;
|
|
133
194
|
paths.library.limit = limits["library-limit"] || LIMIT_DEFAULTS.library;
|
|
134
195
|
|
|
196
|
+
const tuning = resolveTuning(toml.tuning || {});
|
|
197
|
+
|
|
135
198
|
const execution = toml.execution || {};
|
|
136
199
|
const bot = toml.bot || {};
|
|
137
200
|
|
|
138
201
|
return {
|
|
139
202
|
supervisor: toml.schedule?.supervisor || "daily",
|
|
140
|
-
model: toml.schedule?.model || "gpt-5-mini",
|
|
203
|
+
model: toml.tuning?.model || toml.schedule?.model || "gpt-5-mini",
|
|
204
|
+
tuning,
|
|
141
205
|
paths,
|
|
142
206
|
buildScript: execution.build || "npm run build",
|
|
143
207
|
testScript: execution.test || "npm test",
|
|
@@ -48,11 +48,12 @@ export function buildClientOptions(githubToken) {
|
|
|
48
48
|
* @param {string} options.prompt - The prompt to send
|
|
49
49
|
* @param {string[]} options.writablePaths - Paths the agent may modify
|
|
50
50
|
* @param {string} [options.githubToken] - Optional token; falls back to COPILOT_GITHUB_TOKEN env var.
|
|
51
|
+
* @param {Object} [options.tuning] - Tuning config (reasoningEffort, infiniteSessions)
|
|
51
52
|
* @returns {Promise<{content: string, tokensUsed: number}>}
|
|
52
53
|
*/
|
|
53
|
-
export async function runCopilotTask({ model, systemMessage, prompt, writablePaths, githubToken }) {
|
|
54
|
+
export async function runCopilotTask({ model, systemMessage, prompt, writablePaths, githubToken, tuning }) {
|
|
54
55
|
core.info(
|
|
55
|
-
`[copilot] Creating client (model=${model}, promptLen=${prompt.length}, writablePaths=${writablePaths.length})`,
|
|
56
|
+
`[copilot] Creating client (model=${model}, promptLen=${prompt.length}, writablePaths=${writablePaths.length}, tuning=${tuning?.reasoningEffort || "default"})`,
|
|
56
57
|
);
|
|
57
58
|
|
|
58
59
|
const clientOptions = buildClientOptions(githubToken);
|
|
@@ -60,13 +61,20 @@ export async function runCopilotTask({ model, systemMessage, prompt, writablePat
|
|
|
60
61
|
|
|
61
62
|
try {
|
|
62
63
|
core.info("[copilot] Creating session...");
|
|
63
|
-
const
|
|
64
|
+
const sessionConfig = {
|
|
64
65
|
model,
|
|
65
66
|
systemMessage: { content: systemMessage },
|
|
66
67
|
tools: createAgentTools(writablePaths),
|
|
67
68
|
onPermissionRequest: approveAll,
|
|
68
69
|
workingDirectory: process.cwd(),
|
|
69
|
-
}
|
|
70
|
+
};
|
|
71
|
+
if (tuning?.reasoningEffort) {
|
|
72
|
+
sessionConfig.reasoningEffort = tuning.reasoningEffort;
|
|
73
|
+
}
|
|
74
|
+
if (tuning?.infiniteSessions === true) {
|
|
75
|
+
sessionConfig.infiniteSessions = {};
|
|
76
|
+
}
|
|
77
|
+
const session = await client.createSession(sessionConfig);
|
|
70
78
|
core.info(`[copilot] Session created: ${session.sessionId}`);
|
|
71
79
|
|
|
72
80
|
// Check auth status now that client is connected
|
|
@@ -11,7 +11,7 @@ import { runCopilotTask, readOptionalFile, scanDirectory } from "../copilot.js";
|
|
|
11
11
|
|
|
12
12
|
const BOT_LOGINS = ["github-actions[bot]", "github-actions"];
|
|
13
13
|
|
|
14
|
-
async function fetchDiscussion(octokit, discussionUrl) {
|
|
14
|
+
async function fetchDiscussion(octokit, discussionUrl, commentsLimit = 10) {
|
|
15
15
|
const urlMatch = discussionUrl.match(/github\.com\/([^/]+)\/([^/]+)\/discussions\/(\d+)/);
|
|
16
16
|
if (!urlMatch) {
|
|
17
17
|
core.warning(`Could not parse discussion URL: ${discussionUrl}`);
|
|
@@ -26,7 +26,7 @@ async function fetchDiscussion(octokit, discussionUrl) {
|
|
|
26
26
|
id
|
|
27
27
|
title
|
|
28
28
|
body
|
|
29
|
-
comments(last:
|
|
29
|
+
comments(last: ${commentsLimit}) {
|
|
30
30
|
nodes {
|
|
31
31
|
body
|
|
32
32
|
author { login }
|
|
@@ -53,7 +53,7 @@ async function fetchDiscussion(octokit, discussionUrl) {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function buildPrompt(discussionUrl, discussion, context) {
|
|
56
|
+
function buildPrompt(discussionUrl, discussion, context, t) {
|
|
57
57
|
const { config, instructions } = context;
|
|
58
58
|
const { title, body, comments } = discussion;
|
|
59
59
|
|
|
@@ -63,7 +63,7 @@ function buildPrompt(discussionUrl, discussion, context) {
|
|
|
63
63
|
const lastBotReply = botReplies.length > 0 ? botReplies[botReplies.length - 1] : null;
|
|
64
64
|
|
|
65
65
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
66
|
-
const contributing = readOptionalFile(config.paths.contributing.path, 1000);
|
|
66
|
+
const contributing = readOptionalFile(config.paths.contributing.path, t.documentSummary || 1000);
|
|
67
67
|
const featuresPath = config.paths.features.path;
|
|
68
68
|
const featureNames = existsSync(featuresPath)
|
|
69
69
|
? scanDirectory(featuresPath, ".md").map((f) => f.name.replace(".md", ""))
|
|
@@ -152,20 +152,21 @@ async function postReply(octokit, nodeId, replyBody) {
|
|
|
152
152
|
*/
|
|
153
153
|
export async function discussions(context) {
|
|
154
154
|
const { octokit, model, discussionUrl } = context;
|
|
155
|
+
const t = context.config?.tuning || {};
|
|
155
156
|
|
|
156
157
|
if (!discussionUrl) {
|
|
157
158
|
throw new Error("discussions task requires discussion-url input");
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
const discussion = await fetchDiscussion(octokit, discussionUrl);
|
|
161
|
-
const prompt = buildPrompt(discussionUrl, discussion, context);
|
|
162
|
-
|
|
161
|
+
const discussion = await fetchDiscussion(octokit, discussionUrl, t.discussionComments || 10);
|
|
162
|
+
const prompt = buildPrompt(discussionUrl, discussion, context, t);
|
|
163
163
|
const { content, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
|
|
164
164
|
model,
|
|
165
165
|
systemMessage:
|
|
166
166
|
"You are this repository. Respond in first person. Be concise and engaging — never repeat what you said in your last reply. Adapt to the user's language level. Encourage experimentation and suggest interesting projects. When a user requests an action, pass it to the supervisor via [ACTION:request-supervisor]. Protect the mission: push back on requests that contradict it.",
|
|
167
167
|
prompt,
|
|
168
168
|
writablePaths: [],
|
|
169
|
+
tuning: t,
|
|
169
170
|
});
|
|
170
171
|
|
|
171
172
|
const actionMatch = content.match(/\[ACTION:(\S+?)\](.+)?/);
|
|
@@ -13,7 +13,7 @@ import { runCopilotTask, readOptionalFile, scanDirectory } from "../copilot.js";
|
|
|
13
13
|
/**
|
|
14
14
|
* Enhance a single GitHub issue with testable acceptance criteria.
|
|
15
15
|
*/
|
|
16
|
-
async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instructions, model }) {
|
|
16
|
+
async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instructions, model, tuning: t }) {
|
|
17
17
|
if (await isIssueResolved(octokit, repo, issueNumber)) {
|
|
18
18
|
return { outcome: "nop", details: `Issue #${issueNumber} already resolved` };
|
|
19
19
|
}
|
|
@@ -28,7 +28,7 @@ async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instruct
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const contributing = readOptionalFile(config.paths.contributing.path);
|
|
31
|
-
const features = scanDirectory(config.paths.features.path, ".md", { contentLimit: 2000 });
|
|
31
|
+
const features = scanDirectory(config.paths.features.path, ".md", { contentLimit: t.documentSummary || 2000 });
|
|
32
32
|
|
|
33
33
|
const agentInstructions = instructions || "Enhance this issue with clear, testable acceptance criteria.";
|
|
34
34
|
|
|
@@ -39,7 +39,7 @@ async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instruct
|
|
|
39
39
|
`## Issue #${issueNumber}: ${issue.title}`,
|
|
40
40
|
issue.body || "(no description)",
|
|
41
41
|
"",
|
|
42
|
-
contributing ? `## Contributing Guidelines\n${contributing.substring(0,
|
|
42
|
+
contributing ? `## Contributing Guidelines\n${contributing.substring(0, t.documentSummary || 2000)}` : "",
|
|
43
43
|
features.length > 0 ? `## Related Features\n${features.map((f) => f.content).join("\n---\n")}` : "",
|
|
44
44
|
config.configToml ? `## Configuration (agentic-lib.toml)\n\`\`\`toml\n${config.configToml}\n\`\`\`` : "",
|
|
45
45
|
config.packageJson ? `## Dependencies (package.json)\n\`\`\`json\n${config.packageJson}\n\`\`\`` : "",
|
|
@@ -64,6 +64,7 @@ async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instruct
|
|
|
64
64
|
systemMessage: "You are a requirements analyst. Enhance GitHub issues with clear, testable acceptance criteria.",
|
|
65
65
|
prompt,
|
|
66
66
|
writablePaths: [],
|
|
67
|
+
tuning: t,
|
|
67
68
|
});
|
|
68
69
|
|
|
69
70
|
if (enhancedBody.trim()) {
|
|
@@ -113,10 +114,11 @@ async function enhanceSingleIssue({ octokit, repo, config, issueNumber, instruct
|
|
|
113
114
|
*/
|
|
114
115
|
export async function enhanceIssue(context) {
|
|
115
116
|
const { octokit, repo, config, issueNumber, instructions, model } = context;
|
|
117
|
+
const t = config.tuning || {};
|
|
116
118
|
|
|
117
119
|
// Single issue mode
|
|
118
120
|
if (issueNumber) {
|
|
119
|
-
return enhanceSingleIssue({ octokit, repo, config, issueNumber, instructions, model });
|
|
121
|
+
return enhanceSingleIssue({ octokit, repo, config, issueNumber, instructions, model, tuning: t });
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// Batch mode: find up to 3 unready automated issues
|
|
@@ -149,6 +151,7 @@ export async function enhanceIssue(context) {
|
|
|
149
151
|
issueNumber: issue.number,
|
|
150
152
|
instructions,
|
|
151
153
|
model,
|
|
154
|
+
tuning: t,
|
|
152
155
|
});
|
|
153
156
|
results.push(result);
|
|
154
157
|
totalTokens += result.tokensUsed || 0;
|
|
@@ -93,11 +93,13 @@ export async function fixCode(context) {
|
|
|
93
93
|
"- Make minimal changes to fix the failing tests",
|
|
94
94
|
].join("\n");
|
|
95
95
|
|
|
96
|
+
const t = config.tuning || {};
|
|
96
97
|
const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
|
|
97
98
|
model,
|
|
98
99
|
systemMessage: `You are an autonomous coding agent fixing failing tests on PR #${prNumber}. Make minimal, targeted changes to fix the test failures.`,
|
|
99
100
|
prompt,
|
|
100
101
|
writablePaths,
|
|
102
|
+
tuning: t,
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
core.info(`Copilot SDK fix response received (${tokensUsed} tokens)`);
|
|
@@ -15,19 +15,20 @@ import { runCopilotTask, readOptionalFile, scanDirectory, formatPathsSection } f
|
|
|
15
15
|
*/
|
|
16
16
|
export async function maintainFeatures(context) {
|
|
17
17
|
const { config, instructions, writablePaths, model, octokit, repo } = context;
|
|
18
|
+
const t = config.tuning || {};
|
|
18
19
|
|
|
19
20
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
20
21
|
const featuresPath = config.paths.features.path;
|
|
21
22
|
const featureLimit = config.paths.features.limit;
|
|
22
|
-
const features = scanDirectory(featuresPath, ".md");
|
|
23
|
+
const features = scanDirectory(featuresPath, ".md", { fileLimit: t.featuresScan || 10 });
|
|
23
24
|
const libraryDocs = scanDirectory(config.paths.library.path, ".md", {
|
|
24
|
-
contentLimit: 1000,
|
|
25
|
+
contentLimit: t.documentSummary || 1000,
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
const { data: closedIssues } = await octokit.rest.issues.listForRepo({
|
|
28
29
|
...repo,
|
|
29
30
|
state: "closed",
|
|
30
|
-
per_page: 20,
|
|
31
|
+
per_page: t.issuesScan || 20,
|
|
31
32
|
sort: "updated",
|
|
32
33
|
direction: "desc",
|
|
33
34
|
});
|
|
@@ -48,7 +49,7 @@ export async function maintainFeatures(context) {
|
|
|
48
49
|
...libraryDocs.map((d) => `### ${d.name}\n${d.content}`),
|
|
49
50
|
"",
|
|
50
51
|
`## Recently Closed Issues (${closedIssues.length})`,
|
|
51
|
-
...closedIssues.slice(0,
|
|
52
|
+
...closedIssues.slice(0, Math.floor((t.issuesScan || 20) / 2)).map((i) => `- #${i.number}: ${i.title}`),
|
|
52
53
|
"",
|
|
53
54
|
"## Your Task",
|
|
54
55
|
`1. Review each existing feature — if it is already implemented or irrelevant, delete it.`,
|
|
@@ -68,6 +69,7 @@ export async function maintainFeatures(context) {
|
|
|
68
69
|
"You are a feature lifecycle manager. Create, update, and prune feature specification files to keep the project focused on its mission.",
|
|
69
70
|
prompt,
|
|
70
71
|
writablePaths,
|
|
72
|
+
tuning: t,
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
return {
|
|
@@ -16,6 +16,7 @@ import { runCopilotTask, readOptionalFile, scanDirectory, formatPathsSection } f
|
|
|
16
16
|
*/
|
|
17
17
|
export async function maintainLibrary(context) {
|
|
18
18
|
const { config, instructions, writablePaths, model } = context;
|
|
19
|
+
const t = config.tuning || {};
|
|
19
20
|
|
|
20
21
|
const sources = readOptionalFile(config.paths.librarySources.path);
|
|
21
22
|
if (!sources.trim()) {
|
|
@@ -25,7 +26,7 @@ export async function maintainLibrary(context) {
|
|
|
25
26
|
|
|
26
27
|
const libraryPath = config.paths.library.path;
|
|
27
28
|
const libraryLimit = config.paths.library.limit;
|
|
28
|
-
const libraryDocs = scanDirectory(libraryPath, ".md", { contentLimit: 500 });
|
|
29
|
+
const libraryDocs = scanDirectory(libraryPath, ".md", { contentLimit: t.documentSummary || 500 });
|
|
29
30
|
|
|
30
31
|
const agentInstructions = instructions || "Maintain the library by updating documents from sources.";
|
|
31
32
|
|
|
@@ -56,6 +57,7 @@ export async function maintainLibrary(context) {
|
|
|
56
57
|
"You are a knowledge librarian. Maintain a library of technical documents extracted from web sources.",
|
|
57
58
|
prompt,
|
|
58
59
|
writablePaths,
|
|
60
|
+
tuning: t,
|
|
59
61
|
});
|
|
60
62
|
|
|
61
63
|
return {
|
|
@@ -78,11 +78,13 @@ export async function resolveIssue(context) {
|
|
|
78
78
|
contributing ? `\n## Contributing Guidelines\n${contributing}` : "",
|
|
79
79
|
].join("\n");
|
|
80
80
|
|
|
81
|
+
const t = config.tuning || {};
|
|
81
82
|
const { content: resultContent, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
|
|
82
83
|
model,
|
|
83
84
|
systemMessage: `You are an autonomous coding agent resolving GitHub issue #${issueNumber}. Write clean, tested code. Only modify files listed under "Writable" paths. Read-only paths are for context only.`,
|
|
84
85
|
prompt,
|
|
85
86
|
writablePaths,
|
|
87
|
+
tuning: t,
|
|
86
88
|
});
|
|
87
89
|
|
|
88
90
|
core.info(`Copilot SDK response received (${tokensUsed} tokens)`);
|
|
@@ -21,7 +21,7 @@ import { runCopilotTask, scanDirectory } from "../copilot.js";
|
|
|
21
21
|
* @param {string} params.model - Model name
|
|
22
22
|
* @returns {Promise<Object>} Result with outcome, tokensUsed, model
|
|
23
23
|
*/
|
|
24
|
-
async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, instructions, model }) {
|
|
24
|
+
async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, instructions, model, tuning: t }) {
|
|
25
25
|
const { data: issue } = await octokit.rest.issues.get({
|
|
26
26
|
...repo,
|
|
27
27
|
issue_number: Number(targetIssueNumber),
|
|
@@ -32,18 +32,18 @@ async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, ins
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const sourceFiles = scanDirectory(config.paths.source.path, [".js", ".ts"], {
|
|
35
|
-
contentLimit: 5000,
|
|
36
|
-
fileLimit: 20,
|
|
35
|
+
contentLimit: t.sourceContent || 5000,
|
|
36
|
+
fileLimit: t.sourceScan || 20,
|
|
37
37
|
recursive: true,
|
|
38
38
|
});
|
|
39
39
|
const testFiles = scanDirectory(config.paths.tests.path, [".test.js", ".test.ts"], {
|
|
40
|
-
contentLimit: 5000,
|
|
41
|
-
fileLimit: 20,
|
|
40
|
+
contentLimit: t.sourceContent || 5000,
|
|
41
|
+
fileLimit: t.sourceScan || 20,
|
|
42
42
|
recursive: true,
|
|
43
43
|
});
|
|
44
44
|
const docsFiles = scanDirectory(config.paths.documentation?.path || "docs/", [".md"], {
|
|
45
|
-
fileLimit: 10,
|
|
46
|
-
contentLimit: 2000,
|
|
45
|
+
fileLimit: t.featuresScan || 10,
|
|
46
|
+
contentLimit: t.documentSummary || 2000,
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
const agentInstructions = instructions || "Review whether this issue has been resolved by the current codebase.";
|
|
@@ -85,6 +85,7 @@ async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, ins
|
|
|
85
85
|
systemMessage: "You are a code reviewer determining if GitHub issues have been resolved.",
|
|
86
86
|
prompt,
|
|
87
87
|
writablePaths: [],
|
|
88
|
+
tuning: t,
|
|
88
89
|
});
|
|
89
90
|
|
|
90
91
|
// Strip leading markdown formatting (e.g., **RESOLVED** or *RESOLVED*)
|
|
@@ -184,10 +185,11 @@ async function findUnreviewedIssues(octokit, repo, limit) {
|
|
|
184
185
|
*/
|
|
185
186
|
export async function reviewIssue(context) {
|
|
186
187
|
const { octokit, repo, config, issueNumber, instructions, model } = context;
|
|
188
|
+
const t = config.tuning || {};
|
|
187
189
|
|
|
188
190
|
// Single issue mode
|
|
189
191
|
if (issueNumber) {
|
|
190
|
-
return reviewSingleIssue({ octokit, repo, config, targetIssueNumber: issueNumber, instructions, model });
|
|
192
|
+
return reviewSingleIssue({ octokit, repo, config, targetIssueNumber: issueNumber, instructions, model, tuning: t });
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
// Batch mode: find up to 3 unreviewed issues
|
|
@@ -204,7 +206,9 @@ export async function reviewIssue(context) {
|
|
|
204
206
|
|
|
205
207
|
for (const num of issueNumbers) {
|
|
206
208
|
core.info(`Batch reviewing issue #${num} (${results.length + 1}/${issueNumbers.length})`);
|
|
207
|
-
const result = await reviewSingleIssue({
|
|
209
|
+
const result = await reviewSingleIssue({
|
|
210
|
+
octokit, repo, config, targetIssueNumber: num, instructions, model, tuning: t,
|
|
211
|
+
});
|
|
208
212
|
results.push(result);
|
|
209
213
|
totalTokens += result.tokensUsed || 0;
|
|
210
214
|
totalInputTokens += result.inputTokens || 0;
|
|
@@ -9,7 +9,7 @@ import * as core from "@actions/core";
|
|
|
9
9
|
import { existsSync } from "fs";
|
|
10
10
|
import { runCopilotTask, readOptionalFile, scanDirectory } from "../copilot.js";
|
|
11
11
|
|
|
12
|
-
async function gatherContext(octokit, repo, config) {
|
|
12
|
+
async function gatherContext(octokit, repo, config, t) {
|
|
13
13
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
14
14
|
const recentActivity = readOptionalFile(config.intentionBot.intentionFilepath).split("\n").slice(-20).join("\n");
|
|
15
15
|
|
|
@@ -28,7 +28,7 @@ async function gatherContext(octokit, repo, config) {
|
|
|
28
28
|
const { data: openIssues } = await octokit.rest.issues.listForRepo({
|
|
29
29
|
...repo,
|
|
30
30
|
state: "open",
|
|
31
|
-
per_page: 20,
|
|
31
|
+
per_page: t.issuesScan || 20,
|
|
32
32
|
sort: "created",
|
|
33
33
|
direction: "asc",
|
|
34
34
|
});
|
|
@@ -305,8 +305,9 @@ async function executeAction(octokit, repo, action, params) {
|
|
|
305
305
|
*/
|
|
306
306
|
export async function supervise(context) {
|
|
307
307
|
const { octokit, repo, config, instructions, model } = context;
|
|
308
|
+
const t = config.tuning || {};
|
|
308
309
|
|
|
309
|
-
const ctx = await gatherContext(octokit, repo, config);
|
|
310
|
+
const ctx = await gatherContext(octokit, repo, config, t);
|
|
310
311
|
const agentInstructions = instructions || "You are the supervisor. Decide what actions to take.";
|
|
311
312
|
const prompt = buildPrompt(ctx, agentInstructions);
|
|
312
313
|
|
|
@@ -316,6 +317,7 @@ export async function supervise(context) {
|
|
|
316
317
|
"You are the supervisor of an autonomous coding repository. Your job is to advance the mission by choosing which workflows to dispatch and which GitHub actions to take. Pick multiple actions when appropriate. Be strategic — consider what's already in progress, what's blocked, and what will make the most impact.",
|
|
317
318
|
prompt,
|
|
318
319
|
writablePaths: [],
|
|
320
|
+
tuning: t,
|
|
319
321
|
});
|
|
320
322
|
|
|
321
323
|
const actions = parseActions(content);
|
|
@@ -16,6 +16,7 @@ import { runCopilotTask, readOptionalFile, scanDirectory, formatPathsSection } f
|
|
|
16
16
|
*/
|
|
17
17
|
export async function transform(context) {
|
|
18
18
|
const { config, instructions, writablePaths, testCommand, model, octokit, repo, issueNumber } = context;
|
|
19
|
+
const t = config.tuning || {};
|
|
19
20
|
|
|
20
21
|
// Read mission (required)
|
|
21
22
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
@@ -24,16 +25,17 @@ export async function transform(context) {
|
|
|
24
25
|
return { outcome: "nop", details: "No mission file found" };
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const features = scanDirectory(config.paths.features.path, ".md");
|
|
28
|
+
const features = scanDirectory(config.paths.features.path, ".md", { fileLimit: t.featuresScan || 10 });
|
|
28
29
|
const sourceFiles = scanDirectory(config.paths.source.path, [".js", ".ts"], {
|
|
29
|
-
|
|
30
|
+
fileLimit: t.sourceScan || 10,
|
|
31
|
+
contentLimit: t.sourceContent || 5000,
|
|
30
32
|
recursive: true,
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
const { data: openIssues } = await octokit.rest.issues.listForRepo({
|
|
34
36
|
...repo,
|
|
35
37
|
state: "open",
|
|
36
|
-
per_page: 20,
|
|
38
|
+
per_page: t.issuesScan || 20,
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
// Fetch target issue if specified
|
|
@@ -67,6 +69,7 @@ export async function transform(context) {
|
|
|
67
69
|
features,
|
|
68
70
|
sourceFiles,
|
|
69
71
|
openIssues,
|
|
72
|
+
tuning: t,
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
|
|
@@ -88,13 +91,13 @@ export async function transform(context) {
|
|
|
88
91
|
mission,
|
|
89
92
|
"",
|
|
90
93
|
`## Current Features (${features.length})`,
|
|
91
|
-
...features.map((f) => `### ${f.name}\n${f.content.substring(0, 2000)}`),
|
|
94
|
+
...features.map((f) => `### ${f.name}\n${f.content.substring(0, t.documentSummary || 2000)}`),
|
|
92
95
|
"",
|
|
93
96
|
`## Current Source Files (${sourceFiles.length})`,
|
|
94
97
|
...sourceFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
|
|
95
98
|
"",
|
|
96
99
|
`## Open Issues (${openIssues.length})`,
|
|
97
|
-
...openIssues.slice(0, 20).map((i) => `- #${i.number}: ${i.title}`),
|
|
100
|
+
...openIssues.slice(0, t.issuesScan || 20).map((i) => `- #${i.number}: ${i.title}`),
|
|
98
101
|
"",
|
|
99
102
|
"## Output Artifacts",
|
|
100
103
|
"If your changes produce output artifacts (plots, visualizations, data files, usage examples),",
|
|
@@ -126,6 +129,7 @@ export async function transform(context) {
|
|
|
126
129
|
"You are an autonomous code transformation agent. Your goal is to advance the repository toward its mission by making the most impactful change possible in a single step.",
|
|
127
130
|
prompt,
|
|
128
131
|
writablePaths,
|
|
132
|
+
tuning: t,
|
|
129
133
|
});
|
|
130
134
|
|
|
131
135
|
core.info(`Transformation step completed (${tokensUsed} tokens)`);
|
|
@@ -155,6 +159,7 @@ async function transformTdd({
|
|
|
155
159
|
features,
|
|
156
160
|
sourceFiles,
|
|
157
161
|
openIssues,
|
|
162
|
+
tuning: t,
|
|
158
163
|
}) {
|
|
159
164
|
let totalTokens = 0;
|
|
160
165
|
|
|
@@ -175,13 +180,13 @@ async function transformTdd({
|
|
|
175
180
|
mission,
|
|
176
181
|
"",
|
|
177
182
|
`## Current Features (${features.length})`,
|
|
178
|
-
...features.map((f) => `### ${f.name}\n${f.content.substring(0, 2000)}`),
|
|
183
|
+
...features.map((f) => `### ${f.name}\n${f.content.substring(0, t.documentSummary || 2000)}`),
|
|
179
184
|
"",
|
|
180
185
|
`## Current Source Files (${sourceFiles.length})`,
|
|
181
186
|
...sourceFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
|
|
182
187
|
"",
|
|
183
188
|
`## Open Issues (${openIssues.length})`,
|
|
184
|
-
...openIssues.slice(0, 20).map((i) => `- #${i.number}: ${i.title}`),
|
|
189
|
+
...openIssues.slice(0, t.issuesScan || 20).map((i) => `- #${i.number}: ${i.title}`),
|
|
185
190
|
"",
|
|
186
191
|
formatPathsSection(writablePaths, readOnlyPaths, _config),
|
|
187
192
|
"",
|
|
@@ -197,6 +202,7 @@ async function transformTdd({
|
|
|
197
202
|
"You are a TDD agent. In this phase, write ONLY a failing test that captures the next feature requirement. Do not write implementation code.",
|
|
198
203
|
prompt: testPrompt,
|
|
199
204
|
writablePaths,
|
|
205
|
+
tuning: t,
|
|
200
206
|
});
|
|
201
207
|
totalTokens += phase1.tokensUsed;
|
|
202
208
|
const testResult = phase1.content;
|
|
@@ -242,6 +248,7 @@ async function transformTdd({
|
|
|
242
248
|
"You are a TDD agent. A failing test was written in Phase 1. Write the minimum implementation to make it pass. Do not modify the test.",
|
|
243
249
|
prompt: implPrompt,
|
|
244
250
|
writablePaths,
|
|
251
|
+
tuning: t,
|
|
245
252
|
});
|
|
246
253
|
totalTokens += phase2.tokensUsed;
|
|
247
254
|
|