@cuylabs/agent-core 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-GFTW23FV.js → chunk-BGG2HVIR.js} +4 -2
- package/dist/{chunk-TOTDGK3P.js → chunk-CSR75JVC.js} +4 -5
- package/dist/{chunk-ICZ66572.js → chunk-CZ5XOVDV.js} +40 -9
- package/dist/{chunk-2O4MCSQS.js → chunk-FYC33XFI.js} +31 -10
- package/dist/{chunk-WBPOZ7CL.js → chunk-HNEI7JVE.js} +114 -38
- package/dist/{chunk-SPILYYDF.js → chunk-I7EJGKUP.js} +79 -7
- package/dist/{chunk-SSFBF3US.js → chunk-JPBFAQNS.js} +7 -12
- package/dist/{chunk-5FMSGQVX.js → chunk-JZRLCTSD.js} +8 -2
- package/dist/{chunk-V4RFNEET.js → chunk-MLTJHUVG.js} +34 -16
- package/dist/{chunk-QAL3OMI3.js → chunk-MO3N6M32.js} +4 -1
- package/dist/{chunk-CMYN2RCB.js → chunk-NWQUZWLT.js} +13 -7
- package/dist/{chunk-MXAP4UG6.js → chunk-QJV5XPPS.js} +238 -86
- package/dist/{chunk-T4UIX5D7.js → chunk-S6AKEPAX.js} +9 -3
- package/dist/{chunk-N3VX7FEE.js → chunk-STDJYXYK.js} +1 -4
- package/dist/{chunk-6HZBHFOL.js → chunk-TPZ37IWI.js} +10 -1
- package/dist/{chunk-NDZWXCBZ.js → chunk-TZ4VA4VX.js} +33 -11
- package/dist/chunk-US7S4FYW.js +610 -0
- package/dist/{chunk-RN6WZEUF.js → chunk-WI5JFEAI.js} +71 -36
- package/dist/{chunk-5NVVNXPQ.js → chunk-ZKEC7MFQ.js} +5 -30
- package/dist/dispatch/index.d.ts +5 -3
- package/dist/dispatch/index.js +3 -3
- package/dist/execution/index.d.ts +6 -4
- package/dist/execution/index.js +7 -7
- package/dist/index.d.ts +8 -5
- package/dist/index.js +119 -116
- package/dist/inference/errors/index.js +1 -1
- package/dist/inference/index.d.ts +6 -4
- package/dist/inference/index.js +6 -6
- package/dist/{instance-DzPiv6EK.d.ts → instance-N5VhcNT2.d.ts} +45 -7
- package/dist/logger/index.js +1 -1
- package/dist/mcp/index.d.ts +116 -3
- package/dist/mcp/index.js +6 -2
- package/dist/middleware/index.d.ts +5 -3
- package/dist/middleware/index.js +3 -3
- package/dist/{model-messages-CJfwfzGe.d.ts → model-messages-DnsiSiZj.d.ts} +1 -1
- package/dist/models/index.js +2 -2
- package/dist/models/reasoning/index.js +2 -2
- package/dist/plugin/index.d.ts +4 -2
- package/dist/plugin/index.js +1 -1
- package/dist/profiles/index.d.ts +4 -2
- package/dist/profiles/index.js +1 -1
- package/dist/prompt/index.d.ts +5 -3
- package/dist/prompt/index.js +2 -2
- package/dist/safety/index.d.ts +5 -3
- package/dist/safety/index.js +1 -1
- package/dist/skill/index.d.ts +5 -3
- package/dist/skill/index.js +2 -2
- package/dist/storage/index.d.ts +5 -3
- package/dist/storage/index.js +1 -1
- package/dist/subagents/index.d.ts +4 -2
- package/dist/subagents/index.js +4 -4
- package/dist/team/index.d.ts +5 -3
- package/dist/team/index.js +1 -1
- package/dist/tool/index.d.ts +5 -3
- package/dist/tool/index.js +2 -2
- package/dist/{types-Bj_J8u_W.d.ts → types-DMjoFKKv.d.ts} +55 -7
- package/package.json +1 -6
- package/dist/chunk-ROTGCYDW.js +0 -221
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSkillRegistry,
|
|
3
3
|
emptySkillRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I7EJGKUP.js";
|
|
5
5
|
import {
|
|
6
6
|
extractModelId,
|
|
7
7
|
extractProvider
|
|
@@ -311,7 +311,9 @@ function formatInstructions(files, basePath) {
|
|
|
311
311
|
for (const file of files) {
|
|
312
312
|
const displayPath = basePath ? file.path.replace(basePath + sep, "").replace(basePath, "") : basename2(file.path);
|
|
313
313
|
blocks.push("");
|
|
314
|
-
blocks.push(
|
|
314
|
+
blocks.push(
|
|
315
|
+
`<instructions source="${displayPath}" scope="${file.source}">`
|
|
316
|
+
);
|
|
315
317
|
blocks.push(file.content);
|
|
316
318
|
blocks.push("</instructions>");
|
|
317
319
|
}
|
|
@@ -16,7 +16,9 @@ ${skillList}
|
|
|
16
16
|
|
|
17
17
|
Only load a skill when the current task clearly matches its description. Skills provide detailed workflows, reference material, and scripts.`,
|
|
18
18
|
parameters: z.object({
|
|
19
|
-
name: z.string().describe(
|
|
19
|
+
name: z.string().describe(
|
|
20
|
+
"The name of the skill to load (must match one of the available skills)"
|
|
21
|
+
)
|
|
20
22
|
}),
|
|
21
23
|
execute: async ({ name }) => {
|
|
22
24
|
const content = await registry.loadContent(name);
|
|
@@ -78,10 +80,7 @@ function createSkillResourceTool(registry) {
|
|
|
78
80
|
}
|
|
79
81
|
function createSkillTools(registry) {
|
|
80
82
|
if (registry.size === 0) return [];
|
|
81
|
-
return [
|
|
82
|
-
createSkillTool(registry),
|
|
83
|
-
createSkillResourceTool(registry)
|
|
84
|
-
];
|
|
83
|
+
return [createSkillTool(registry), createSkillResourceTool(registry)];
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
export {
|
|
@@ -44,7 +44,8 @@ function serializeMessage(message) {
|
|
|
44
44
|
if ("tokens" in message) serialized.tokens = message.tokens;
|
|
45
45
|
if ("cost" in message) serialized.cost = message.cost;
|
|
46
46
|
if ("error" in message) serialized.error = message.error;
|
|
47
|
-
if ("toolCalls" in message && message.toolCalls)
|
|
47
|
+
if ("toolCalls" in message && message.toolCalls)
|
|
48
|
+
serialized.toolCalls = message.toolCalls;
|
|
48
49
|
}
|
|
49
50
|
if (message.role === "tool") {
|
|
50
51
|
if ("toolCallId" in message) serialized.toolCallId = message.toolCallId;
|
|
@@ -163,7 +164,9 @@ function getLeafId(entries) {
|
|
|
163
164
|
const hasChildren = /* @__PURE__ */ new Set();
|
|
164
165
|
for (const children of childMap.values()) {
|
|
165
166
|
for (const child of children) {
|
|
166
|
-
const entry = entries.find(
|
|
167
|
+
const entry = entries.find(
|
|
168
|
+
(e) => e.type !== "header" && e.id === child
|
|
169
|
+
);
|
|
167
170
|
if (entry && entry.type !== "header") {
|
|
168
171
|
const parentId = entry.parentId;
|
|
169
172
|
if (parentId) hasChildren.add(parentId);
|
|
@@ -281,7 +284,15 @@ var MemoryStorage = class {
|
|
|
281
284
|
};
|
|
282
285
|
|
|
283
286
|
// src/storage/file/helpers.ts
|
|
284
|
-
import {
|
|
287
|
+
import {
|
|
288
|
+
appendFile,
|
|
289
|
+
mkdir,
|
|
290
|
+
readFile,
|
|
291
|
+
readdir,
|
|
292
|
+
stat,
|
|
293
|
+
unlink,
|
|
294
|
+
writeFile
|
|
295
|
+
} from "fs/promises";
|
|
285
296
|
import { existsSync } from "fs";
|
|
286
297
|
import { basename, join } from "path";
|
|
287
298
|
async function ensureStorageDirectory(directory) {
|
|
@@ -391,7 +402,10 @@ var FileStorage = class {
|
|
|
391
402
|
if (this.useCache && this.cache.has(sessionId)) {
|
|
392
403
|
return this.cache.get(sessionId);
|
|
393
404
|
}
|
|
394
|
-
const entries = await loadEntriesFromDisk(
|
|
405
|
+
const entries = await loadEntriesFromDisk(
|
|
406
|
+
this.getPath(sessionId),
|
|
407
|
+
sessionId
|
|
408
|
+
);
|
|
395
409
|
if (this.useCache) {
|
|
396
410
|
this.cache.set(sessionId, entries);
|
|
397
411
|
}
|
|
@@ -448,9 +462,15 @@ var FileStorage = class {
|
|
|
448
462
|
async list() {
|
|
449
463
|
await this.ensureDir();
|
|
450
464
|
const infos = [];
|
|
451
|
-
for (const sessionId of await listSessionIds(
|
|
465
|
+
for (const sessionId of await listSessionIds(
|
|
466
|
+
this.directory,
|
|
467
|
+
this.extension
|
|
468
|
+
)) {
|
|
452
469
|
try {
|
|
453
|
-
const info = extractSessionInfo(
|
|
470
|
+
const info = extractSessionInfo(
|
|
471
|
+
await this.getEntries(sessionId),
|
|
472
|
+
this.getPath(sessionId)
|
|
473
|
+
);
|
|
454
474
|
if (info) {
|
|
455
475
|
infos.push(info);
|
|
456
476
|
}
|
|
@@ -490,7 +510,10 @@ function getDataDir(appName = "cuylabs") {
|
|
|
490
510
|
return join2(homedir(), `.${appName}`);
|
|
491
511
|
}
|
|
492
512
|
if (platform === "win32") {
|
|
493
|
-
return join2(
|
|
513
|
+
return join2(
|
|
514
|
+
process.env.APPDATA || join2(homedir(), "AppData", "Roaming"),
|
|
515
|
+
appName
|
|
516
|
+
);
|
|
494
517
|
}
|
|
495
518
|
const xdgData = process.env.XDG_DATA_HOME || join2(homedir(), ".local", "share");
|
|
496
519
|
return join2(xdgData, appName);
|
|
@@ -575,7 +598,11 @@ var SessionManager = class {
|
|
|
575
598
|
if (!this.currentSessionId) {
|
|
576
599
|
throw new Error("No session loaded");
|
|
577
600
|
}
|
|
578
|
-
const entry = createMessageEntry(
|
|
601
|
+
const entry = createMessageEntry(
|
|
602
|
+
message,
|
|
603
|
+
this.currentLeafId,
|
|
604
|
+
this.idsCache
|
|
605
|
+
);
|
|
579
606
|
await this.storage.append(this.currentSessionId, entry);
|
|
580
607
|
this.entriesCache.push(entry);
|
|
581
608
|
this.idsCache.add(entry.id);
|
|
@@ -690,7 +717,11 @@ var SessionManager = class {
|
|
|
690
717
|
if (!this.currentSessionId) {
|
|
691
718
|
throw new Error("No session loaded");
|
|
692
719
|
}
|
|
693
|
-
const entry = createMetadataEntry(
|
|
720
|
+
const entry = createMetadataEntry(
|
|
721
|
+
updates,
|
|
722
|
+
this.currentLeafId,
|
|
723
|
+
this.idsCache
|
|
724
|
+
);
|
|
694
725
|
await this.storage.append(this.currentSessionId, entry);
|
|
695
726
|
this.entriesCache.push(entry);
|
|
696
727
|
this.idsCache.add(entry.id);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Profiles
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TPZ37IWI.js";
|
|
4
4
|
import {
|
|
5
5
|
createLocalDispatchRuntime
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JPBFAQNS.js";
|
|
7
7
|
import {
|
|
8
8
|
Tool
|
|
9
9
|
} from "./chunk-Q742PSH3.js";
|
|
@@ -168,7 +168,9 @@ Guidelines:
|
|
|
168
168
|
}
|
|
169
169
|
function toCompletedResult(record) {
|
|
170
170
|
if (!record.result || !record.sessionId) {
|
|
171
|
-
throw new Error(
|
|
171
|
+
throw new Error(
|
|
172
|
+
`Dispatch "${record.id}" did not produce a completed result.`
|
|
173
|
+
);
|
|
172
174
|
}
|
|
173
175
|
return {
|
|
174
176
|
response: record.result.response,
|
|
@@ -200,7 +202,9 @@ function formatTerminalFailure(record) {
|
|
|
200
202
|
);
|
|
201
203
|
}
|
|
202
204
|
return formatWaitErrorResult(
|
|
203
|
-
new Error(
|
|
205
|
+
new Error(
|
|
206
|
+
`Subagent "${record.id}" is in unexpected state "${record.status}".`
|
|
207
|
+
)
|
|
204
208
|
);
|
|
205
209
|
}
|
|
206
210
|
function createInvokeAgentTool(runtime, roles, options) {
|
|
@@ -238,7 +242,11 @@ function createInvokeAgentTool(runtime, roles, options) {
|
|
|
238
242
|
);
|
|
239
243
|
}
|
|
240
244
|
if (isAsync) {
|
|
241
|
-
return formatAsyncSpawnedResult(
|
|
245
|
+
return formatAsyncSpawnedResult(
|
|
246
|
+
started.id,
|
|
247
|
+
role.name,
|
|
248
|
+
started.sessionId
|
|
249
|
+
);
|
|
242
250
|
}
|
|
243
251
|
try {
|
|
244
252
|
const finished = await waitForTerminalDispatch(runtime, started.id);
|
|
@@ -377,7 +385,9 @@ function getConfiguredSubAgents(agent) {
|
|
|
377
385
|
return installedSubAgents.get(agent)?.config;
|
|
378
386
|
}
|
|
379
387
|
function getInstalledSubAgentBackend(agent) {
|
|
380
|
-
const backend = installedSubAgents.get(
|
|
388
|
+
const backend = installedSubAgents.get(
|
|
389
|
+
agent
|
|
390
|
+
)?.backend;
|
|
381
391
|
return backend && backend !== "uninstalled" ? backend : void 0;
|
|
382
392
|
}
|
|
383
393
|
function clearInstalledSubAgents(agent) {
|
|
@@ -517,7 +527,9 @@ function parseSubAgentToolSpec(raw) {
|
|
|
517
527
|
if (parts.length === 0) {
|
|
518
528
|
return { mode: "inherit" };
|
|
519
529
|
}
|
|
520
|
-
const hasModified = parts.some(
|
|
530
|
+
const hasModified = parts.some(
|
|
531
|
+
(part) => part.startsWith("+") || part.startsWith("-")
|
|
532
|
+
);
|
|
521
533
|
if (hasModified) {
|
|
522
534
|
return {
|
|
523
535
|
mode: "modifiers",
|
|
@@ -553,7 +565,10 @@ function toSubAgentRole(parsed, resolvers = {}) {
|
|
|
553
565
|
const toolSpec = parseSubAgentToolSpec(frontmatter.tools);
|
|
554
566
|
if (toolSpec.mode === "explicit" || toolSpec.mode === "modifiers") {
|
|
555
567
|
resolvedProfile = {
|
|
556
|
-
...resolvedProfile ?? {
|
|
568
|
+
...resolvedProfile ?? {
|
|
569
|
+
name: "custom",
|
|
570
|
+
description: "Markdown-defined role"
|
|
571
|
+
}
|
|
557
572
|
};
|
|
558
573
|
if (toolSpec.mode === "explicit") {
|
|
559
574
|
resolvedProfile.allowTools = toolSpec.patterns;
|
|
@@ -643,7 +658,10 @@ function loadRoleDir(dir, source, resolvers, errors, onRole) {
|
|
|
643
658
|
const content = readFileSync(filePath, "utf-8");
|
|
644
659
|
const parsed = parseMarkdownSubAgentRole(content, filePath);
|
|
645
660
|
if (!parsed) {
|
|
646
|
-
errors.push({
|
|
661
|
+
errors.push({
|
|
662
|
+
path: filePath,
|
|
663
|
+
error: "Missing required frontmatter (name, description)"
|
|
664
|
+
});
|
|
647
665
|
continue;
|
|
648
666
|
}
|
|
649
667
|
const role = toSubAgentRole(parsed, resolvers);
|
|
@@ -668,7 +686,10 @@ function loadRoleFile(filePath, source, resolvers, errors, onRole) {
|
|
|
668
686
|
const content = readFileSync(filePath, "utf-8");
|
|
669
687
|
const parsed = parseMarkdownSubAgentRole(content, filePath);
|
|
670
688
|
if (!parsed) {
|
|
671
|
-
errors.push({
|
|
689
|
+
errors.push({
|
|
690
|
+
path: filePath,
|
|
691
|
+
error: "Missing required frontmatter (name, description)"
|
|
692
|
+
});
|
|
672
693
|
return null;
|
|
673
694
|
}
|
|
674
695
|
const role = toSubAgentRole(parsed, resolvers);
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Inference,
|
|
3
3
|
buildModelCallContext
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NWQUZWLT.js";
|
|
5
5
|
import {
|
|
6
|
-
PRUNE_PROTECTED_TOOLS,
|
|
7
|
-
accumulateUsage,
|
|
8
6
|
currentScope,
|
|
9
7
|
executeAgentToolCall,
|
|
10
8
|
snapshotScope,
|
|
11
9
|
streamWithinScope,
|
|
12
10
|
withinScope
|
|
13
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ZKEC7MFQ.js";
|
|
14
12
|
import {
|
|
15
13
|
LLMError
|
|
16
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-STDJYXYK.js";
|
|
17
15
|
import {
|
|
18
16
|
extractModelId,
|
|
19
17
|
extractProvider
|
|
@@ -23,7 +21,7 @@ import {
|
|
|
23
21
|
} from "./chunk-FII65CN7.js";
|
|
24
22
|
import {
|
|
25
23
|
silentLogger
|
|
26
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-S6AKEPAX.js";
|
|
27
25
|
|
|
28
26
|
// src/execution/task/observer.ts
|
|
29
27
|
function defaultAgentTaskCheckpointStrategy(input) {
|
|
@@ -321,13 +319,21 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
321
319
|
event,
|
|
322
320
|
createdAt: turnState.updatedAt
|
|
323
321
|
};
|
|
324
|
-
await notifyObservers(
|
|
325
|
-
|
|
326
|
-
|
|
322
|
+
await notifyObservers(
|
|
323
|
+
baseObservers,
|
|
324
|
+
async (observer) => {
|
|
325
|
+
await observer.onCheckpoint?.(checkpoint);
|
|
326
|
+
},
|
|
327
|
+
log
|
|
328
|
+
);
|
|
327
329
|
};
|
|
328
|
-
await notifyObservers(
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
await notifyObservers(
|
|
331
|
+
baseObservers,
|
|
332
|
+
async (observer) => {
|
|
333
|
+
await observer.onTaskStart?.(run, createSnapshot());
|
|
334
|
+
},
|
|
335
|
+
log
|
|
336
|
+
);
|
|
331
337
|
await emitCheckpoint("task-start");
|
|
332
338
|
const activateCtx = baseObservers.find((o) => o.activateContext)?.activateContext?.bind(void 0, sessionId, executionId);
|
|
333
339
|
try {
|
|
@@ -341,9 +347,13 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
341
347
|
toolCalls.push({ name: event.toolName, result: event.result });
|
|
342
348
|
}
|
|
343
349
|
const snapshot = createSnapshot();
|
|
344
|
-
await notifyObservers(
|
|
345
|
-
|
|
346
|
-
|
|
350
|
+
await notifyObservers(
|
|
351
|
+
baseObservers,
|
|
352
|
+
async (observer) => {
|
|
353
|
+
await observer.onTaskEvent?.(run, event, snapshot);
|
|
354
|
+
},
|
|
355
|
+
log
|
|
356
|
+
);
|
|
347
357
|
const checkpointReason = checkpointStrategy({
|
|
348
358
|
run,
|
|
349
359
|
event,
|
|
@@ -368,16 +378,28 @@ function createAgentTaskRunner(agent, options = {}) {
|
|
|
368
378
|
usage: { ...turnState.usage },
|
|
369
379
|
toolCalls
|
|
370
380
|
};
|
|
371
|
-
await notifyObservers(
|
|
372
|
-
|
|
373
|
-
|
|
381
|
+
await notifyObservers(
|
|
382
|
+
baseObservers,
|
|
383
|
+
async (observer) => {
|
|
384
|
+
await observer.onTaskComplete?.(run, result, createSnapshot());
|
|
385
|
+
},
|
|
386
|
+
log
|
|
387
|
+
);
|
|
374
388
|
return result;
|
|
375
389
|
} catch (error) {
|
|
376
390
|
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
377
391
|
turnState = failAgentTurnState(turnState, normalizedError, nowIso());
|
|
378
|
-
await notifyObservers(
|
|
379
|
-
|
|
380
|
-
|
|
392
|
+
await notifyObservers(
|
|
393
|
+
baseObservers,
|
|
394
|
+
async (observer) => {
|
|
395
|
+
await observer.onTaskError?.(
|
|
396
|
+
run,
|
|
397
|
+
normalizedError,
|
|
398
|
+
createSnapshot()
|
|
399
|
+
);
|
|
400
|
+
},
|
|
401
|
+
log
|
|
402
|
+
);
|
|
381
403
|
await emitCheckpoint("task-error");
|
|
382
404
|
throw normalizedError;
|
|
383
405
|
}
|
|
@@ -633,6 +655,9 @@ function estimateConversationTokens(messages) {
|
|
|
633
655
|
return total;
|
|
634
656
|
}
|
|
635
657
|
|
|
658
|
+
// src/types/compaction.ts
|
|
659
|
+
var PRUNE_PROTECTED_TOOLS = ["skill"];
|
|
660
|
+
|
|
636
661
|
// src/agent/context/pruning.ts
|
|
637
662
|
var DEFAULT_CONTEXT_LIMITS = {
|
|
638
663
|
contextWindow: 128e3,
|
|
@@ -744,18 +769,36 @@ async function pruneContext(messages, options = {}) {
|
|
|
744
769
|
let summary;
|
|
745
770
|
const initialTokens = estimateConversationTokens(currentMessages);
|
|
746
771
|
if (!shouldPruneContext(initialTokens, limits)) {
|
|
747
|
-
return {
|
|
772
|
+
return {
|
|
773
|
+
messages: currentMessages,
|
|
774
|
+
removedCount: 0,
|
|
775
|
+
tokensRemoved: 0,
|
|
776
|
+
summarized: false
|
|
777
|
+
};
|
|
748
778
|
}
|
|
749
|
-
const prunedMessages = pruneToolResults(
|
|
779
|
+
const prunedMessages = pruneToolResults(
|
|
780
|
+
currentMessages,
|
|
781
|
+
limits.protectedTokens
|
|
782
|
+
);
|
|
750
783
|
const afterPruneTokens = estimateConversationTokens(prunedMessages);
|
|
751
784
|
tokensRemoved = initialTokens - afterPruneTokens;
|
|
752
785
|
currentMessages = prunedMessages;
|
|
753
786
|
if (!isContextOverflowing(afterPruneTokens, limits)) {
|
|
754
|
-
return {
|
|
787
|
+
return {
|
|
788
|
+
messages: currentMessages,
|
|
789
|
+
removedCount: 0,
|
|
790
|
+
tokensRemoved,
|
|
791
|
+
summarized: false
|
|
792
|
+
};
|
|
755
793
|
}
|
|
756
794
|
const cutIndex = findCutPoint(currentMessages, limits.protectedTokens);
|
|
757
795
|
if (cutIndex === 0) {
|
|
758
|
-
return {
|
|
796
|
+
return {
|
|
797
|
+
messages: currentMessages,
|
|
798
|
+
removedCount: 0,
|
|
799
|
+
tokensRemoved,
|
|
800
|
+
summarized: false
|
|
801
|
+
};
|
|
759
802
|
}
|
|
760
803
|
const toSummarize = currentMessages.slice(0, cutIndex);
|
|
761
804
|
const toKeep = currentMessages.slice(cutIndex);
|
|
@@ -779,7 +822,13 @@ ${summary}`,
|
|
|
779
822
|
} else {
|
|
780
823
|
currentMessages = toKeep;
|
|
781
824
|
}
|
|
782
|
-
return {
|
|
825
|
+
return {
|
|
826
|
+
messages: currentMessages,
|
|
827
|
+
removedCount,
|
|
828
|
+
tokensRemoved,
|
|
829
|
+
summarized,
|
|
830
|
+
summary
|
|
831
|
+
};
|
|
783
832
|
}
|
|
784
833
|
|
|
785
834
|
// src/agent/context/manager.ts
|
|
@@ -1327,6 +1376,29 @@ async function* runModelStep(options) {
|
|
|
1327
1376
|
);
|
|
1328
1377
|
}
|
|
1329
1378
|
|
|
1379
|
+
// src/types/messages.ts
|
|
1380
|
+
function accumulateUsage(current, next) {
|
|
1381
|
+
if (!next) return current;
|
|
1382
|
+
if (!current) {
|
|
1383
|
+
return {
|
|
1384
|
+
inputTokens: next.inputTokens ?? 0,
|
|
1385
|
+
outputTokens: next.outputTokens ?? 0,
|
|
1386
|
+
totalTokens: next.totalTokens ?? 0,
|
|
1387
|
+
cacheReadTokens: (next.cacheReadTokens ?? 0) || void 0,
|
|
1388
|
+
cacheWriteTokens: (next.cacheWriteTokens ?? 0) || void 0
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
const cacheRead = (current.cacheReadTokens ?? 0) + (next.cacheReadTokens ?? 0);
|
|
1392
|
+
const cacheWrite = (current.cacheWriteTokens ?? 0) + (next.cacheWriteTokens ?? 0);
|
|
1393
|
+
return {
|
|
1394
|
+
inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
|
|
1395
|
+
outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
|
|
1396
|
+
totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0),
|
|
1397
|
+
cacheReadTokens: cacheRead || void 0,
|
|
1398
|
+
cacheWriteTokens: cacheWrite || void 0
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1330
1402
|
// src/execution/turn-runner/tool-batch.ts
|
|
1331
1403
|
function cloneToolResultRecord(options) {
|
|
1332
1404
|
return new Map(
|
|
@@ -1453,11 +1525,7 @@ async function runToolBatch(options) {
|
|
|
1453
1525
|
let safe = false;
|
|
1454
1526
|
let initialized;
|
|
1455
1527
|
try {
|
|
1456
|
-
const result = await isParallelSafe(
|
|
1457
|
-
tool,
|
|
1458
|
-
toolCall.args,
|
|
1459
|
-
options.cwd
|
|
1460
|
-
);
|
|
1528
|
+
const result = await isParallelSafe(tool, toolCall.args, options.cwd);
|
|
1461
1529
|
safe = result.safe;
|
|
1462
1530
|
initialized = result.initialized;
|
|
1463
1531
|
} catch {
|
|
@@ -1586,7 +1654,11 @@ function cloneAgentWorkflowTurnState(state) {
|
|
|
1586
1654
|
...state,
|
|
1587
1655
|
systemPrompts: [...state.systemPrompts],
|
|
1588
1656
|
messages: state.messages.map(cloneMessageSnapshot),
|
|
1589
|
-
...state.pendingInput ? {
|
|
1657
|
+
...state.pendingInput ? {
|
|
1658
|
+
pendingInput: cloneMessageSnapshot(
|
|
1659
|
+
state.pendingInput
|
|
1660
|
+
)
|
|
1661
|
+
} : {},
|
|
1590
1662
|
...state.usage ? { usage: cloneUsage(state.usage) } : {},
|
|
1591
1663
|
...state.turnState ? { turnState: structuredClone(state.turnState) } : {},
|
|
1592
1664
|
...state.lastModelStep ? { lastModelStep: structuredClone(state.lastModelStep) } : {},
|
|
@@ -1612,12 +1684,14 @@ function applyWorkflowInterventions(state, interventions, updatedAt) {
|
|
|
1612
1684
|
if (interventions.length === 0) {
|
|
1613
1685
|
return state;
|
|
1614
1686
|
}
|
|
1615
|
-
const injected = interventions.map(
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1687
|
+
const injected = interventions.map(
|
|
1688
|
+
(intervention) => ({
|
|
1689
|
+
id: intervention.id,
|
|
1690
|
+
role: "user",
|
|
1691
|
+
createdAt: intervention.createdAt,
|
|
1692
|
+
content: intervention.message
|
|
1693
|
+
})
|
|
1694
|
+
);
|
|
1621
1695
|
return {
|
|
1622
1696
|
...state,
|
|
1623
1697
|
messages: [...state.messages, ...injected],
|
|
@@ -1982,6 +2056,7 @@ export {
|
|
|
1982
2056
|
estimateTokens,
|
|
1983
2057
|
estimateMessageTokens,
|
|
1984
2058
|
estimateConversationTokens,
|
|
2059
|
+
PRUNE_PROTECTED_TOOLS,
|
|
1985
2060
|
DEFAULT_CONTEXT_LIMITS,
|
|
1986
2061
|
getUsableTokenLimit,
|
|
1987
2062
|
findCutPoint,
|
|
@@ -1991,6 +2066,7 @@ export {
|
|
|
1991
2066
|
ContextOverflowError,
|
|
1992
2067
|
processStepStream,
|
|
1993
2068
|
runModelStep,
|
|
2069
|
+
accumulateUsage,
|
|
1994
2070
|
runToolBatch,
|
|
1995
2071
|
commitStep,
|
|
1996
2072
|
commitOutput,
|
|
@@ -118,9 +118,14 @@ async function loadSkillMetadata(filePath, scope, source, maxSize) {
|
|
|
118
118
|
import { readFile as readFile2, readdir, stat as stat2 } from "fs/promises";
|
|
119
119
|
import { extname, join as join2, relative } from "path";
|
|
120
120
|
async function loadSkillContent(metadata) {
|
|
121
|
+
if (!metadata.filePath) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Cannot load skill content for "${metadata.name}": no file path. Pack-contributed skills must have content pre-cached via SkillRegistry.register(metadata, content).`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
121
126
|
const raw = await readFile2(metadata.filePath, "utf-8");
|
|
122
127
|
const { body } = parseFrontmatter(raw);
|
|
123
|
-
const resources = await scanSkillResources(metadata.baseDir);
|
|
128
|
+
const resources = await scanSkillResources(metadata.baseDir ?? "");
|
|
124
129
|
return {
|
|
125
130
|
...metadata,
|
|
126
131
|
body,
|
|
@@ -128,6 +133,14 @@ async function loadSkillContent(metadata) {
|
|
|
128
133
|
};
|
|
129
134
|
}
|
|
130
135
|
async function loadResourceContent(resource) {
|
|
136
|
+
if (resource.content !== void 0) {
|
|
137
|
+
return resource.content;
|
|
138
|
+
}
|
|
139
|
+
if (!resource.absolutePath) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Resource "${resource.relativePath}" has no content or absolute path.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
131
144
|
return readFile2(resource.absolutePath, "utf-8");
|
|
132
145
|
}
|
|
133
146
|
async function scanSkillResources(baseDir) {
|
|
@@ -158,7 +171,14 @@ async function collectFiles(dirPath, baseDir, type, resources, maxDepth = 3, cur
|
|
|
158
171
|
absolutePath: fullPath
|
|
159
172
|
});
|
|
160
173
|
} else if (entry.isDirectory()) {
|
|
161
|
-
await collectFiles(
|
|
174
|
+
await collectFiles(
|
|
175
|
+
fullPath,
|
|
176
|
+
baseDir,
|
|
177
|
+
type,
|
|
178
|
+
resources,
|
|
179
|
+
maxDepth,
|
|
180
|
+
currentDepth + 1
|
|
181
|
+
);
|
|
162
182
|
}
|
|
163
183
|
}
|
|
164
184
|
} catch {
|
|
@@ -197,7 +217,9 @@ function deduplicateSkills(skills) {
|
|
|
197
217
|
byName.set(skill.name, skill);
|
|
198
218
|
}
|
|
199
219
|
}
|
|
200
|
-
return Array.from(byName.values()).sort(
|
|
220
|
+
return Array.from(byName.values()).sort(
|
|
221
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
222
|
+
);
|
|
201
223
|
}
|
|
202
224
|
|
|
203
225
|
// src/skill/discovery/fs.ts
|
|
@@ -256,7 +278,9 @@ async function scanRoot(root, maxDepth, maxFileSize = DEFAULT_SKILL_MAX_SIZE) {
|
|
|
256
278
|
dirsScanned++;
|
|
257
279
|
try {
|
|
258
280
|
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
259
|
-
const hasSkillFile = entries.some(
|
|
281
|
+
const hasSkillFile = entries.some(
|
|
282
|
+
(entry) => entry.isFile() && entry.name === SKILL_FILENAME
|
|
283
|
+
);
|
|
260
284
|
if (hasSkillFile) {
|
|
261
285
|
const filePath = join4(dirPath, SKILL_FILENAME);
|
|
262
286
|
const metadata = await loadSkillMetadata(
|
|
@@ -304,7 +328,11 @@ async function discoverSkills(cwd, config) {
|
|
|
304
328
|
if (config?.roots) {
|
|
305
329
|
for (const root of config.roots) {
|
|
306
330
|
const absRoot = resolve2(resolvedCwd, root);
|
|
307
|
-
roots.push({
|
|
331
|
+
roots.push({
|
|
332
|
+
path: absRoot,
|
|
333
|
+
scope: "global",
|
|
334
|
+
source: { type: "local", root: absRoot }
|
|
335
|
+
});
|
|
308
336
|
}
|
|
309
337
|
}
|
|
310
338
|
const home = homedir();
|
|
@@ -488,9 +516,13 @@ var SkillRegistry = class {
|
|
|
488
516
|
lines.push("");
|
|
489
517
|
lines.push(`<skill name="${skill.name}" scope="${skill.scope}">`);
|
|
490
518
|
lines.push(` <description>${skill.description}</description>`);
|
|
491
|
-
|
|
519
|
+
if (skill.filePath) {
|
|
520
|
+
lines.push(` <file>${skill.filePath}</file>`);
|
|
521
|
+
}
|
|
492
522
|
if (skill.dependencies && skill.dependencies.length > 0) {
|
|
493
|
-
lines.push(
|
|
523
|
+
lines.push(
|
|
524
|
+
` <depends-on>${skill.dependencies.join(", ")}</depends-on>`
|
|
525
|
+
);
|
|
494
526
|
}
|
|
495
527
|
lines.push("</skill>");
|
|
496
528
|
}
|
|
@@ -546,6 +578,46 @@ var SkillRegistry = class {
|
|
|
546
578
|
// ==========================================================================
|
|
547
579
|
// Cache Management
|
|
548
580
|
// ==========================================================================
|
|
581
|
+
// ==========================================================================
|
|
582
|
+
// External Registration (for capability packs)
|
|
583
|
+
// ==========================================================================
|
|
584
|
+
/**
|
|
585
|
+
* Register an externally defined skill with optional pre-loaded content.
|
|
586
|
+
*
|
|
587
|
+
* Intended for capability packs that contribute skills without placing
|
|
588
|
+
* files on disk — the pack's inline body is stored directly in the
|
|
589
|
+
* content cache so the agent can load it without a file read.
|
|
590
|
+
*
|
|
591
|
+
* **Priority:** registered skills have lower priority than discovered
|
|
592
|
+
* skills. If a skill with the same name was already found during
|
|
593
|
+
* discovery, the discovered skill wins and this call is a no-op.
|
|
594
|
+
*
|
|
595
|
+
* @param metadata L1 metadata describing the skill.
|
|
596
|
+
* @param content Pre-built content (L2). When provided, this is stored
|
|
597
|
+
* in the cache so `loadContent()` never reads a file.
|
|
598
|
+
*/
|
|
599
|
+
register(metadata, content) {
|
|
600
|
+
const existing = this.skills.get(metadata.name);
|
|
601
|
+
if (existing) {
|
|
602
|
+
const protectedExisting = existing.scope === "builtin" || existing.source.type === "local" || existing.filePath !== void 0 || existing.baseDir !== void 0;
|
|
603
|
+
if (protectedExisting) {
|
|
604
|
+
return "skipped";
|
|
605
|
+
}
|
|
606
|
+
this.skills.set(metadata.name, metadata);
|
|
607
|
+
if (content) {
|
|
608
|
+
this.contentCache.set(metadata.name, content);
|
|
609
|
+
}
|
|
610
|
+
return "updated";
|
|
611
|
+
}
|
|
612
|
+
this.skills.set(metadata.name, metadata);
|
|
613
|
+
if (content) {
|
|
614
|
+
this.contentCache.set(metadata.name, content);
|
|
615
|
+
}
|
|
616
|
+
return "registered";
|
|
617
|
+
}
|
|
618
|
+
// ==========================================================================
|
|
619
|
+
// Cache Management
|
|
620
|
+
// ==========================================================================
|
|
549
621
|
/** Clear the content cache, forcing reloads on next access. */
|
|
550
622
|
clearContentCache() {
|
|
551
623
|
this.contentCache.clear();
|