@aigne/core 1.72.0-beta.10 → 1.72.0-beta.12
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/CHANGELOG.md +22 -0
- package/lib/cjs/agents/agent.d.ts +1 -0
- package/lib/cjs/agents/agent.js +3 -0
- package/lib/cjs/agents/ai-agent.js +4 -17
- package/lib/cjs/prompt/agent-session.d.ts +20 -2
- package/lib/cjs/prompt/agent-session.js +103 -27
- package/lib/cjs/prompt/compact/types.d.ts +7 -0
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.d.ts +2 -1
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.js +4 -4
- package/lib/cjs/prompt/skills/afs/agent-skill/skill-loader.js +4 -2
- package/lib/dts/agents/agent.d.ts +1 -0
- package/lib/dts/prompt/agent-session.d.ts +20 -2
- package/lib/dts/prompt/compact/types.d.ts +7 -0
- package/lib/dts/prompt/skills/afs/agent-skill/agent-skill.d.ts +2 -1
- package/lib/esm/agents/agent.d.ts +1 -0
- package/lib/esm/agents/agent.js +3 -0
- package/lib/esm/agents/ai-agent.js +4 -17
- package/lib/esm/prompt/agent-session.d.ts +20 -2
- package/lib/esm/prompt/agent-session.js +103 -27
- package/lib/esm/prompt/compact/types.d.ts +7 -0
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.d.ts +2 -1
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.js +4 -4
- package/lib/esm/prompt/skills/afs/agent-skill/skill-loader.js +4 -2
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.72.0-beta.12](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.72.0-beta.11...core-v1.72.0-beta.12) (2026-01-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **afs:** support `~` in the local path for local-fs & add agent-skill example ([#877](https://github.com/AIGNE-io/aigne-framework/issues/877)) ([c86293f](https://github.com/AIGNE-io/aigne-framework/commit/c86293f3d70447974395d02e238305a42b256b66))
|
|
9
|
+
|
|
10
|
+
## [1.72.0-beta.11](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.72.0-beta.10...core-v1.72.0-beta.11) (2026-01-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **core:** preserve Agent Skill in session compact and support complex tool result content ([#876](https://github.com/AIGNE-io/aigne-framework/issues/876)) ([edb86ae](https://github.com/AIGNE-io/aigne-framework/commit/edb86ae2b9cfe56a8f08b276f843606e310566cf))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Dependencies
|
|
19
|
+
|
|
20
|
+
* The following workspace dependencies were updated
|
|
21
|
+
* dependencies
|
|
22
|
+
* @aigne/afs bumped to 1.4.0-beta.6
|
|
23
|
+
* @aigne/afs-history bumped to 1.2.0-beta.7
|
|
24
|
+
|
|
3
25
|
## [1.72.0-beta.10](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.72.0-beta.9...core-v1.72.0-beta.10) (2026-01-06)
|
|
4
26
|
|
|
5
27
|
|
|
@@ -513,6 +513,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
513
513
|
*/
|
|
514
514
|
protected postprocess(input: I, output: O, options: AgentInvokeOptions): Promise<void>;
|
|
515
515
|
protected publishToTopics(output: Message, options: AgentInvokeOptions): Promise<void>;
|
|
516
|
+
formatOutput(output: O): PromiseOrValue<string>;
|
|
516
517
|
/**
|
|
517
518
|
* Core processing method of the agent, must be implemented in subclasses
|
|
518
519
|
*
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -454,21 +454,6 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
454
454
|
}
|
|
455
455
|
const message = { role: "agent", toolCalls };
|
|
456
456
|
yield { progress: { event: "message", message } };
|
|
457
|
-
const skillToolUse = toolCallsWithTools.find((i) => i.tool instanceof agent_skill_js_1.AgentSkill);
|
|
458
|
-
if (skillToolUse) {
|
|
459
|
-
await session.endMessage(skillToolUse.function, {
|
|
460
|
-
role: "agent",
|
|
461
|
-
content: JSON.stringify({ ...skillToolUse.function }),
|
|
462
|
-
}, options);
|
|
463
|
-
const skillResult = await this.invokeSkill(skillToolUse.tool, { ...input, ...skillToolUse.function.arguments }, options);
|
|
464
|
-
await session.startMessage(skillToolUse.function.arguments, {
|
|
465
|
-
role: "user",
|
|
466
|
-
content: [
|
|
467
|
-
{ type: "text", text: agent_skill_js_1.AgentSkill.formatOutput(skillResult), isAgentSkill: true },
|
|
468
|
-
],
|
|
469
|
-
}, options);
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
457
|
await session.appendCurrentMessages(message, options);
|
|
473
458
|
const executedToolCalls = [];
|
|
474
459
|
let error;
|
|
@@ -502,11 +487,13 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
502
487
|
throw error;
|
|
503
488
|
// Continue LLM function calling loop if any tools were executed
|
|
504
489
|
if (executedToolCalls.length) {
|
|
505
|
-
for (const { call, output } of executedToolCalls) {
|
|
490
|
+
for (const { call, tool, output } of executedToolCalls) {
|
|
491
|
+
const isAgentSkill = !output.isError && tool instanceof agent_skill_js_1.AgentSkill ? true : undefined;
|
|
492
|
+
const text = await tool.formatOutput(output);
|
|
506
493
|
const message = {
|
|
507
494
|
role: "tool",
|
|
508
495
|
toolCallId: call.id,
|
|
509
|
-
content:
|
|
496
|
+
content: [{ type: "text", text, isAgentSkill }],
|
|
510
497
|
};
|
|
511
498
|
yield { progress: { event: "message", message: message } };
|
|
512
499
|
await session.appendCurrentMessages(message, options);
|
|
@@ -103,8 +103,8 @@ export declare class AgentSession {
|
|
|
103
103
|
*/
|
|
104
104
|
private loadUserMemory;
|
|
105
105
|
/**
|
|
106
|
-
* Load session history including compact
|
|
107
|
-
* @returns Object containing compact
|
|
106
|
+
* Load session history including compact content and history entries
|
|
107
|
+
* @returns Object containing history compact and history entries
|
|
108
108
|
*/
|
|
109
109
|
private loadSessionHistory;
|
|
110
110
|
/**
|
|
@@ -125,6 +125,24 @@ export declare class AgentSession {
|
|
|
125
125
|
* Internal method that performs the actual user memory extraction
|
|
126
126
|
*/
|
|
127
127
|
private doUpdateUserMemory;
|
|
128
|
+
/**
|
|
129
|
+
* Find Agent Skill content from a single message
|
|
130
|
+
* @param msg - Message to search in
|
|
131
|
+
* @returns The skill content text if found, undefined otherwise
|
|
132
|
+
*/
|
|
133
|
+
private findSkillContentInMessage;
|
|
134
|
+
/**
|
|
135
|
+
* Find the last Agent Skill from a list of messages
|
|
136
|
+
* @param messages - Messages to search through
|
|
137
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
138
|
+
*/
|
|
139
|
+
private findLastAgentSkillFromMessages;
|
|
140
|
+
/**
|
|
141
|
+
* Find the last Agent Skill from a list of history entries
|
|
142
|
+
* @param entries - History entries to search through
|
|
143
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
144
|
+
*/
|
|
145
|
+
private findLastAgentSkill;
|
|
128
146
|
private initializeDefaultCompactor;
|
|
129
147
|
private initializeDefaultSessionMemoryExtractor;
|
|
130
148
|
private initializeDefaultUserMemoryExtractor;
|
|
@@ -87,42 +87,59 @@ class AgentSession {
|
|
|
87
87
|
}
|
|
88
88
|
async getMessages() {
|
|
89
89
|
await this.ensureInitialized();
|
|
90
|
-
const { systemMessages, userMemory, sessionMemory,
|
|
90
|
+
const { systemMessages, userMemory, sessionMemory, historyCompact, historyEntries, currentEntry, currentEntryCompact, } = this.runtimeState;
|
|
91
91
|
let currentMessages = [];
|
|
92
92
|
if (currentEntry?.messages?.length) {
|
|
93
|
-
if (
|
|
94
|
-
const { compressedCount, summary } =
|
|
95
|
-
const firstMsg = currentEntry.messages[0];
|
|
96
|
-
const hasSkill = firstMsg?.role === "user" &&
|
|
97
|
-
Array.isArray(firstMsg.content) &&
|
|
98
|
-
firstMsg.content.some((block) => block.type === "text" && block.isAgentSkill === true);
|
|
99
|
-
const skillMessage = hasSkill ? [firstMsg] : [];
|
|
93
|
+
if (currentEntryCompact) {
|
|
94
|
+
const { compressedCount, summary } = currentEntryCompact;
|
|
100
95
|
const summaryMessage = {
|
|
101
96
|
role: "user",
|
|
102
97
|
content: `[Earlier messages in this conversation (${compressedCount} messages compressed)]\n${summary}`,
|
|
103
98
|
};
|
|
104
99
|
const remainingMessages = currentEntry.messages.slice(compressedCount);
|
|
105
|
-
currentMessages = [
|
|
100
|
+
currentMessages = [summaryMessage, ...remainingMessages];
|
|
106
101
|
}
|
|
107
102
|
else {
|
|
108
103
|
currentMessages = currentEntry.messages;
|
|
109
104
|
}
|
|
110
105
|
}
|
|
106
|
+
// Flatten history entries messages once
|
|
107
|
+
const historyMessages = historyEntries.flatMap((entry) => entry.content?.messages ?? []);
|
|
108
|
+
// Check if there's an Agent Skill in current uncompressed messages
|
|
109
|
+
const hasSkillInCurrentMessages = [...historyMessages, ...currentMessages].some((msg) => msg.role === "user" &&
|
|
110
|
+
Array.isArray(msg.content) &&
|
|
111
|
+
msg.content.some((block) => block.type === "text" && block.isAgentSkill === true));
|
|
112
|
+
// Prefer currentEntryCompact's lastAgentSkill over historyCompact's (newer takes priority)
|
|
113
|
+
const lastAgentSkillToInject = currentEntryCompact?.lastAgentSkill ?? historyCompact?.lastAgentSkill;
|
|
111
114
|
const messages = [
|
|
112
115
|
...(systemMessages ?? []),
|
|
113
116
|
...(userMemory && userMemory.length > 0 ? [this.formatUserMemory(userMemory)] : []),
|
|
114
117
|
...(sessionMemory && sessionMemory.length > 0
|
|
115
118
|
? [this.formatSessionMemory(sessionMemory)]
|
|
116
119
|
: []),
|
|
117
|
-
...(
|
|
120
|
+
...(historyCompact?.summary
|
|
118
121
|
? [
|
|
119
122
|
{
|
|
120
123
|
role: "system",
|
|
121
|
-
content: `Previous conversation summary:\n${
|
|
124
|
+
content: `Previous conversation summary:\n${historyCompact.summary}`,
|
|
122
125
|
},
|
|
123
126
|
]
|
|
124
127
|
: []),
|
|
125
|
-
|
|
128
|
+
// Only inject lastAgentSkill if there's no skill in current messages
|
|
129
|
+
...(lastAgentSkillToInject && !hasSkillInCurrentMessages
|
|
130
|
+
? [
|
|
131
|
+
{
|
|
132
|
+
role: "user",
|
|
133
|
+
content: [
|
|
134
|
+
{
|
|
135
|
+
type: "text",
|
|
136
|
+
text: lastAgentSkillToInject.content,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
: []),
|
|
142
|
+
...historyMessages,
|
|
126
143
|
...currentMessages,
|
|
127
144
|
];
|
|
128
145
|
// Filter out thinking messages and truncate large messages
|
|
@@ -213,7 +230,7 @@ ${"```"}
|
|
|
213
230
|
if (this.compactionPromise)
|
|
214
231
|
await this.compactionPromise;
|
|
215
232
|
}
|
|
216
|
-
this.runtimeState.
|
|
233
|
+
this.runtimeState.currentEntryCompact = undefined;
|
|
217
234
|
this.runtimeState.currentEntry = { input, messages: [message] };
|
|
218
235
|
}
|
|
219
236
|
async endMessage(output, message, options) {
|
|
@@ -249,7 +266,7 @@ ${"```"}
|
|
|
249
266
|
}
|
|
250
267
|
this.runtimeState.historyEntries.push(newEntry);
|
|
251
268
|
this.runtimeState.currentEntry = null;
|
|
252
|
-
this.runtimeState.
|
|
269
|
+
this.runtimeState.currentEntryCompact = undefined;
|
|
253
270
|
// Only run compact and memory extraction if mode is not disabled
|
|
254
271
|
if (this.mode !== "disabled") {
|
|
255
272
|
await Promise.all([
|
|
@@ -333,7 +350,7 @@ ${"```"}
|
|
|
333
350
|
// Split into batches to avoid context overflow
|
|
334
351
|
const batches = this.splitIntoBatches(entriesToCompact, maxTokens);
|
|
335
352
|
// Process batches incrementally, each summary becomes input for the next
|
|
336
|
-
let currentSummary = this.runtimeState.
|
|
353
|
+
let currentSummary = this.runtimeState.historyCompact?.summary;
|
|
337
354
|
for (const batch of batches) {
|
|
338
355
|
const messages = batch
|
|
339
356
|
.flatMap((e) => e.content?.messages ?? [])
|
|
@@ -345,19 +362,30 @@ ${"```"}
|
|
|
345
362
|
});
|
|
346
363
|
currentSummary = result.summary;
|
|
347
364
|
}
|
|
365
|
+
// Extract last Agent Skill from entries to compact
|
|
366
|
+
let lastAgentSkill = this.findLastAgentSkill(entriesToCompact);
|
|
367
|
+
// If no skill found in entries to compact, inherit from previous compact
|
|
368
|
+
if (!lastAgentSkill && this.runtimeState.historyCompact?.lastAgentSkill) {
|
|
369
|
+
lastAgentSkill = this.runtimeState.historyCompact.lastAgentSkill;
|
|
370
|
+
}
|
|
371
|
+
// Create compact content
|
|
372
|
+
const historyCompact = {
|
|
373
|
+
summary: currentSummary ?? "",
|
|
374
|
+
lastAgentSkill,
|
|
375
|
+
};
|
|
348
376
|
// Write compact entry to AFS
|
|
349
377
|
if (this.afs && this.historyModulePath) {
|
|
350
378
|
await this.afs.write((0, ufo_1.joinURL)(this.historyModulePath, "by-session", this.sessionId, "@metadata/compact/new"), {
|
|
351
379
|
userId: this.userId,
|
|
352
380
|
agentId: this.agentId,
|
|
353
|
-
content:
|
|
381
|
+
content: historyCompact,
|
|
354
382
|
metadata: {
|
|
355
383
|
latestEntryId: latestCompactedEntry.id,
|
|
356
384
|
},
|
|
357
385
|
});
|
|
358
386
|
}
|
|
359
387
|
// Update runtime state: keep the summary and recent entries
|
|
360
|
-
this.runtimeState.
|
|
388
|
+
this.runtimeState.historyCompact = historyCompact;
|
|
361
389
|
this.runtimeState.historyEntries = entriesToKeep;
|
|
362
390
|
}
|
|
363
391
|
async compactCurrentEntry(options) {
|
|
@@ -367,7 +395,7 @@ ${"```"}
|
|
|
367
395
|
const currentEntry = this.runtimeState.currentEntry;
|
|
368
396
|
if (!currentEntry?.messages?.length)
|
|
369
397
|
return;
|
|
370
|
-
const alreadyCompressedCount = this.runtimeState.
|
|
398
|
+
const alreadyCompressedCount = this.runtimeState.currentEntryCompact?.compressedCount ?? 0;
|
|
371
399
|
const uncompressedMessages = currentEntry.messages.slice(alreadyCompressedCount);
|
|
372
400
|
if (uncompressedMessages.length === 0)
|
|
373
401
|
return;
|
|
@@ -415,13 +443,17 @@ ${"```"}
|
|
|
415
443
|
if (messagesToCompact.length === 0)
|
|
416
444
|
return;
|
|
417
445
|
const result = await options.context.invoke(compactor, {
|
|
418
|
-
previousSummary: this.runtimeState.
|
|
419
|
-
? [this.runtimeState.
|
|
446
|
+
previousSummary: this.runtimeState.currentEntryCompact?.summary
|
|
447
|
+
? [this.runtimeState.currentEntryCompact.summary]
|
|
420
448
|
: undefined,
|
|
421
449
|
messages: messagesToCompact,
|
|
422
450
|
});
|
|
423
|
-
|
|
451
|
+
// Find last Agent Skill from messages being compacted
|
|
452
|
+
const lastAgentSkill = this.findLastAgentSkillFromMessages(messagesToCompact) ??
|
|
453
|
+
this.runtimeState.currentEntryCompact?.lastAgentSkill;
|
|
454
|
+
this.runtimeState.currentEntryCompact = {
|
|
424
455
|
summary: result.summary,
|
|
456
|
+
lastAgentSkill,
|
|
425
457
|
compressedCount: alreadyCompressedCount + messagesToCompact.length,
|
|
426
458
|
};
|
|
427
459
|
}
|
|
@@ -429,7 +461,7 @@ ${"```"}
|
|
|
429
461
|
const currentEntry = this.runtimeState.currentEntry;
|
|
430
462
|
if (!currentEntry?.messages?.length)
|
|
431
463
|
return;
|
|
432
|
-
const compressedCount = this.runtimeState.
|
|
464
|
+
const compressedCount = this.runtimeState.currentEntryCompact?.compressedCount ?? 0;
|
|
433
465
|
const uncompressedMessages = currentEntry.messages.slice(compressedCount);
|
|
434
466
|
const threshold = this.keepTokenBudget;
|
|
435
467
|
const currentTokens = this.estimateMessagesTokens(uncompressedMessages, this.singleMessageLimit);
|
|
@@ -546,7 +578,7 @@ ${"```"}
|
|
|
546
578
|
// Update runtime state with loaded data
|
|
547
579
|
this.runtimeState.userMemory = userMemory;
|
|
548
580
|
this.runtimeState.sessionMemory = sessionMemory;
|
|
549
|
-
this.runtimeState.
|
|
581
|
+
this.runtimeState.historyCompact = sessionHistory.historyCompact;
|
|
550
582
|
this.runtimeState.historyEntries = sessionHistory.historyEntries;
|
|
551
583
|
}
|
|
552
584
|
}
|
|
@@ -599,8 +631,8 @@ ${"```"}
|
|
|
599
631
|
return facts;
|
|
600
632
|
}
|
|
601
633
|
/**
|
|
602
|
-
* Load session history including compact
|
|
603
|
-
* @returns Object containing compact
|
|
634
|
+
* Load session history including compact content and history entries
|
|
635
|
+
* @returns Object containing history compact and history entries
|
|
604
636
|
*/
|
|
605
637
|
async loadSessionHistory() {
|
|
606
638
|
if (!this.afs || !this.historyModulePath) {
|
|
@@ -614,7 +646,7 @@ ${"```"}
|
|
|
614
646
|
limit: 1,
|
|
615
647
|
});
|
|
616
648
|
const latestCompact = compactResult.data[0];
|
|
617
|
-
const
|
|
649
|
+
const historyCompact = latestCompact?.content;
|
|
618
650
|
// Load history entries (after compact point if exists)
|
|
619
651
|
const afsEntries = (await this.afs.list((0, ufo_1.joinURL)(this.historyModulePath, "by-session", this.sessionId), {
|
|
620
652
|
filter: {
|
|
@@ -630,7 +662,7 @@ ${"```"}
|
|
|
630
662
|
})).data;
|
|
631
663
|
const historyEntries = afsEntries.reverse().filter((entry) => (0, type_utils_js_1.isNonNullable)(entry.content));
|
|
632
664
|
return {
|
|
633
|
-
|
|
665
|
+
historyCompact,
|
|
634
666
|
historyEntries,
|
|
635
667
|
};
|
|
636
668
|
}
|
|
@@ -864,6 +896,50 @@ ${"```"}
|
|
|
864
896
|
}
|
|
865
897
|
}
|
|
866
898
|
}
|
|
899
|
+
/**
|
|
900
|
+
* Find Agent Skill content from a single message
|
|
901
|
+
* @param msg - Message to search in
|
|
902
|
+
* @returns The skill content text if found, undefined otherwise
|
|
903
|
+
*/
|
|
904
|
+
findSkillContentInMessage(msg) {
|
|
905
|
+
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
906
|
+
const skillBlock = msg.content.find((block) => block.type === "text" && block.isAgentSkill === true);
|
|
907
|
+
if (skillBlock && skillBlock.type === "text") {
|
|
908
|
+
return skillBlock.text;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return undefined;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Find the last Agent Skill from a list of messages
|
|
915
|
+
* @param messages - Messages to search through
|
|
916
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
917
|
+
*/
|
|
918
|
+
findLastAgentSkillFromMessages(messages) {
|
|
919
|
+
// Search backwards through messages to find the last Agent Skill
|
|
920
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
921
|
+
const msg = messages[i];
|
|
922
|
+
if (!msg)
|
|
923
|
+
continue;
|
|
924
|
+
const skillContent = this.findSkillContentInMessage(msg);
|
|
925
|
+
if (skillContent) {
|
|
926
|
+
return {
|
|
927
|
+
content: skillContent,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return undefined;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Find the last Agent Skill from a list of history entries
|
|
935
|
+
* @param entries - History entries to search through
|
|
936
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
937
|
+
*/
|
|
938
|
+
findLastAgentSkill(entries) {
|
|
939
|
+
// Flatten all messages from entries
|
|
940
|
+
const allMessages = entries.flatMap((entry) => entry.content?.messages ?? []);
|
|
941
|
+
return this.findLastAgentSkillFromMessages(allMessages);
|
|
942
|
+
}
|
|
867
943
|
async initializeDefaultCompactor() {
|
|
868
944
|
this.compactConfig.compactor ??= await Promise.resolve().then(() => __importStar(require("./compact/compactor.js"))).then((m) => new m.AISessionCompactor());
|
|
869
945
|
}
|
|
@@ -37,6 +37,13 @@ export interface EntryContent {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface CompactContent extends Message {
|
|
39
39
|
summary: string;
|
|
40
|
+
/**
|
|
41
|
+
* Last Agent Skill content in the session
|
|
42
|
+
* Preserved across compactions to maintain skill instructions
|
|
43
|
+
*/
|
|
44
|
+
lastAgentSkill?: {
|
|
45
|
+
content: string;
|
|
46
|
+
};
|
|
40
47
|
}
|
|
41
48
|
/**
|
|
42
49
|
* Input structure for the compactor agent
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Agent, type AgentOptions, type Message } from "../../../../agents/agent.js";
|
|
2
|
+
import type { PromiseOrValue } from "../../../../utils/type-utils.js";
|
|
2
3
|
import type { Skill } from "./skill-loader.js";
|
|
3
4
|
export interface SkillToolInput extends Message {
|
|
4
5
|
skill: string;
|
|
@@ -11,7 +12,7 @@ export interface SkillToolOptions extends AgentOptions<SkillToolInput, SkillTool
|
|
|
11
12
|
agentSkills: Skill[];
|
|
12
13
|
}
|
|
13
14
|
export declare class AgentSkill extends Agent<SkillToolInput, SkillToolOutput> {
|
|
14
|
-
|
|
15
|
+
formatOutput(output: SkillToolOutput | Message): PromiseOrValue<string>;
|
|
15
16
|
constructor(options: SkillToolOptions);
|
|
16
17
|
private agentSkills;
|
|
17
18
|
process(input: SkillToolInput): Promise<SkillToolOutput>;
|
|
@@ -8,11 +8,11 @@ const skillToolInputSchema = zod_1.z.object({
|
|
|
8
8
|
args: zod_1.z.string().optional().describe("The arguments to pass to the skill."),
|
|
9
9
|
});
|
|
10
10
|
class AgentSkill extends agent_js_1.Agent {
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
|
|
11
|
+
formatOutput(output) {
|
|
12
|
+
if ("result" in output && typeof output.result === "string") {
|
|
13
|
+
return output.result;
|
|
14
14
|
}
|
|
15
|
-
return output
|
|
15
|
+
return super.formatOutput(output);
|
|
16
16
|
}
|
|
17
17
|
constructor(options) {
|
|
18
18
|
super({
|
|
@@ -42,10 +42,12 @@ async function loadAgentSkillFromAFS({ afs, }) {
|
|
|
42
42
|
return;
|
|
43
43
|
const skills = [];
|
|
44
44
|
for (const module of filtered) {
|
|
45
|
-
const data = (await afs
|
|
45
|
+
const data = (await afs
|
|
46
|
+
.list(module.path, {
|
|
46
47
|
pattern: "**/SKILL.md",
|
|
47
48
|
maxDepth: 10,
|
|
48
|
-
})
|
|
49
|
+
})
|
|
50
|
+
.catch(() => ({ data: [] }))).data;
|
|
49
51
|
for (const entry of data) {
|
|
50
52
|
const { data: file } = await afs.read(entry.path);
|
|
51
53
|
if (typeof file?.content !== "string")
|
|
@@ -513,6 +513,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
513
513
|
*/
|
|
514
514
|
protected postprocess(input: I, output: O, options: AgentInvokeOptions): Promise<void>;
|
|
515
515
|
protected publishToTopics(output: Message, options: AgentInvokeOptions): Promise<void>;
|
|
516
|
+
formatOutput(output: O): PromiseOrValue<string>;
|
|
516
517
|
/**
|
|
517
518
|
* Core processing method of the agent, must be implemented in subclasses
|
|
518
519
|
*
|
|
@@ -103,8 +103,8 @@ export declare class AgentSession {
|
|
|
103
103
|
*/
|
|
104
104
|
private loadUserMemory;
|
|
105
105
|
/**
|
|
106
|
-
* Load session history including compact
|
|
107
|
-
* @returns Object containing compact
|
|
106
|
+
* Load session history including compact content and history entries
|
|
107
|
+
* @returns Object containing history compact and history entries
|
|
108
108
|
*/
|
|
109
109
|
private loadSessionHistory;
|
|
110
110
|
/**
|
|
@@ -125,6 +125,24 @@ export declare class AgentSession {
|
|
|
125
125
|
* Internal method that performs the actual user memory extraction
|
|
126
126
|
*/
|
|
127
127
|
private doUpdateUserMemory;
|
|
128
|
+
/**
|
|
129
|
+
* Find Agent Skill content from a single message
|
|
130
|
+
* @param msg - Message to search in
|
|
131
|
+
* @returns The skill content text if found, undefined otherwise
|
|
132
|
+
*/
|
|
133
|
+
private findSkillContentInMessage;
|
|
134
|
+
/**
|
|
135
|
+
* Find the last Agent Skill from a list of messages
|
|
136
|
+
* @param messages - Messages to search through
|
|
137
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
138
|
+
*/
|
|
139
|
+
private findLastAgentSkillFromMessages;
|
|
140
|
+
/**
|
|
141
|
+
* Find the last Agent Skill from a list of history entries
|
|
142
|
+
* @param entries - History entries to search through
|
|
143
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
144
|
+
*/
|
|
145
|
+
private findLastAgentSkill;
|
|
128
146
|
private initializeDefaultCompactor;
|
|
129
147
|
private initializeDefaultSessionMemoryExtractor;
|
|
130
148
|
private initializeDefaultUserMemoryExtractor;
|
|
@@ -37,6 +37,13 @@ export interface EntryContent {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface CompactContent extends Message {
|
|
39
39
|
summary: string;
|
|
40
|
+
/**
|
|
41
|
+
* Last Agent Skill content in the session
|
|
42
|
+
* Preserved across compactions to maintain skill instructions
|
|
43
|
+
*/
|
|
44
|
+
lastAgentSkill?: {
|
|
45
|
+
content: string;
|
|
46
|
+
};
|
|
40
47
|
}
|
|
41
48
|
/**
|
|
42
49
|
* Input structure for the compactor agent
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Agent, type AgentOptions, type Message } from "../../../../agents/agent.js";
|
|
2
|
+
import type { PromiseOrValue } from "../../../../utils/type-utils.js";
|
|
2
3
|
import type { Skill } from "./skill-loader.js";
|
|
3
4
|
export interface SkillToolInput extends Message {
|
|
4
5
|
skill: string;
|
|
@@ -11,7 +12,7 @@ export interface SkillToolOptions extends AgentOptions<SkillToolInput, SkillTool
|
|
|
11
12
|
agentSkills: Skill[];
|
|
12
13
|
}
|
|
13
14
|
export declare class AgentSkill extends Agent<SkillToolInput, SkillToolOutput> {
|
|
14
|
-
|
|
15
|
+
formatOutput(output: SkillToolOutput | Message): PromiseOrValue<string>;
|
|
15
16
|
constructor(options: SkillToolOptions);
|
|
16
17
|
private agentSkills;
|
|
17
18
|
process(input: SkillToolInput): Promise<SkillToolOutput>;
|
|
@@ -513,6 +513,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
513
513
|
*/
|
|
514
514
|
protected postprocess(input: I, output: O, options: AgentInvokeOptions): Promise<void>;
|
|
515
515
|
protected publishToTopics(output: Message, options: AgentInvokeOptions): Promise<void>;
|
|
516
|
+
formatOutput(output: O): PromiseOrValue<string>;
|
|
516
517
|
/**
|
|
517
518
|
* Core processing method of the agent, must be implemented in subclasses
|
|
518
519
|
*
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -418,21 +418,6 @@ export class AIAgent extends Agent {
|
|
|
418
418
|
}
|
|
419
419
|
const message = { role: "agent", toolCalls };
|
|
420
420
|
yield { progress: { event: "message", message } };
|
|
421
|
-
const skillToolUse = toolCallsWithTools.find((i) => i.tool instanceof AgentSkill);
|
|
422
|
-
if (skillToolUse) {
|
|
423
|
-
await session.endMessage(skillToolUse.function, {
|
|
424
|
-
role: "agent",
|
|
425
|
-
content: JSON.stringify({ ...skillToolUse.function }),
|
|
426
|
-
}, options);
|
|
427
|
-
const skillResult = await this.invokeSkill(skillToolUse.tool, { ...input, ...skillToolUse.function.arguments }, options);
|
|
428
|
-
await session.startMessage(skillToolUse.function.arguments, {
|
|
429
|
-
role: "user",
|
|
430
|
-
content: [
|
|
431
|
-
{ type: "text", text: AgentSkill.formatOutput(skillResult), isAgentSkill: true },
|
|
432
|
-
],
|
|
433
|
-
}, options);
|
|
434
|
-
continue;
|
|
435
|
-
}
|
|
436
421
|
await session.appendCurrentMessages(message, options);
|
|
437
422
|
const executedToolCalls = [];
|
|
438
423
|
let error;
|
|
@@ -466,11 +451,13 @@ export class AIAgent extends Agent {
|
|
|
466
451
|
throw error;
|
|
467
452
|
// Continue LLM function calling loop if any tools were executed
|
|
468
453
|
if (executedToolCalls.length) {
|
|
469
|
-
for (const { call, output } of executedToolCalls) {
|
|
454
|
+
for (const { call, tool, output } of executedToolCalls) {
|
|
455
|
+
const isAgentSkill = !output.isError && tool instanceof AgentSkill ? true : undefined;
|
|
456
|
+
const text = await tool.formatOutput(output);
|
|
470
457
|
const message = {
|
|
471
458
|
role: "tool",
|
|
472
459
|
toolCallId: call.id,
|
|
473
|
-
content:
|
|
460
|
+
content: [{ type: "text", text, isAgentSkill }],
|
|
474
461
|
};
|
|
475
462
|
yield { progress: { event: "message", message: message } };
|
|
476
463
|
await session.appendCurrentMessages(message, options);
|
|
@@ -103,8 +103,8 @@ export declare class AgentSession {
|
|
|
103
103
|
*/
|
|
104
104
|
private loadUserMemory;
|
|
105
105
|
/**
|
|
106
|
-
* Load session history including compact
|
|
107
|
-
* @returns Object containing compact
|
|
106
|
+
* Load session history including compact content and history entries
|
|
107
|
+
* @returns Object containing history compact and history entries
|
|
108
108
|
*/
|
|
109
109
|
private loadSessionHistory;
|
|
110
110
|
/**
|
|
@@ -125,6 +125,24 @@ export declare class AgentSession {
|
|
|
125
125
|
* Internal method that performs the actual user memory extraction
|
|
126
126
|
*/
|
|
127
127
|
private doUpdateUserMemory;
|
|
128
|
+
/**
|
|
129
|
+
* Find Agent Skill content from a single message
|
|
130
|
+
* @param msg - Message to search in
|
|
131
|
+
* @returns The skill content text if found, undefined otherwise
|
|
132
|
+
*/
|
|
133
|
+
private findSkillContentInMessage;
|
|
134
|
+
/**
|
|
135
|
+
* Find the last Agent Skill from a list of messages
|
|
136
|
+
* @param messages - Messages to search through
|
|
137
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
138
|
+
*/
|
|
139
|
+
private findLastAgentSkillFromMessages;
|
|
140
|
+
/**
|
|
141
|
+
* Find the last Agent Skill from a list of history entries
|
|
142
|
+
* @param entries - History entries to search through
|
|
143
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
144
|
+
*/
|
|
145
|
+
private findLastAgentSkill;
|
|
128
146
|
private initializeDefaultCompactor;
|
|
129
147
|
private initializeDefaultSessionMemoryExtractor;
|
|
130
148
|
private initializeDefaultUserMemoryExtractor;
|
|
@@ -48,42 +48,59 @@ export class AgentSession {
|
|
|
48
48
|
}
|
|
49
49
|
async getMessages() {
|
|
50
50
|
await this.ensureInitialized();
|
|
51
|
-
const { systemMessages, userMemory, sessionMemory,
|
|
51
|
+
const { systemMessages, userMemory, sessionMemory, historyCompact, historyEntries, currentEntry, currentEntryCompact, } = this.runtimeState;
|
|
52
52
|
let currentMessages = [];
|
|
53
53
|
if (currentEntry?.messages?.length) {
|
|
54
|
-
if (
|
|
55
|
-
const { compressedCount, summary } =
|
|
56
|
-
const firstMsg = currentEntry.messages[0];
|
|
57
|
-
const hasSkill = firstMsg?.role === "user" &&
|
|
58
|
-
Array.isArray(firstMsg.content) &&
|
|
59
|
-
firstMsg.content.some((block) => block.type === "text" && block.isAgentSkill === true);
|
|
60
|
-
const skillMessage = hasSkill ? [firstMsg] : [];
|
|
54
|
+
if (currentEntryCompact) {
|
|
55
|
+
const { compressedCount, summary } = currentEntryCompact;
|
|
61
56
|
const summaryMessage = {
|
|
62
57
|
role: "user",
|
|
63
58
|
content: `[Earlier messages in this conversation (${compressedCount} messages compressed)]\n${summary}`,
|
|
64
59
|
};
|
|
65
60
|
const remainingMessages = currentEntry.messages.slice(compressedCount);
|
|
66
|
-
currentMessages = [
|
|
61
|
+
currentMessages = [summaryMessage, ...remainingMessages];
|
|
67
62
|
}
|
|
68
63
|
else {
|
|
69
64
|
currentMessages = currentEntry.messages;
|
|
70
65
|
}
|
|
71
66
|
}
|
|
67
|
+
// Flatten history entries messages once
|
|
68
|
+
const historyMessages = historyEntries.flatMap((entry) => entry.content?.messages ?? []);
|
|
69
|
+
// Check if there's an Agent Skill in current uncompressed messages
|
|
70
|
+
const hasSkillInCurrentMessages = [...historyMessages, ...currentMessages].some((msg) => msg.role === "user" &&
|
|
71
|
+
Array.isArray(msg.content) &&
|
|
72
|
+
msg.content.some((block) => block.type === "text" && block.isAgentSkill === true));
|
|
73
|
+
// Prefer currentEntryCompact's lastAgentSkill over historyCompact's (newer takes priority)
|
|
74
|
+
const lastAgentSkillToInject = currentEntryCompact?.lastAgentSkill ?? historyCompact?.lastAgentSkill;
|
|
72
75
|
const messages = [
|
|
73
76
|
...(systemMessages ?? []),
|
|
74
77
|
...(userMemory && userMemory.length > 0 ? [this.formatUserMemory(userMemory)] : []),
|
|
75
78
|
...(sessionMemory && sessionMemory.length > 0
|
|
76
79
|
? [this.formatSessionMemory(sessionMemory)]
|
|
77
80
|
: []),
|
|
78
|
-
...(
|
|
81
|
+
...(historyCompact?.summary
|
|
79
82
|
? [
|
|
80
83
|
{
|
|
81
84
|
role: "system",
|
|
82
|
-
content: `Previous conversation summary:\n${
|
|
85
|
+
content: `Previous conversation summary:\n${historyCompact.summary}`,
|
|
83
86
|
},
|
|
84
87
|
]
|
|
85
88
|
: []),
|
|
86
|
-
|
|
89
|
+
// Only inject lastAgentSkill if there's no skill in current messages
|
|
90
|
+
...(lastAgentSkillToInject && !hasSkillInCurrentMessages
|
|
91
|
+
? [
|
|
92
|
+
{
|
|
93
|
+
role: "user",
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: lastAgentSkillToInject.content,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
: []),
|
|
103
|
+
...historyMessages,
|
|
87
104
|
...currentMessages,
|
|
88
105
|
];
|
|
89
106
|
// Filter out thinking messages and truncate large messages
|
|
@@ -174,7 +191,7 @@ ${"```"}
|
|
|
174
191
|
if (this.compactionPromise)
|
|
175
192
|
await this.compactionPromise;
|
|
176
193
|
}
|
|
177
|
-
this.runtimeState.
|
|
194
|
+
this.runtimeState.currentEntryCompact = undefined;
|
|
178
195
|
this.runtimeState.currentEntry = { input, messages: [message] };
|
|
179
196
|
}
|
|
180
197
|
async endMessage(output, message, options) {
|
|
@@ -210,7 +227,7 @@ ${"```"}
|
|
|
210
227
|
}
|
|
211
228
|
this.runtimeState.historyEntries.push(newEntry);
|
|
212
229
|
this.runtimeState.currentEntry = null;
|
|
213
|
-
this.runtimeState.
|
|
230
|
+
this.runtimeState.currentEntryCompact = undefined;
|
|
214
231
|
// Only run compact and memory extraction if mode is not disabled
|
|
215
232
|
if (this.mode !== "disabled") {
|
|
216
233
|
await Promise.all([
|
|
@@ -294,7 +311,7 @@ ${"```"}
|
|
|
294
311
|
// Split into batches to avoid context overflow
|
|
295
312
|
const batches = this.splitIntoBatches(entriesToCompact, maxTokens);
|
|
296
313
|
// Process batches incrementally, each summary becomes input for the next
|
|
297
|
-
let currentSummary = this.runtimeState.
|
|
314
|
+
let currentSummary = this.runtimeState.historyCompact?.summary;
|
|
298
315
|
for (const batch of batches) {
|
|
299
316
|
const messages = batch
|
|
300
317
|
.flatMap((e) => e.content?.messages ?? [])
|
|
@@ -306,19 +323,30 @@ ${"```"}
|
|
|
306
323
|
});
|
|
307
324
|
currentSummary = result.summary;
|
|
308
325
|
}
|
|
326
|
+
// Extract last Agent Skill from entries to compact
|
|
327
|
+
let lastAgentSkill = this.findLastAgentSkill(entriesToCompact);
|
|
328
|
+
// If no skill found in entries to compact, inherit from previous compact
|
|
329
|
+
if (!lastAgentSkill && this.runtimeState.historyCompact?.lastAgentSkill) {
|
|
330
|
+
lastAgentSkill = this.runtimeState.historyCompact.lastAgentSkill;
|
|
331
|
+
}
|
|
332
|
+
// Create compact content
|
|
333
|
+
const historyCompact = {
|
|
334
|
+
summary: currentSummary ?? "",
|
|
335
|
+
lastAgentSkill,
|
|
336
|
+
};
|
|
309
337
|
// Write compact entry to AFS
|
|
310
338
|
if (this.afs && this.historyModulePath) {
|
|
311
339
|
await this.afs.write(joinURL(this.historyModulePath, "by-session", this.sessionId, "@metadata/compact/new"), {
|
|
312
340
|
userId: this.userId,
|
|
313
341
|
agentId: this.agentId,
|
|
314
|
-
content:
|
|
342
|
+
content: historyCompact,
|
|
315
343
|
metadata: {
|
|
316
344
|
latestEntryId: latestCompactedEntry.id,
|
|
317
345
|
},
|
|
318
346
|
});
|
|
319
347
|
}
|
|
320
348
|
// Update runtime state: keep the summary and recent entries
|
|
321
|
-
this.runtimeState.
|
|
349
|
+
this.runtimeState.historyCompact = historyCompact;
|
|
322
350
|
this.runtimeState.historyEntries = entriesToKeep;
|
|
323
351
|
}
|
|
324
352
|
async compactCurrentEntry(options) {
|
|
@@ -328,7 +356,7 @@ ${"```"}
|
|
|
328
356
|
const currentEntry = this.runtimeState.currentEntry;
|
|
329
357
|
if (!currentEntry?.messages?.length)
|
|
330
358
|
return;
|
|
331
|
-
const alreadyCompressedCount = this.runtimeState.
|
|
359
|
+
const alreadyCompressedCount = this.runtimeState.currentEntryCompact?.compressedCount ?? 0;
|
|
332
360
|
const uncompressedMessages = currentEntry.messages.slice(alreadyCompressedCount);
|
|
333
361
|
if (uncompressedMessages.length === 0)
|
|
334
362
|
return;
|
|
@@ -376,13 +404,17 @@ ${"```"}
|
|
|
376
404
|
if (messagesToCompact.length === 0)
|
|
377
405
|
return;
|
|
378
406
|
const result = await options.context.invoke(compactor, {
|
|
379
|
-
previousSummary: this.runtimeState.
|
|
380
|
-
? [this.runtimeState.
|
|
407
|
+
previousSummary: this.runtimeState.currentEntryCompact?.summary
|
|
408
|
+
? [this.runtimeState.currentEntryCompact.summary]
|
|
381
409
|
: undefined,
|
|
382
410
|
messages: messagesToCompact,
|
|
383
411
|
});
|
|
384
|
-
|
|
412
|
+
// Find last Agent Skill from messages being compacted
|
|
413
|
+
const lastAgentSkill = this.findLastAgentSkillFromMessages(messagesToCompact) ??
|
|
414
|
+
this.runtimeState.currentEntryCompact?.lastAgentSkill;
|
|
415
|
+
this.runtimeState.currentEntryCompact = {
|
|
385
416
|
summary: result.summary,
|
|
417
|
+
lastAgentSkill,
|
|
386
418
|
compressedCount: alreadyCompressedCount + messagesToCompact.length,
|
|
387
419
|
};
|
|
388
420
|
}
|
|
@@ -390,7 +422,7 @@ ${"```"}
|
|
|
390
422
|
const currentEntry = this.runtimeState.currentEntry;
|
|
391
423
|
if (!currentEntry?.messages?.length)
|
|
392
424
|
return;
|
|
393
|
-
const compressedCount = this.runtimeState.
|
|
425
|
+
const compressedCount = this.runtimeState.currentEntryCompact?.compressedCount ?? 0;
|
|
394
426
|
const uncompressedMessages = currentEntry.messages.slice(compressedCount);
|
|
395
427
|
const threshold = this.keepTokenBudget;
|
|
396
428
|
const currentTokens = this.estimateMessagesTokens(uncompressedMessages, this.singleMessageLimit);
|
|
@@ -507,7 +539,7 @@ ${"```"}
|
|
|
507
539
|
// Update runtime state with loaded data
|
|
508
540
|
this.runtimeState.userMemory = userMemory;
|
|
509
541
|
this.runtimeState.sessionMemory = sessionMemory;
|
|
510
|
-
this.runtimeState.
|
|
542
|
+
this.runtimeState.historyCompact = sessionHistory.historyCompact;
|
|
511
543
|
this.runtimeState.historyEntries = sessionHistory.historyEntries;
|
|
512
544
|
}
|
|
513
545
|
}
|
|
@@ -560,8 +592,8 @@ ${"```"}
|
|
|
560
592
|
return facts;
|
|
561
593
|
}
|
|
562
594
|
/**
|
|
563
|
-
* Load session history including compact
|
|
564
|
-
* @returns Object containing compact
|
|
595
|
+
* Load session history including compact content and history entries
|
|
596
|
+
* @returns Object containing history compact and history entries
|
|
565
597
|
*/
|
|
566
598
|
async loadSessionHistory() {
|
|
567
599
|
if (!this.afs || !this.historyModulePath) {
|
|
@@ -575,7 +607,7 @@ ${"```"}
|
|
|
575
607
|
limit: 1,
|
|
576
608
|
});
|
|
577
609
|
const latestCompact = compactResult.data[0];
|
|
578
|
-
const
|
|
610
|
+
const historyCompact = latestCompact?.content;
|
|
579
611
|
// Load history entries (after compact point if exists)
|
|
580
612
|
const afsEntries = (await this.afs.list(joinURL(this.historyModulePath, "by-session", this.sessionId), {
|
|
581
613
|
filter: {
|
|
@@ -591,7 +623,7 @@ ${"```"}
|
|
|
591
623
|
})).data;
|
|
592
624
|
const historyEntries = afsEntries.reverse().filter((entry) => isNonNullable(entry.content));
|
|
593
625
|
return {
|
|
594
|
-
|
|
626
|
+
historyCompact,
|
|
595
627
|
historyEntries,
|
|
596
628
|
};
|
|
597
629
|
}
|
|
@@ -825,6 +857,50 @@ ${"```"}
|
|
|
825
857
|
}
|
|
826
858
|
}
|
|
827
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* Find Agent Skill content from a single message
|
|
862
|
+
* @param msg - Message to search in
|
|
863
|
+
* @returns The skill content text if found, undefined otherwise
|
|
864
|
+
*/
|
|
865
|
+
findSkillContentInMessage(msg) {
|
|
866
|
+
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
867
|
+
const skillBlock = msg.content.find((block) => block.type === "text" && block.isAgentSkill === true);
|
|
868
|
+
if (skillBlock && skillBlock.type === "text") {
|
|
869
|
+
return skillBlock.text;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return undefined;
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Find the last Agent Skill from a list of messages
|
|
876
|
+
* @param messages - Messages to search through
|
|
877
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
878
|
+
*/
|
|
879
|
+
findLastAgentSkillFromMessages(messages) {
|
|
880
|
+
// Search backwards through messages to find the last Agent Skill
|
|
881
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
882
|
+
const msg = messages[i];
|
|
883
|
+
if (!msg)
|
|
884
|
+
continue;
|
|
885
|
+
const skillContent = this.findSkillContentInMessage(msg);
|
|
886
|
+
if (skillContent) {
|
|
887
|
+
return {
|
|
888
|
+
content: skillContent,
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return undefined;
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Find the last Agent Skill from a list of history entries
|
|
896
|
+
* @param entries - History entries to search through
|
|
897
|
+
* @returns The last Agent Skill found, or undefined if none found
|
|
898
|
+
*/
|
|
899
|
+
findLastAgentSkill(entries) {
|
|
900
|
+
// Flatten all messages from entries
|
|
901
|
+
const allMessages = entries.flatMap((entry) => entry.content?.messages ?? []);
|
|
902
|
+
return this.findLastAgentSkillFromMessages(allMessages);
|
|
903
|
+
}
|
|
828
904
|
async initializeDefaultCompactor() {
|
|
829
905
|
this.compactConfig.compactor ??= await import("./compact/compactor.js").then((m) => new m.AISessionCompactor());
|
|
830
906
|
}
|
|
@@ -37,6 +37,13 @@ export interface EntryContent {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface CompactContent extends Message {
|
|
39
39
|
summary: string;
|
|
40
|
+
/**
|
|
41
|
+
* Last Agent Skill content in the session
|
|
42
|
+
* Preserved across compactions to maintain skill instructions
|
|
43
|
+
*/
|
|
44
|
+
lastAgentSkill?: {
|
|
45
|
+
content: string;
|
|
46
|
+
};
|
|
40
47
|
}
|
|
41
48
|
/**
|
|
42
49
|
* Input structure for the compactor agent
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Agent, type AgentOptions, type Message } from "../../../../agents/agent.js";
|
|
2
|
+
import type { PromiseOrValue } from "../../../../utils/type-utils.js";
|
|
2
3
|
import type { Skill } from "./skill-loader.js";
|
|
3
4
|
export interface SkillToolInput extends Message {
|
|
4
5
|
skill: string;
|
|
@@ -11,7 +12,7 @@ export interface SkillToolOptions extends AgentOptions<SkillToolInput, SkillTool
|
|
|
11
12
|
agentSkills: Skill[];
|
|
12
13
|
}
|
|
13
14
|
export declare class AgentSkill extends Agent<SkillToolInput, SkillToolOutput> {
|
|
14
|
-
|
|
15
|
+
formatOutput(output: SkillToolOutput | Message): PromiseOrValue<string>;
|
|
15
16
|
constructor(options: SkillToolOptions);
|
|
16
17
|
private agentSkills;
|
|
17
18
|
process(input: SkillToolInput): Promise<SkillToolOutput>;
|
|
@@ -5,11 +5,11 @@ const skillToolInputSchema = z.object({
|
|
|
5
5
|
args: z.string().optional().describe("The arguments to pass to the skill."),
|
|
6
6
|
});
|
|
7
7
|
export class AgentSkill extends Agent {
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
|
|
8
|
+
formatOutput(output) {
|
|
9
|
+
if ("result" in output && typeof output.result === "string") {
|
|
10
|
+
return output.result;
|
|
11
11
|
}
|
|
12
|
-
return output
|
|
12
|
+
return super.formatOutput(output);
|
|
13
13
|
}
|
|
14
14
|
constructor(options) {
|
|
15
15
|
super({
|
|
@@ -34,10 +34,12 @@ export async function loadAgentSkillFromAFS({ afs, }) {
|
|
|
34
34
|
return;
|
|
35
35
|
const skills = [];
|
|
36
36
|
for (const module of filtered) {
|
|
37
|
-
const data = (await afs
|
|
37
|
+
const data = (await afs
|
|
38
|
+
.list(module.path, {
|
|
38
39
|
pattern: "**/SKILL.md",
|
|
39
40
|
maxDepth: 10,
|
|
40
|
-
})
|
|
41
|
+
})
|
|
42
|
+
.catch(() => ({ data: [] }))).data;
|
|
41
43
|
for (const entry of data) {
|
|
42
44
|
const { data: file } = await afs.read(entry.path);
|
|
43
45
|
if (typeof file?.content !== "string")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/core",
|
|
3
|
-
"version": "1.72.0-beta.
|
|
3
|
+
"version": "1.72.0-beta.12",
|
|
4
4
|
"description": "The functional core of agentic AI",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -93,10 +93,10 @@
|
|
|
93
93
|
"zod": "^3.25.67",
|
|
94
94
|
"zod-from-json-schema": "^0.0.5",
|
|
95
95
|
"zod-to-json-schema": "^3.24.6",
|
|
96
|
-
"@aigne/afs": "^1.4.0-beta.5",
|
|
97
96
|
"@aigne/observability-api": "^0.11.14-beta.1",
|
|
98
|
-
"@aigne/afs-history": "^1.2.0-beta.
|
|
99
|
-
"@aigne/platform-helpers": "^0.6.7-beta"
|
|
97
|
+
"@aigne/afs-history": "^1.2.0-beta.7",
|
|
98
|
+
"@aigne/platform-helpers": "^0.6.7-beta",
|
|
99
|
+
"@aigne/afs": "^1.4.0-beta.6"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
|
102
102
|
"@types/bun": "^1.2.22",
|