@xandout/libra-harness 0.1.8
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/LICENSE +21 -0
- package/README.md +486 -0
- package/dist/agent.d.ts +174 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +575 -0
- package/dist/agent.js.map +1 -0
- package/dist/ai-sdk-model.d.ts +26 -0
- package/dist/ai-sdk-model.d.ts.map +1 -0
- package/dist/ai-sdk-model.js +260 -0
- package/dist/ai-sdk-model.js.map +1 -0
- package/dist/context.d.ts +75 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/extension.d.ts +63 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +2 -0
- package/dist/extension.js.map +1 -0
- package/dist/extras/extension-loader.d.ts +205 -0
- package/dist/extras/extension-loader.d.ts.map +1 -0
- package/dist/extras/extension-loader.js +315 -0
- package/dist/extras/extension-loader.js.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.d.ts +46 -0
- package/dist/extras/extensions/auto-steer/extension.d.ts.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.js +52 -0
- package/dist/extras/extensions/auto-steer/extension.js.map +1 -0
- package/dist/extras/extensions/auto-steer/extension.json +7 -0
- package/dist/extras/extensions/auto-steer/index.d.ts +3 -0
- package/dist/extras/extensions/auto-steer/index.d.ts.map +1 -0
- package/dist/extras/extensions/auto-steer/index.js +2 -0
- package/dist/extras/extensions/auto-steer/index.js.map +1 -0
- package/dist/extras/extensions/disk-session/extension.d.ts +167 -0
- package/dist/extras/extensions/disk-session/extension.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/extension.js +492 -0
- package/dist/extras/extensions/disk-session/extension.js.map +1 -0
- package/dist/extras/extensions/disk-session/extension.json +6 -0
- package/dist/extras/extensions/disk-session/extension.test.d.ts +2 -0
- package/dist/extras/extensions/disk-session/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/extension.test.js +672 -0
- package/dist/extras/extensions/disk-session/extension.test.js.map +1 -0
- package/dist/extras/extensions/disk-session/index.d.ts +3 -0
- package/dist/extras/extensions/disk-session/index.d.ts.map +1 -0
- package/dist/extras/extensions/disk-session/index.js +2 -0
- package/dist/extras/extensions/disk-session/index.js.map +1 -0
- package/dist/extras/extensions/emoji/extension.d.ts +20 -0
- package/dist/extras/extensions/emoji/extension.d.ts.map +1 -0
- package/dist/extras/extensions/emoji/extension.js +22 -0
- package/dist/extras/extensions/emoji/extension.js.map +1 -0
- package/dist/extras/extensions/emoji/extension.json +7 -0
- package/dist/extras/extensions/emoji/index.d.ts +3 -0
- package/dist/extras/extensions/emoji/index.d.ts.map +1 -0
- package/dist/extras/extensions/emoji/index.js +2 -0
- package/dist/extras/extensions/emoji/index.js.map +1 -0
- package/dist/extras/extensions/filesystem/extension.d.ts +53 -0
- package/dist/extras/extensions/filesystem/extension.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/extension.js +350 -0
- package/dist/extras/extensions/filesystem/extension.js.map +1 -0
- package/dist/extras/extensions/filesystem/extension.json +6 -0
- package/dist/extras/extensions/filesystem/extension.test.d.ts +2 -0
- package/dist/extras/extensions/filesystem/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/extension.test.js +387 -0
- package/dist/extras/extensions/filesystem/extension.test.js.map +1 -0
- package/dist/extras/extensions/filesystem/index.d.ts +2 -0
- package/dist/extras/extensions/filesystem/index.d.ts.map +1 -0
- package/dist/extras/extensions/filesystem/index.js +2 -0
- package/dist/extras/extensions/filesystem/index.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.d.ts +53 -0
- package/dist/extras/extensions/keyword-extractor/extension.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.js +61 -0
- package/dist/extras/extensions/keyword-extractor/extension.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.json +6 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.d.ts +2 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.js +105 -0
- package/dist/extras/extensions/keyword-extractor/extension.test.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/index.d.ts +5 -0
- package/dist/extras/extensions/keyword-extractor/index.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/index.js +3 -0
- package/dist/extras/extensions/keyword-extractor/index.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.d.ts +68 -0
- package/dist/extras/extensions/keyword-extractor/nlp.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.js +156 -0
- package/dist/extras/extensions/keyword-extractor/nlp.js.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts +2 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts.map +1 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.js +176 -0
- package/dist/extras/extensions/keyword-extractor/nlp.test.js.map +1 -0
- package/dist/extras/extensions/logger/extension.d.ts +52 -0
- package/dist/extras/extensions/logger/extension.d.ts.map +1 -0
- package/dist/extras/extensions/logger/extension.js +68 -0
- package/dist/extras/extensions/logger/extension.js.map +1 -0
- package/dist/extras/extensions/logger/extension.json +7 -0
- package/dist/extras/extensions/logger/index.d.ts +3 -0
- package/dist/extras/extensions/logger/index.d.ts.map +1 -0
- package/dist/extras/extensions/logger/index.js +2 -0
- package/dist/extras/extensions/logger/index.js.map +1 -0
- package/dist/extras/extensions/mcp/extension.d.ts +63 -0
- package/dist/extras/extensions/mcp/extension.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/extension.js +437 -0
- package/dist/extras/extensions/mcp/extension.js.map +1 -0
- package/dist/extras/extensions/mcp/extension.json +7 -0
- package/dist/extras/extensions/mcp/extension.test.d.ts +2 -0
- package/dist/extras/extensions/mcp/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/extension.test.js +286 -0
- package/dist/extras/extensions/mcp/extension.test.js.map +1 -0
- package/dist/extras/extensions/mcp/index.d.ts +3 -0
- package/dist/extras/extensions/mcp/index.d.ts.map +1 -0
- package/dist/extras/extensions/mcp/index.js +2 -0
- package/dist/extras/extensions/mcp/index.js.map +1 -0
- package/dist/extras/extensions/mem-session/extension.d.ts +24 -0
- package/dist/extras/extensions/mem-session/extension.d.ts.map +1 -0
- package/dist/extras/extensions/mem-session/extension.js +49 -0
- package/dist/extras/extensions/mem-session/extension.js.map +1 -0
- package/dist/extras/extensions/mem-session/extension.json +6 -0
- package/dist/extras/extensions/mem-session/index.d.ts +2 -0
- package/dist/extras/extensions/mem-session/index.d.ts.map +1 -0
- package/dist/extras/extensions/mem-session/index.js +2 -0
- package/dist/extras/extensions/mem-session/index.js.map +1 -0
- package/dist/extras/extensions/memory/extension.d.ts +54 -0
- package/dist/extras/extensions/memory/extension.d.ts.map +1 -0
- package/dist/extras/extensions/memory/extension.js +143 -0
- package/dist/extras/extensions/memory/extension.js.map +1 -0
- package/dist/extras/extensions/memory/extension.json +7 -0
- package/dist/extras/extensions/memory/index.d.ts +5 -0
- package/dist/extras/extensions/memory/index.d.ts.map +1 -0
- package/dist/extras/extensions/memory/index.js +3 -0
- package/dist/extras/extensions/memory/index.js.map +1 -0
- package/dist/extras/extensions/memory/llm-extractor.d.ts +42 -0
- package/dist/extras/extensions/memory/llm-extractor.d.ts.map +1 -0
- package/dist/extras/extensions/memory/llm-extractor.js +89 -0
- package/dist/extras/extensions/memory/llm-extractor.js.map +1 -0
- package/dist/extras/extensions/memory/types.d.ts +142 -0
- package/dist/extras/extensions/memory/types.d.ts.map +1 -0
- package/dist/extras/extensions/memory/types.js +2 -0
- package/dist/extras/extensions/memory/types.js.map +1 -0
- package/dist/extras/extensions/otel/extension.d.ts +57 -0
- package/dist/extras/extensions/otel/extension.d.ts.map +1 -0
- package/dist/extras/extensions/otel/extension.js +253 -0
- package/dist/extras/extensions/otel/extension.js.map +1 -0
- package/dist/extras/extensions/otel/extension.json +7 -0
- package/dist/extras/extensions/otel/extension.test.d.ts +2 -0
- package/dist/extras/extensions/otel/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/otel/extension.test.js +399 -0
- package/dist/extras/extensions/otel/extension.test.js.map +1 -0
- package/dist/extras/extensions/otel/index.d.ts +4 -0
- package/dist/extras/extensions/otel/index.d.ts.map +1 -0
- package/dist/extras/extensions/otel/index.js +3 -0
- package/dist/extras/extensions/otel/index.js.map +1 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts +60 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts.map +1 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.js +134 -0
- package/dist/extras/extensions/otel/jsonl-span-exporter.js.map +1 -0
- package/dist/extras/extensions/scripts/extension.d.ts +180 -0
- package/dist/extras/extensions/scripts/extension.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/extension.js +618 -0
- package/dist/extras/extensions/scripts/extension.js.map +1 -0
- package/dist/extras/extensions/scripts/extension.json +7 -0
- package/dist/extras/extensions/scripts/extension.test.d.ts +2 -0
- package/dist/extras/extensions/scripts/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/extension.test.js +552 -0
- package/dist/extras/extensions/scripts/extension.test.js.map +1 -0
- package/dist/extras/extensions/scripts/index.d.ts +3 -0
- package/dist/extras/extensions/scripts/index.d.ts.map +1 -0
- package/dist/extras/extensions/scripts/index.js +2 -0
- package/dist/extras/extensions/scripts/index.js.map +1 -0
- package/dist/extras/extensions/skills/extension.d.ts +105 -0
- package/dist/extras/extensions/skills/extension.d.ts.map +1 -0
- package/dist/extras/extensions/skills/extension.js +419 -0
- package/dist/extras/extensions/skills/extension.js.map +1 -0
- package/dist/extras/extensions/skills/extension.json +7 -0
- package/dist/extras/extensions/skills/extension.test.d.ts +2 -0
- package/dist/extras/extensions/skills/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/skills/extension.test.js +184 -0
- package/dist/extras/extensions/skills/extension.test.js.map +1 -0
- package/dist/extras/extensions/skills/index.d.ts +4 -0
- package/dist/extras/extensions/skills/index.d.ts.map +1 -0
- package/dist/extras/extensions/skills/index.js +3 -0
- package/dist/extras/extensions/skills/index.js.map +1 -0
- package/dist/extras/extensions/streaming/extension.d.ts +15 -0
- package/dist/extras/extensions/streaming/extension.d.ts.map +1 -0
- package/dist/extras/extensions/streaming/extension.js +41 -0
- package/dist/extras/extensions/streaming/extension.js.map +1 -0
- package/dist/extras/extensions/streaming/extension.json +6 -0
- package/dist/extras/extensions/streaming/index.d.ts +2 -0
- package/dist/extras/extensions/streaming/index.d.ts.map +1 -0
- package/dist/extras/extensions/streaming/index.js +2 -0
- package/dist/extras/extensions/streaming/index.js.map +1 -0
- package/dist/extras/extensions/structured-output/extension.d.ts +11 -0
- package/dist/extras/extensions/structured-output/extension.d.ts.map +1 -0
- package/dist/extras/extensions/structured-output/extension.js +102 -0
- package/dist/extras/extensions/structured-output/extension.js.map +1 -0
- package/dist/extras/extensions/structured-output/extension.json +7 -0
- package/dist/extras/extensions/structured-output/index.d.ts +3 -0
- package/dist/extras/extensions/structured-output/index.d.ts.map +1 -0
- package/dist/extras/extensions/structured-output/index.js +2 -0
- package/dist/extras/extensions/structured-output/index.js.map +1 -0
- package/dist/extras/extensions/timestamp/extension.d.ts +11 -0
- package/dist/extras/extensions/timestamp/extension.d.ts.map +1 -0
- package/dist/extras/extensions/timestamp/extension.js +21 -0
- package/dist/extras/extensions/timestamp/extension.js.map +1 -0
- package/dist/extras/extensions/timestamp/extension.json +6 -0
- package/dist/extras/extensions/timestamp/index.d.ts +2 -0
- package/dist/extras/extensions/timestamp/index.d.ts.map +1 -0
- package/dist/extras/extensions/timestamp/index.js +2 -0
- package/dist/extras/extensions/timestamp/index.js.map +1 -0
- package/dist/extras/extensions/token-stats/extension.d.ts +50 -0
- package/dist/extras/extensions/token-stats/extension.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/extension.js +99 -0
- package/dist/extras/extensions/token-stats/extension.js.map +1 -0
- package/dist/extras/extensions/token-stats/extension.json +7 -0
- package/dist/extras/extensions/token-stats/extension.test.d.ts +2 -0
- package/dist/extras/extensions/token-stats/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/extension.test.js +197 -0
- package/dist/extras/extensions/token-stats/extension.test.js.map +1 -0
- package/dist/extras/extensions/token-stats/index.d.ts +3 -0
- package/dist/extras/extensions/token-stats/index.d.ts.map +1 -0
- package/dist/extras/extensions/token-stats/index.js +2 -0
- package/dist/extras/extensions/token-stats/index.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.d.ts +89 -0
- package/dist/extras/extensions/tool-buffer/extension.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.js +182 -0
- package/dist/extras/extensions/tool-buffer/extension.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.json +7 -0
- package/dist/extras/extensions/tool-buffer/extension.test.d.ts +2 -0
- package/dist/extras/extensions/tool-buffer/extension.test.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/extension.test.js +549 -0
- package/dist/extras/extensions/tool-buffer/extension.test.js.map +1 -0
- package/dist/extras/extensions/tool-buffer/index.d.ts +3 -0
- package/dist/extras/extensions/tool-buffer/index.d.ts.map +1 -0
- package/dist/extras/extensions/tool-buffer/index.js +2 -0
- package/dist/extras/extensions/tool-buffer/index.js.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.d.ts +22 -0
- package/dist/extras/extensions/weather-tool/extension.d.ts.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.js +33 -0
- package/dist/extras/extensions/weather-tool/extension.js.map +1 -0
- package/dist/extras/extensions/weather-tool/extension.json +7 -0
- package/dist/extras/extensions/weather-tool/index.d.ts +3 -0
- package/dist/extras/extensions/weather-tool/index.d.ts.map +1 -0
- package/dist/extras/extensions/weather-tool/index.js +2 -0
- package/dist/extras/extensions/weather-tool/index.js.map +1 -0
- package/dist/extras/models/ai-sdk-resolver.d.ts +15 -0
- package/dist/extras/models/ai-sdk-resolver.d.ts.map +1 -0
- package/dist/extras/models/ai-sdk-resolver.js +57 -0
- package/dist/extras/models/ai-sdk-resolver.js.map +1 -0
- package/dist/extras/models/index.d.ts +5 -0
- package/dist/extras/models/index.d.ts.map +1 -0
- package/dist/extras/models/index.js +3 -0
- package/dist/extras/models/index.js.map +1 -0
- package/dist/extras/models/routing-model.d.ts +18 -0
- package/dist/extras/models/routing-model.d.ts.map +1 -0
- package/dist/extras/models/routing-model.js +24 -0
- package/dist/extras/models/routing-model.js.map +1 -0
- package/dist/extras/openai-provider/index.d.ts +3 -0
- package/dist/extras/openai-provider/index.d.ts.map +1 -0
- package/dist/extras/openai-provider/index.js +2 -0
- package/dist/extras/openai-provider/index.js.map +1 -0
- package/dist/extras/openai-provider/server.d.ts +34 -0
- package/dist/extras/openai-provider/server.d.ts.map +1 -0
- package/dist/extras/openai-provider/server.js +335 -0
- package/dist/extras/openai-provider/server.js.map +1 -0
- package/dist/handle.d.ts +56 -0
- package/dist/handle.d.ts.map +1 -0
- package/dist/handle.js +2 -0
- package/dist/handle.js.map +1 -0
- package/dist/hooks.d.ts +98 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +53 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +75 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/tool.d.ts +78 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +78 -0
- package/dist/tool.js.map +1 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +178 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { Agent } from '../../../agent.js';
|
|
6
|
+
import { createSkillExtension } from './index.js';
|
|
7
|
+
// โโ Mock model โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
8
|
+
// Returns a fixed assistant message.
|
|
9
|
+
function mockModel() {
|
|
10
|
+
return {
|
|
11
|
+
async generate() {
|
|
12
|
+
return {
|
|
13
|
+
message: { role: 'assistant', content: 'ok' },
|
|
14
|
+
finishReason: 'stop',
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
20
|
+
function makeSkill(dir, name, frontmatter = {}, body = 'Skill body') {
|
|
21
|
+
const skillDir = join(dir, name);
|
|
22
|
+
mkdirSync(skillDir, { recursive: true });
|
|
23
|
+
const fmLines = Object.entries(frontmatter).map(([k, v]) => `${k}: ${v}`);
|
|
24
|
+
const content = `---\nname: ${name}\n${fmLines.join('\n')}\n---\n${body}`;
|
|
25
|
+
writeFileSync(join(skillDir, 'SKILL.md'), content);
|
|
26
|
+
return skillDir;
|
|
27
|
+
}
|
|
28
|
+
// โโ Test setup โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
29
|
+
let tmpDir;
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'skills-test-'));
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
// โโ Tests โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
37
|
+
describe('skills extension', () => {
|
|
38
|
+
it('loads skills from a directory at startup', () => {
|
|
39
|
+
makeSkill(tmpDir, 'code-review', { description: 'Review code' });
|
|
40
|
+
makeSkill(tmpDir, 'summarize', { description: 'Summarize text' });
|
|
41
|
+
const ext = createSkillExtension({ skillsDirs: tmpDir });
|
|
42
|
+
expect(ext).toBeDefined();
|
|
43
|
+
const agent = new Agent({ model: mockModel() });
|
|
44
|
+
agent.use(ext);
|
|
45
|
+
// list_skills should be registered as a tool
|
|
46
|
+
expect(agent.getTools()).toContain('list_skills');
|
|
47
|
+
expect(agent.getTools()).toContain('use_skill');
|
|
48
|
+
});
|
|
49
|
+
it('returns undefined when no skillsDirs provided', () => {
|
|
50
|
+
const ext = createSkillExtension({});
|
|
51
|
+
expect(ext).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
it('list_skills returns skills present at startup', async () => {
|
|
54
|
+
makeSkill(tmpDir, 'alpha', { description: 'Alpha skill' });
|
|
55
|
+
makeSkill(tmpDir, 'beta', { description: 'Beta skill' });
|
|
56
|
+
const ext = createSkillExtension({ skillsDirs: tmpDir });
|
|
57
|
+
const agent = new Agent({ model: mockModel() });
|
|
58
|
+
agent.use(ext);
|
|
59
|
+
// Find the list_skills tool and call it directly.
|
|
60
|
+
const tools = agent.getTools();
|
|
61
|
+
expect(tools).toContain('list_skills');
|
|
62
|
+
});
|
|
63
|
+
it('list_skills discovers new skills added at runtime', async () => {
|
|
64
|
+
// Start with one skill.
|
|
65
|
+
makeSkill(tmpDir, 'existing', { description: 'Existing skill' });
|
|
66
|
+
const ext = createSkillExtension({ skillsDirs: tmpDir });
|
|
67
|
+
const agent = new Agent({ model: mockModel() });
|
|
68
|
+
agent.use(ext);
|
|
69
|
+
// Add a new skill directory after the extension is installed.
|
|
70
|
+
makeSkill(tmpDir, 'runtime-added', { description: 'Added at runtime' });
|
|
71
|
+
// Model that calls list_skills on first turn, then returns the
|
|
72
|
+
// tool result as the final message so we can inspect it.
|
|
73
|
+
let callCount = 0;
|
|
74
|
+
let capturedToolResult = '';
|
|
75
|
+
const callModel = {
|
|
76
|
+
async generate(req) {
|
|
77
|
+
callCount++;
|
|
78
|
+
if (callCount === 1) {
|
|
79
|
+
return {
|
|
80
|
+
message: {
|
|
81
|
+
role: 'assistant',
|
|
82
|
+
content: '',
|
|
83
|
+
toolCalls: [{
|
|
84
|
+
id: 'call_1',
|
|
85
|
+
name: 'list_skills',
|
|
86
|
+
arguments: '{}',
|
|
87
|
+
}],
|
|
88
|
+
},
|
|
89
|
+
finishReason: 'tool_calls',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// Second call: capture the tool result and return it.
|
|
93
|
+
const toolMsg = req.messages.find((m) => m.role === 'tool');
|
|
94
|
+
capturedToolResult = toolMsg?.content ?? '';
|
|
95
|
+
return {
|
|
96
|
+
message: { role: 'assistant', content: capturedToolResult },
|
|
97
|
+
finishReason: 'stop',
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
const agent2 = new Agent({ model: callModel });
|
|
102
|
+
agent2.use(ext);
|
|
103
|
+
const result = await agent2.run({ message: 'list skills' });
|
|
104
|
+
expect(result.finishReason).toBe('stop');
|
|
105
|
+
expect(result.toolCalls?.some((tc) => tc.name === 'list_skills')).toBe(true);
|
|
106
|
+
// The tool result should include both the existing and runtime-added skills.
|
|
107
|
+
expect(capturedToolResult).toContain('existing');
|
|
108
|
+
expect(capturedToolResult).toContain('runtime-added');
|
|
109
|
+
});
|
|
110
|
+
it('use_skill can load a skill added at runtime', async () => {
|
|
111
|
+
// Start with no skills.
|
|
112
|
+
const ext = createSkillExtension({ skillsDirs: tmpDir });
|
|
113
|
+
const agent = new Agent({ model: mockModel() });
|
|
114
|
+
agent.use(ext);
|
|
115
|
+
// Add a skill after install.
|
|
116
|
+
makeSkill(tmpDir, 'late-skill', { description: 'Added late' }, 'Late skill content');
|
|
117
|
+
// Model that calls use_skill, then returns the result.
|
|
118
|
+
let sawSkillContent = false;
|
|
119
|
+
const callModel = {
|
|
120
|
+
async generate(req) {
|
|
121
|
+
const hasUseSkill = req.tools?.some((t) => t.function.name === 'use_skill');
|
|
122
|
+
if (hasUseSkill && !req.messages.some((m) => m.role === 'tool')) {
|
|
123
|
+
return {
|
|
124
|
+
message: {
|
|
125
|
+
role: 'assistant',
|
|
126
|
+
content: '',
|
|
127
|
+
toolCalls: [{
|
|
128
|
+
id: 'call_1',
|
|
129
|
+
name: 'use_skill',
|
|
130
|
+
arguments: JSON.stringify({ skill: 'late-skill' }),
|
|
131
|
+
}],
|
|
132
|
+
},
|
|
133
|
+
finishReason: 'tool_calls',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Check if the tool result contains the late skill content
|
|
137
|
+
const toolMsg = req.messages.find((m) => m.role === 'tool');
|
|
138
|
+
if (toolMsg && toolMsg.content.includes('Late skill content')) {
|
|
139
|
+
sawSkillContent = true;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
message: { role: 'assistant', content: 'done' },
|
|
143
|
+
finishReason: 'stop',
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
const agent2 = new Agent({ model: callModel });
|
|
148
|
+
agent2.use(ext);
|
|
149
|
+
await agent2.run({ message: 'use the late skill' });
|
|
150
|
+
expect(sawSkillContent).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
it('autoLoad skills are appended to system prompt at install time', () => {
|
|
153
|
+
makeSkill(tmpDir, 'always-on', { autoLoad: 'true', description: 'Always active' }, 'Always-on content');
|
|
154
|
+
let seenSystemPrompt = '';
|
|
155
|
+
const model = {
|
|
156
|
+
async generate(req) {
|
|
157
|
+
seenSystemPrompt = req.systemPrompt ?? '';
|
|
158
|
+
return {
|
|
159
|
+
message: { role: 'assistant', content: 'ok' },
|
|
160
|
+
finishReason: 'stop',
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
const ext = createSkillExtension({ skillsDirs: tmpDir });
|
|
165
|
+
const agent = new Agent({ model: model, systemPrompt: 'Base prompt.' });
|
|
166
|
+
agent.use(ext);
|
|
167
|
+
return agent.run({ message: 'hi' }).then(() => {
|
|
168
|
+
expect(seenSystemPrompt).toContain('Base prompt.');
|
|
169
|
+
expect(seenSystemPrompt).toContain('Always-on content');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
it('supports multiple skills directories', () => {
|
|
173
|
+
const dir2 = mkdtempSync(join(tmpdir(), 'skills-test-2-'));
|
|
174
|
+
makeSkill(tmpDir, 'from-dir1', { description: 'First dir' });
|
|
175
|
+
makeSkill(dir2, 'from-dir2', { description: 'Second dir' });
|
|
176
|
+
const ext = createSkillExtension({ skillsDirs: [tmpDir, dir2] });
|
|
177
|
+
const agent = new Agent({ model: mockModel() });
|
|
178
|
+
agent.use(ext);
|
|
179
|
+
expect(agent.getTools()).toContain('list_skills');
|
|
180
|
+
// Clean up second dir
|
|
181
|
+
rmSync(dir2, { recursive: true, force: true });
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=extension.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../../../src/extras/extensions/skills/extension.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Extension } from '../../../extension.js';
|
|
2
|
+
/**
|
|
3
|
+
* Streaming extension โ sets `onDelta` on the model request in
|
|
4
|
+
* `beforeLLM` so the AISdkModel uses its streaming path.
|
|
5
|
+
*
|
|
6
|
+
* The caller passes callbacks via `metadata.streamCallbacks`:
|
|
7
|
+
* - `onText(delta)` โ text token deltas
|
|
8
|
+
* - `onReasoning(delta)` โ reasoning/thinking token deltas
|
|
9
|
+
* - `onToolInput(delta, toolName)` โ tool argument token deltas
|
|
10
|
+
*
|
|
11
|
+
* When no `streamCallbacks` are in metadata, the extension is a no-op
|
|
12
|
+
* and the model uses `doGenerate` (no streaming overhead).
|
|
13
|
+
*/
|
|
14
|
+
export default function createStreamingExtension(): Extension;
|
|
15
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/streaming/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,wBAAwB,IAAI,SAAS,CAgC5D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming extension โ sets `onDelta` on the model request in
|
|
3
|
+
* `beforeLLM` so the AISdkModel uses its streaming path.
|
|
4
|
+
*
|
|
5
|
+
* The caller passes callbacks via `metadata.streamCallbacks`:
|
|
6
|
+
* - `onText(delta)` โ text token deltas
|
|
7
|
+
* - `onReasoning(delta)` โ reasoning/thinking token deltas
|
|
8
|
+
* - `onToolInput(delta, toolName)` โ tool argument token deltas
|
|
9
|
+
*
|
|
10
|
+
* When no `streamCallbacks` are in metadata, the extension is a no-op
|
|
11
|
+
* and the model uses `doGenerate` (no streaming overhead).
|
|
12
|
+
*/
|
|
13
|
+
export default function createStreamingExtension() {
|
|
14
|
+
return {
|
|
15
|
+
name: 'streaming',
|
|
16
|
+
priority: 100,
|
|
17
|
+
install(agent) {
|
|
18
|
+
agent.hook('beforeLLM', 'streaming', async (ctx) => {
|
|
19
|
+
if (!ctx.modelRequest)
|
|
20
|
+
return;
|
|
21
|
+
const callbacks = ctx.turn.metadata.streamCallbacks;
|
|
22
|
+
if (!callbacks)
|
|
23
|
+
return;
|
|
24
|
+
ctx.modelRequest.onDelta = (delta) => {
|
|
25
|
+
switch (delta.type) {
|
|
26
|
+
case 'text':
|
|
27
|
+
callbacks.onText?.(delta.content);
|
|
28
|
+
break;
|
|
29
|
+
case 'reasoning':
|
|
30
|
+
callbacks.onReasoning?.(delta.content);
|
|
31
|
+
break;
|
|
32
|
+
case 'tool-input':
|
|
33
|
+
callbacks.onToolInput?.(delta.content, delta.toolName ?? '');
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/streaming/extension.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,wBAAwB;IAC9C,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,GAAG;QACb,OAAO,CAAC,KAAK;YACX,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACjD,IAAI,CAAC,GAAG,CAAC,YAAY;oBAAE,OAAO;gBAE9B,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,eAIvB,CAAC;gBAEd,IAAI,CAAC,SAAS;oBAAE,OAAO;gBAEvB,GAAG,CAAC,YAAY,CAAC,OAAO,GAAG,CAAC,KAAiB,EAAE,EAAE;oBAC/C,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;wBACnB,KAAK,MAAM;4BACT,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;4BAClC,MAAM;wBACR,KAAK,WAAW;4BACd,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;4BACvC,MAAM;wBACR,KAAK,YAAY;4BACf,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;4BAC7D,MAAM;oBACV,CAAC;gBACH,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/streaming/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/streaming/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Extension } from '../../../extension.js';
|
|
2
|
+
export interface StructuredOutputConfig {
|
|
3
|
+
/** JSON schema to validate against. Required. */
|
|
4
|
+
schema: Record<string, unknown>;
|
|
5
|
+
/** Field name in metadata to store the parsed JSON. Default: "structured". */
|
|
6
|
+
metadataKey?: string;
|
|
7
|
+
/** Whether to strip markdown code fences from the response. Default: true. */
|
|
8
|
+
stripCodeFences?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export default function createStructuredOutputExtension(config: StructuredOutputConfig): Extension | undefined;
|
|
11
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/structured-output/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,+BAA+B,CACrD,MAAM,EAAE,sBAAsB,GAC7B,SAAS,GAAG,SAAS,CA8GvB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export default function createStructuredOutputExtension(config) {
|
|
2
|
+
if (!config?.schema) {
|
|
3
|
+
console.log('[structured-output] no schema in config โ skipping');
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const { schema } = config;
|
|
7
|
+
const metadataKey = config.metadataKey ?? 'structured';
|
|
8
|
+
const stripCodeFences = config.stripCodeFences ?? true;
|
|
9
|
+
return {
|
|
10
|
+
name: 'structured-output',
|
|
11
|
+
priority: 50,
|
|
12
|
+
install(agent) {
|
|
13
|
+
agent.hook('beforeResponse', 'structured-output', async (ctx) => {
|
|
14
|
+
if (!ctx.turn.response)
|
|
15
|
+
return;
|
|
16
|
+
let raw = ctx.turn.response.message;
|
|
17
|
+
// Strip markdown code fences if present (LLMs often wrap JSON in ```json ... ```).
|
|
18
|
+
if (stripCodeFences) {
|
|
19
|
+
const fenceMatch = raw.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
20
|
+
if (fenceMatch) {
|
|
21
|
+
raw = fenceMatch[1].trim();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Not valid JSON โ replace the response with an error that includes the schema.
|
|
30
|
+
ctx.turn.response = {
|
|
31
|
+
...ctx.turn.response,
|
|
32
|
+
message: JSON.stringify({
|
|
33
|
+
error: 'Response is not valid JSON',
|
|
34
|
+
expectedSchema: schema,
|
|
35
|
+
rawResponse: ctx.turn.response.message.slice(0, 500),
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Validate against the schema's required fields.
|
|
41
|
+
const required = schema.required ?? [];
|
|
42
|
+
const missing = required.filter((field) => {
|
|
43
|
+
const value = parsed[field];
|
|
44
|
+
return value === undefined || value === null;
|
|
45
|
+
});
|
|
46
|
+
if (missing.length > 0) {
|
|
47
|
+
ctx.turn.response = {
|
|
48
|
+
...ctx.turn.response,
|
|
49
|
+
message: JSON.stringify({
|
|
50
|
+
error: `Missing required fields: ${missing.join(', ')}`,
|
|
51
|
+
expectedSchema: schema,
|
|
52
|
+
received: Object.keys(parsed),
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Type-check each field against the schema.
|
|
58
|
+
const properties = schema.properties ?? {};
|
|
59
|
+
const typeErrors = [];
|
|
60
|
+
for (const [field, spec] of Object.entries(properties)) {
|
|
61
|
+
const value = parsed[field];
|
|
62
|
+
if (value === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
const expectedType = spec.type;
|
|
65
|
+
let actualType;
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
actualType = 'array';
|
|
68
|
+
}
|
|
69
|
+
else if (typeof value === 'number' && Number.isInteger(value)) {
|
|
70
|
+
actualType = 'number';
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
actualType = typeof value;
|
|
74
|
+
}
|
|
75
|
+
if (actualType !== expectedType) {
|
|
76
|
+
typeErrors.push(`Field "${field}" expected ${expectedType}, got ${actualType}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (typeErrors.length > 0) {
|
|
80
|
+
ctx.turn.response = {
|
|
81
|
+
...ctx.turn.response,
|
|
82
|
+
message: JSON.stringify({
|
|
83
|
+
error: 'Type validation failed',
|
|
84
|
+
errors: typeErrors,
|
|
85
|
+
expectedSchema: schema,
|
|
86
|
+
}),
|
|
87
|
+
};
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Valid โ store the parsed object in metadata and clean up the response.
|
|
91
|
+
ctx.turn.metadata[metadataKey] = parsed;
|
|
92
|
+
// Keep the response as the raw JSON string so callers can parse it.
|
|
93
|
+
// Or optionally replace with a formatted version.
|
|
94
|
+
ctx.turn.response = {
|
|
95
|
+
...ctx.turn.response,
|
|
96
|
+
message: JSON.stringify(parsed, null, 2),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/structured-output/extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "structured-output",
|
|
3
|
+
"description": "Validates LLM output against a JSON schema via beforeResponse hook. Accepts a schema, optional metadataKey, and stripCodeFences via config.",
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"priority": 50,
|
|
6
|
+
"configKeys": ["schema", "metadataKey", "stripCodeFences"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/structured-output/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,gBAAgB,CAAC;AAC5E,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/structured-output/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Extension } from '../../../extension.js';
|
|
2
|
+
/**
|
|
3
|
+
* timestamp extension โ records start/finish ISO timestamps in turn
|
|
4
|
+
* metadata for observability.
|
|
5
|
+
*
|
|
6
|
+
* Sets `metadata.startedAt` in `beforeTurn` and `metadata.finishedAt`
|
|
7
|
+
* in `afterTurn`. No config needed โ self-contained.
|
|
8
|
+
*/
|
|
9
|
+
declare const timestampExtension: Extension;
|
|
10
|
+
export default timestampExtension;
|
|
11
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/timestamp/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;GAMG;AACH,QAAA,MAAM,kBAAkB,EAAE,SAWzB,CAAC;eAEa,kBAAkB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* timestamp extension โ records start/finish ISO timestamps in turn
|
|
3
|
+
* metadata for observability.
|
|
4
|
+
*
|
|
5
|
+
* Sets `metadata.startedAt` in `beforeTurn` and `metadata.finishedAt`
|
|
6
|
+
* in `afterTurn`. No config needed โ self-contained.
|
|
7
|
+
*/
|
|
8
|
+
const timestampExtension = {
|
|
9
|
+
name: 'timestamp',
|
|
10
|
+
priority: 0,
|
|
11
|
+
install(agent) {
|
|
12
|
+
agent.hook('beforeTurn', 'timestamp', async (ctx) => {
|
|
13
|
+
ctx.turn.metadata.startedAt = new Date().toISOString();
|
|
14
|
+
});
|
|
15
|
+
agent.hook('afterTurn', 'timestamp', async (ctx) => {
|
|
16
|
+
ctx.turn.metadata.finishedAt = new Date().toISOString();
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export default timestampExtension;
|
|
21
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/timestamp/extension.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAc;IACpC,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,CAAC;IACX,OAAO,CAAC,KAAK;QACX,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClD,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACjD,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/timestamp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/timestamp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Extension } from '../../../extension.js';
|
|
2
|
+
/**
|
|
3
|
+
* Config for the token-stats extension.
|
|
4
|
+
*/
|
|
5
|
+
export interface TokenStatsConfig {
|
|
6
|
+
/**
|
|
7
|
+
* The model's maximum context window in tokens. Used to compute the
|
|
8
|
+
* context window usage percentage. If omitted, the percentage is
|
|
9
|
+
* not shown. Default: not set.
|
|
10
|
+
*
|
|
11
|
+
* For DeepSeek v4: 131072 (128K). Check your provider's docs.
|
|
12
|
+
*/
|
|
13
|
+
contextWindow?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Whether to use Slack italic formatting (`_text_`) for the stats
|
|
16
|
+
* line. Default: `true`.
|
|
17
|
+
*/
|
|
18
|
+
slackItalics?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Label for the stats line. Default: `๐`.
|
|
21
|
+
*/
|
|
22
|
+
label?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Token-stats extension โ appends a stats line to the agent's final
|
|
26
|
+
* response message.
|
|
27
|
+
*
|
|
28
|
+
* Accumulates token usage across all LLM calls in a turn (via
|
|
29
|
+
* `afterLLM`), then appends a summary to `turn.response.message` in
|
|
30
|
+
* `beforeResponse`. The stats include:
|
|
31
|
+
*
|
|
32
|
+
* - Total prompt + completion tokens
|
|
33
|
+
* - Cached and reasoning tokens (if reported)
|
|
34
|
+
* - Number of LLM calls / iterations
|
|
35
|
+
* - Context window usage percentage (if `contextWindow` is configured)
|
|
36
|
+
*
|
|
37
|
+
* ## Example output (Slack italics)
|
|
38
|
+
*
|
|
39
|
+
* ```
|
|
40
|
+
* _๐ 105,445 prompt + 2,324 completion ยท 1,503 reasoning ยท 3 LLM calls ยท 82% of 128K context_
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* ## Priority
|
|
44
|
+
*
|
|
45
|
+
* Uses priority -100 (runs late, after most extensions) so it sees
|
|
46
|
+
* the final response after other extensions have potentially modified
|
|
47
|
+
* it. The `afterLLM` accumulator runs at the same priority.
|
|
48
|
+
*/
|
|
49
|
+
export default function createTokenStatsExtension(config?: TokenStatsConfig): Extension;
|
|
50
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/token-stats/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAC/C,MAAM,CAAC,EAAE,gBAAgB,GACxB,SAAS,CAsEX"}
|