@xn-intenton-z2a/agentic-lib 7.1.31 → 7.1.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.31",
3
+ "version": "7.1.33",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -76,12 +76,27 @@ export async function runCopilotTask({ model, systemMessage, prompt, writablePat
76
76
  core.warning(`[copilot] Auth check failed: ${authErr.message}`);
77
77
  }
78
78
 
79
+ // Accumulate usage from assistant.usage events (tokens are NOT on the sendAndWait response)
80
+ let totalInputTokens = 0;
81
+ let totalOutputTokens = 0;
82
+ let totalCost = 0;
83
+
79
84
  // Register wildcard event handler for ALL events
80
85
  session.on((event) => {
81
86
  const eventType = event?.type || "unknown";
82
87
  if (eventType === "assistant.message") {
83
88
  const preview = event?.data?.content?.substring(0, 100) || "(no content)";
84
89
  core.info(`[copilot] event=${eventType}: ${preview}...`);
90
+ } else if (eventType === "assistant.usage") {
91
+ const d = event?.data || {};
92
+ const input = d.inputTokens || 0;
93
+ const output = d.outputTokens || 0;
94
+ const cacheRead = d.cacheReadTokens || 0;
95
+ const cost = d.cost || 0;
96
+ totalInputTokens += input;
97
+ totalOutputTokens += output;
98
+ totalCost += cost;
99
+ core.info(`[copilot] event=${eventType}: model=${d.model} input=${input} output=${output} cacheRead=${cacheRead} cost=${cost}`);
85
100
  } else if (eventType === "session.idle") {
86
101
  core.info(`[copilot] event=${eventType}`);
87
102
  } else if (eventType === "session.error") {
@@ -94,10 +109,10 @@ export async function runCopilotTask({ model, systemMessage, prompt, writablePat
94
109
  core.info("[copilot] Sending prompt and waiting for idle...");
95
110
  const response = await session.sendAndWait({ prompt }, 600000);
96
111
  core.info(`[copilot] sendAndWait resolved`);
97
- const tokensUsed = response?.data?.usage?.totalTokens || 0;
112
+ const tokensUsed = totalInputTokens + totalOutputTokens;
98
113
  const content = response?.data?.content || "";
99
114
 
100
- return { content, tokensUsed };
115
+ return { content, tokensUsed, inputTokens: totalInputTokens, outputTokens: totalOutputTokens, cost: totalCost };
101
116
  } finally {
102
117
  await client.stop();
103
118
  }
@@ -105,6 +105,9 @@ async function run() {
105
105
  prNumber: result.prNumber,
106
106
  commitUrl: result.commitUrl,
107
107
  tokensUsed: result.tokensUsed,
108
+ inputTokens: result.inputTokens,
109
+ outputTokens: result.outputTokens,
110
+ cost: result.cost,
108
111
  model: result.model || model,
109
112
  details: result.details,
110
113
  workflowUrl: `${process.env.GITHUB_SERVER_URL}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`,
@@ -19,7 +19,10 @@ import * as core from "@actions/core";
19
19
  * @param {string} [options.issueNumber] - Related issue number
20
20
  * @param {string} [options.prNumber] - Related PR number
21
21
  * @param {string} [options.commitUrl] - URL to the commit
22
- * @param {number} [options.tokensUsed] - Tokens consumed
22
+ * @param {number} [options.tokensUsed] - Total tokens consumed (input + output)
23
+ * @param {number} [options.inputTokens] - Input tokens consumed
24
+ * @param {number} [options.outputTokens] - Output tokens consumed
25
+ * @param {number} [options.cost] - Cost reported by Copilot SDK
23
26
  * @param {string} [options.model] - Model used
24
27
  * @param {string} [options.details] - Additional details
25
28
  * @param {string} [options.workflowUrl] - URL to the workflow run
@@ -32,6 +35,9 @@ export function logActivity({
32
35
  prNumber,
33
36
  commitUrl,
34
37
  tokensUsed,
38
+ inputTokens,
39
+ outputTokens,
40
+ cost,
35
41
  model,
36
42
  details,
37
43
  workflowUrl,
@@ -48,7 +54,8 @@ export function logActivity({
48
54
  if (prNumber) parts.push(`**PR:** #${prNumber}`);
49
55
  if (commitUrl) parts.push(`**Commit:** [${commitUrl}](${commitUrl})`);
50
56
  if (model) parts.push(`**Model:** ${model}`);
51
- if (tokensUsed !== undefined) parts.push(`**Tokens:** ${tokensUsed}`);
57
+ if (tokensUsed) parts.push(`**Tokens:** ${tokensUsed} (in: ${inputTokens || 0}, out: ${outputTokens || 0})`);
58
+ if (cost) parts.push(`**Cost:** ${cost}`);
52
59
  if (workflowUrl) parts.push(`**Workflow:** [${workflowUrl}](${workflowUrl})`);
53
60
  if (details) {
54
61
  parts.push("");
@@ -158,7 +158,7 @@ export async function discussions(context) {
158
158
  const discussion = await fetchDiscussion(octokit, discussionUrl);
159
159
  const prompt = buildPrompt(discussionUrl, discussion, context);
160
160
 
161
- const { content, tokensUsed } = await runCopilotTask({
161
+ const { content, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
162
162
  model,
163
163
  systemMessage:
164
164
  "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.",
@@ -178,6 +178,9 @@ export async function discussions(context) {
178
178
  return {
179
179
  outcome: `discussion-${action}`,
180
180
  tokensUsed,
181
+ inputTokens,
182
+ outputTokens,
183
+ cost,
181
184
  model,
182
185
  details: `Action: ${action}${argSuffix}\nReply: ${replyBody.substring(0, 200)}`,
183
186
  action,
@@ -59,7 +59,7 @@ export async function enhanceIssue(context) {
59
59
  "Output ONLY the new issue body text, no markdown code fences.",
60
60
  ].join("\n");
61
61
 
62
- const { content: enhancedBody, tokensUsed } = await runCopilotTask({
62
+ const { content: enhancedBody, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
63
63
  model,
64
64
  systemMessage: "You are a requirements analyst. Enhance GitHub issues with clear, testable acceptance criteria.",
65
65
  prompt,
@@ -96,6 +96,9 @@ export async function enhanceIssue(context) {
96
96
  return {
97
97
  outcome: "issue-enhanced",
98
98
  tokensUsed,
99
+ inputTokens,
100
+ outputTokens,
101
+ cost,
99
102
  model,
100
103
  details: `Enhanced issue #${issueNumber} with acceptance criteria`,
101
104
  };
@@ -53,7 +53,7 @@ export async function fixCode(context) {
53
53
  "- Make minimal changes to fix the failing tests",
54
54
  ].join("\n");
55
55
 
56
- const { tokensUsed } = await runCopilotTask({
56
+ const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
57
57
  model,
58
58
  systemMessage: `You are an autonomous coding agent fixing failing tests on PR #${prNumber}. Make minimal, targeted changes to fix the test failures.`,
59
59
  prompt,
@@ -65,6 +65,9 @@ export async function fixCode(context) {
65
65
  return {
66
66
  outcome: "fix-applied",
67
67
  tokensUsed,
68
+ inputTokens,
69
+ outputTokens,
70
+ cost,
68
71
  model,
69
72
  details: `Applied fix for ${failedChecks.length} failing check(s) on PR #${prNumber}`,
70
73
  };
@@ -62,7 +62,7 @@ export async function maintainFeatures(context) {
62
62
  "- Feature files must be markdown with a descriptive filename (e.g. HTTP_SERVER.md)",
63
63
  ].join("\n");
64
64
 
65
- const { tokensUsed } = await runCopilotTask({
65
+ const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
66
66
  model,
67
67
  systemMessage:
68
68
  "You are a feature lifecycle manager. Create, update, and prune feature specification files to keep the project focused on its mission.",
@@ -73,6 +73,9 @@ export async function maintainFeatures(context) {
73
73
  return {
74
74
  outcome: "features-maintained",
75
75
  tokensUsed,
76
+ inputTokens,
77
+ outputTokens,
78
+ cost,
76
79
  model,
77
80
  details: `Maintained features (${features.length} existing, limit ${featureLimit})`,
78
81
  };
@@ -50,7 +50,7 @@ export async function maintainLibrary(context) {
50
50
  `- Maximum ${libraryLimit} library documents`,
51
51
  ].join("\n");
52
52
 
53
- const { tokensUsed } = await runCopilotTask({
53
+ const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
54
54
  model,
55
55
  systemMessage:
56
56
  "You are a knowledge librarian. Maintain a library of technical documents extracted from web sources.",
@@ -61,6 +61,9 @@ export async function maintainLibrary(context) {
61
61
  return {
62
62
  outcome: "library-maintained",
63
63
  tokensUsed,
64
+ inputTokens,
65
+ outputTokens,
66
+ cost,
64
67
  model,
65
68
  details: `Maintained library (${libraryDocs.length} docs, limit ${libraryLimit})`,
66
69
  };
@@ -78,7 +78,7 @@ export async function resolveIssue(context) {
78
78
  contributing ? `\n## Contributing Guidelines\n${contributing}` : "",
79
79
  ].join("\n");
80
80
 
81
- const { content: resultContent, tokensUsed } = await runCopilotTask({
81
+ const { content: resultContent, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
82
82
  model,
83
83
  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
84
  prompt,
@@ -91,6 +91,9 @@ export async function resolveIssue(context) {
91
91
  outcome: "code-generated",
92
92
  prNumber: null,
93
93
  tokensUsed,
94
+ inputTokens,
95
+ outputTokens,
96
+ cost,
94
97
  model,
95
98
  commitUrl: null,
96
99
  details: `Generated code for issue #${issueNumber}: ${resultContent.substring(0, 200)}`,
@@ -74,7 +74,7 @@ export async function reviewIssue(context) {
74
74
  '- "OPEN: <reason>" if the issue is not yet resolved',
75
75
  ].join("\n");
76
76
 
77
- const { content: verdict, tokensUsed } = await runCopilotTask({
77
+ const { content: verdict, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
78
78
  model,
79
79
  systemMessage: "You are a code reviewer determining if GitHub issues have been resolved.",
80
80
  prompt,
@@ -108,6 +108,9 @@ export async function reviewIssue(context) {
108
108
  return {
109
109
  outcome: "issue-closed",
110
110
  tokensUsed,
111
+ inputTokens,
112
+ outputTokens,
113
+ cost,
111
114
  model,
112
115
  details: `Closed issue #${targetIssueNumber}: ${verdict.substring(0, 200)}`,
113
116
  };
@@ -117,6 +120,9 @@ export async function reviewIssue(context) {
117
120
  return {
118
121
  outcome: "issue-still-open",
119
122
  tokensUsed,
123
+ inputTokens,
124
+ outputTokens,
125
+ cost,
120
126
  model,
121
127
  details: `Issue #${targetIssueNumber} remains open: ${verdict.substring(0, 200)}`,
122
128
  };
@@ -76,6 +76,8 @@ async function gatherContext(octokit, repo, config) {
76
76
  workflowsSummary,
77
77
  schedule: config.schedule,
78
78
  supervisor: config.supervisor,
79
+ featureIssuesWipLimit: config.featureDevelopmentIssuesWipLimit,
80
+ maintenanceIssuesWipLimit: config.maintenanceIssuesWipLimit,
79
81
  };
80
82
  }
81
83
 
@@ -108,6 +110,11 @@ function buildPrompt(ctx, agentInstructions) {
108
110
  "",
109
111
  `### Schedule: ${ctx.schedule}, Supervisor: ${ctx.supervisor}`,
110
112
  "",
113
+ `### Issue Limits`,
114
+ `Feature development WIP limit: ${ctx.featureIssuesWipLimit}`,
115
+ `Maintenance WIP limit: ${ctx.maintenanceIssuesWipLimit}`,
116
+ `Open issues: ${ctx.issuesSummary.length} (capacity for ${Math.max(0, ctx.featureIssuesWipLimit - ctx.issuesSummary.length)} more)`,
117
+ "",
111
118
  "## Available Actions",
112
119
  "Pick one or more actions. Output them in the format below.",
113
120
  "",
@@ -250,7 +257,7 @@ export async function supervise(context) {
250
257
  const agentInstructions = instructions || "You are the supervisor. Decide what actions to take.";
251
258
  const prompt = buildPrompt(ctx, agentInstructions);
252
259
 
253
- const { content, tokensUsed } = await runCopilotTask({
260
+ const { content, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
254
261
  model,
255
262
  systemMessage:
256
263
  "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.",
@@ -279,6 +286,9 @@ export async function supervise(context) {
279
286
  return {
280
287
  outcome: actions.length === 0 ? "nop" : `supervised:${actions.length}-actions`,
281
288
  tokensUsed,
289
+ inputTokens,
290
+ outputTokens,
291
+ cost,
282
292
  model,
283
293
  details: `Actions: ${results.join(", ")}\nReasoning: ${reasoning.substring(0, 300)}`,
284
294
  };
@@ -85,7 +85,7 @@ export async function transform(context) {
85
85
 
86
86
  core.info(`Transform prompt length: ${prompt.length} chars`);
87
87
 
88
- const { content: resultContent, tokensUsed } = await runCopilotTask({
88
+ const { content: resultContent, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
89
89
  model,
90
90
  systemMessage:
91
91
  "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.",
@@ -98,6 +98,9 @@ export async function transform(context) {
98
98
  return {
99
99
  outcome: "transformed",
100
100
  tokensUsed,
101
+ inputTokens,
102
+ outputTokens,
103
+ cost,
101
104
  model,
102
105
  details: resultContent.substring(0, 500),
103
106
  };
@@ -207,6 +210,9 @@ async function transformTdd({
207
210
  return {
208
211
  outcome: "transformed-tdd",
209
212
  tokensUsed: totalTokens,
213
+ inputTokens: (phase1.inputTokens || 0) + (phase2.inputTokens || 0),
214
+ outputTokens: (phase1.outputTokens || 0) + (phase2.outputTokens || 0),
215
+ cost: (phase1.cost || 0) + (phase2.cost || 0),
210
216
  model,
211
217
  details: `TDD transformation: Phase 1 (failing test) + Phase 2 (implementation). ${testResult.substring(0, 200)}`,
212
218
  };
@@ -1,25 +1,32 @@
1
1
  You are the supervisor of an autonomous coding repository. Your job is to advance the mission by strategically choosing which workflows to dispatch and which GitHub actions to take.
2
2
 
3
+ ## Priority Order
4
+
5
+ 1. **Create issues when the backlog is low** — if fewer than 3 open issues exist, create at least 1 new issue from the features list or mission before dispatching workflows. The pipeline stalls without issues to work on. Always include descriptive titles and the `automated` label.
6
+ 2. **Dispatch transform when ready issues exist** — transform is where code gets written. Always prefer it over maintain when there are open issues with the `ready` label.
7
+ 3. **Dispatch review after transform** — when recent workflow runs show a transform completion, dispatch review to close resolved issues and add `ready` labels to new issues. This keeps the pipeline flowing.
8
+ 4. **Fix failing PRs** — dispatch fix-code for any PR with failing checks (include pr-number).
9
+ 5. **Dispatch maintain sparingly** — only when features or library docs need refreshing AND no maintain has run in the last 3 workflow runs. Maintain is low-value if features are already populated.
10
+
3
11
  ## Decision Framework
4
12
 
5
13
  1. **Check what's already in progress** — don't duplicate work. If a transform is running, don't dispatch another.
6
- 2. **Prioritise unblocking** — fix failing PRs before starting new features. Close resolved issues to free capacity.
7
- 3. **Balance the pipeline** — maintain a healthy mix of feature work, maintenance, and review.
8
- 4. **Respect limits** — don't create issues beyond the WIP limit. Don't dispatch workflows that will fail due to missing prerequisites.
9
- 5. **Be strategic about timing** — if the schedule is hourly, you can afford to spread work across cycles. If daily, batch more aggressively.
14
+ 2. **Prioritise code generation** — the goal is working code. Prefer actions that produce code (transform, fix-code) over metadata (maintain, label).
15
+ 3. **Keep the issue pipeline full** — the biggest bottleneck is running out of open issues. Proactively create issues when capacity allows.
16
+ 4. **Respect limits** — don't create issues beyond the WIP limit shown in the context. Don't dispatch workflows that will fail due to missing prerequisites.
10
17
 
11
18
  ## When to use each action
12
19
 
13
- - **dispatch:agent-flow-transform** — When there are open issues ready to work on and no transform is currently running.
14
- - **dispatch:agent-flow-maintain** — When features or library docs are below their limits, or haven't been refreshed recently.
15
- - **dispatch:agent-flow-review** — When there are open automated issues that might be resolved, or issues that need better acceptance criteria.
20
+ - **github:create-issue** — When open issues < WIP limit. Derive the issue title from unimplemented features or mission goals. Always include relevant labels (`automated`, `enhancement`).
21
+ - **dispatch:agent-flow-transform** — When there are open issues with the `ready` label and no transform is currently running.
22
+ - **dispatch:agent-flow-review** — After observing a recent transform completion, or when there are unenhanced issues needing the `ready` label.
16
23
  - **dispatch:agent-flow-fix-code** — When a specific PR has failing checks. Always include the pr-number.
24
+ - **dispatch:agent-flow-maintain** — When features are below their limit AND no maintain appears in the last 3 workflow runs.
17
25
  - **dispatch:agent-discussions-bot** — When you want to proactively engage in discussions or respond to a user request.
18
- - **github:create-issue** — When you identify a gap between the mission and current features. Always include a descriptive title and relevant labels.
19
26
  - **github:label-issue** — When an issue needs better categorisation for prioritisation.
20
27
  - **github:close-issue** — When an issue is clearly resolved or no longer relevant.
21
28
  - **respond:discussions** — When replying to a user request that came through the discussions bot. Include the discussion URL and a clear message.
22
- - **nop** — When everything is running smoothly and no intervention is needed.
29
+ - **nop** — When everything is running optimally: transform is active, issues are flowing, no failures.
23
30
 
24
31
  ## Guidelines
25
32
 
@@ -28,3 +35,4 @@ You are the supervisor of an autonomous coding repository. Your job is to advanc
28
35
  - When a user has made a request via discussions, prioritise responding to it.
29
36
  - Don't dispatch the same workflow twice in one cycle.
30
37
  - If recent workflow runs show failures, investigate before dispatching more work.
38
+ - Creating an issue + dispatching review in the same cycle is a good pattern: review will enhance the new issue with acceptance criteria and the `ready` label.
@@ -27,7 +27,7 @@ test = "npm test"
27
27
  start = "npm run start"
28
28
 
29
29
  [limits]
30
- feature-issues = 2
30
+ feature-issues = 5
31
31
  maintenance-issues = 1
32
32
  attempts-per-branch = 3
33
33
  attempts-per-issue = 2
@@ -14,7 +14,7 @@
14
14
  "author": "",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@xn-intenton-z2a/agentic-lib": "^7.1.31"
17
+ "@xn-intenton-z2a/agentic-lib": "^7.1.33"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@vitest/coverage-v8": "^4.0.0",
@@ -48,7 +48,7 @@ jobs:
48
48
  weekly: '0 6 * * 1',
49
49
  daily: '0 6 * * *',
50
50
  hourly: '0 * * * *',
51
- continuous: '*/10 * * * *',
51
+ continuous: '*/15 * * * *',
52
52
  };
53
53
 
54
54
  let content = fs.readFileSync(workflowPath, 'utf8');
@@ -23,6 +23,8 @@ on:
23
23
  - test
24
24
  - agent-flow-transform
25
25
  - agent-flow-fix-code
26
+ - agent-flow-maintain
27
+ - agent-flow-review
26
28
  - ci-automerge
27
29
  types:
28
30
  - completed
@@ -172,6 +174,21 @@ jobs:
172
174
  core.warning(`Stale PR check failed: ${err.message}`);
173
175
  }
174
176
 
177
+ // ─── 3. Successful transform → dispatch review ────────────────
178
+ try {
179
+ if (workflowRun && workflowName === 'agent-flow-transform' && conclusion === 'success') {
180
+ core.info('Transform completed successfully — dispatching review to close resolved issues and enhance new ones.');
181
+ await github.rest.actions.createWorkflowDispatch({
182
+ owner, repo,
183
+ workflow_id: 'agent-flow-review.yml',
184
+ ref: 'main',
185
+ inputs: {},
186
+ });
187
+ }
188
+ } catch (err) {
189
+ core.warning(`Post-transform review dispatch failed: ${err.message}`);
190
+ }
191
+
175
192
  # ─── Proactive: LLM-driven strategic decisions ───────────────────────
176
193
  supervise:
177
194
  needs: params