foliko 2.0.3 → 2.0.5

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.
@@ -225,7 +225,7 @@ class ChatSession extends EventEmitter {
225
225
  messageStore.messages = messages;
226
226
  messageStore.historyLoaded = true;
227
227
  messageStore._hasMoreHistory = allMessages.length > MAX_INITIAL_LOAD;
228
- logger.debug(`Loaded ${messages.length} msgs for session ${sessionId} (total: ${allMessages.length})`);
228
+ //logger.debug(`Loaded ${messages.length} msgs for session ${sessionId} (total: ${allMessages.length})`);
229
229
  }
230
230
  }
231
231
  }
@@ -35,7 +35,7 @@ class ToolExecutor extends EventEmitter {
35
35
  return;
36
36
  }
37
37
  this._tools.set(tool.name, tool);
38
- logger.debug('ToolExecutor', `Registered tool: ${tool.name}`);
38
+ //logger.debug('ToolExecutor', `Registered tool: ${tool.name}`);
39
39
  }
40
40
 
41
41
  unregisterTool(name) {
@@ -17,7 +17,7 @@ describe('Plugin declarative prompts', () => {
17
17
  prompts = [
18
18
  {
19
19
  name: 'demo',
20
- slot: 'BEHAVIOR',
20
+ priority: 50,
21
21
  description: 'demo part',
22
22
  provider: function () {
23
23
  return 'demo-content';
@@ -43,7 +43,7 @@ describe('Plugin declarative prompts', () => {
43
43
  prompts = [
44
44
  {
45
45
  name: 'foo',
46
- slot: 'CAPABILITY',
46
+ scope: 'global',
47
47
  provider: function () {
48
48
  return 'foo';
49
49
  },
@@ -70,7 +70,7 @@ describe('Plugin declarative prompts', () => {
70
70
  { provider: () => 'no-name' },
71
71
  {
72
72
  name: 'valid',
73
- slot: 'CUSTOM',
73
+ priority: 50,
74
74
  provider: function () {
75
75
  return 'valid-content';
76
76
  },
@@ -99,7 +99,7 @@ describe('Plugin declarative prompts', () => {
99
99
  prompts = [
100
100
  {
101
101
  name: 'capture',
102
- slot: 'BEHAVIOR',
102
+ scope: 'global',
103
103
  provider: function () {
104
104
  capturedThis = this;
105
105
  return 'x';
@@ -122,8 +122,8 @@ describe('Plugin declarative prompts', () => {
122
122
  return this;
123
123
  }
124
124
  prompts = [
125
- { name: 'a', slot: 'BEHAVIOR', provider: () => 'a' },
126
- { name: 'b', slot: 'BEHAVIOR', provider: () => 'b' },
125
+ { name: 'a', priority: 50, provider: () => 'a' },
126
+ { name: 'b', priority: 60, provider: () => 'b' },
127
127
  ];
128
128
  }
129
129
  const plugin = new CleanupPlugin();
@@ -146,7 +146,7 @@ describe('Plugin declarative prompts', () => {
146
146
  prompts = [
147
147
  {
148
148
  name: 'reloadable',
149
- slot: 'CUSTOM',
149
+ priority: 50,
150
150
  provider: function () {
151
151
  return 'v1';
152
152
  },
@@ -177,7 +177,7 @@ describe('Plugin declarative prompts', () => {
177
177
  prompts = [
178
178
  {
179
179
  name: 'demo',
180
- slot: 'CUSTOM',
180
+ priority: 50,
181
181
  provider: function () {
182
182
  return 'demo-content';
183
183
  },
@@ -192,7 +192,7 @@ describe('Plugin declarative prompts', () => {
192
192
  expect(fw.prompts.getPart('test-owner', 'demo').get()).toBe('demo-content');
193
193
  });
194
194
 
195
- it('renders in slot order', () => {
195
+ it('renders in priority order', () => {
196
196
  class MultiPlugin extends Plugin {
197
197
  name = 'multi';
198
198
  install(f) {
@@ -200,9 +200,9 @@ describe('Plugin declarative prompts', () => {
200
200
  return this;
201
201
  }
202
202
  prompts = [
203
- { name: 'behavior', slot: 'BEHAVIOR', provider: () => 'BEHAVIOR_CONTENT' },
204
- { name: 'identity', slot: 'IDENTITY', provider: () => 'IDENTITY_CONTENT' },
205
- { name: 'capability', slot: 'CAPABILITY', provider: () => 'CAPABILITY_CONTENT' },
203
+ { name: 'behavior', priority: 50, provider: () => 'BEHAVIOR_CONTENT' },
204
+ { name: 'identity', priority: 10, provider: () => 'IDENTITY_CONTENT' },
205
+ { name: 'capability', priority: 30, provider: () => 'CAPABILITY_CONTENT' },
206
206
  ];
207
207
  }
208
208
  const plugin = new MultiPlugin();
@@ -216,4 +216,4 @@ describe('Plugin declarative prompts', () => {
216
216
  expect(identityIdx).toBeLessThan(capabilityIdx);
217
217
  expect(capabilityIdx).toBeLessThan(behaviorIdx);
218
218
  });
219
- });
219
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, beforeEach } from 'vitest';
2
- import { PromptRegistry, PROMPT_SLOT, PROMPT_PRIORITY_TO_SLOT } from '../../src/index';
2
+ import { PromptRegistry } from '../../src/index';
3
3
 
4
4
  describe('PromptRegistry', () => {
5
5
  let reg;
@@ -10,13 +10,20 @@ describe('PromptRegistry', () => {
10
10
 
11
11
  describe('basic API', () => {
12
12
  it('registers and retrieves a part', () => {
13
- reg.register('plugin-a', 'foo', () => 'hello', { slot: 'IDENTITY' });
13
+ reg.register('plugin-a', 'foo', () => 'hello');
14
14
  const part = reg.getPart('plugin-a', 'foo');
15
15
  expect(part).toBeTruthy();
16
16
  expect(part.get()).toBe('hello');
17
17
  expect(reg.count()).toBe(1);
18
18
  });
19
19
 
20
+ it('registers with scope and priority', () => {
21
+ reg.register('plugin-a', 'foo', () => 'hello', { scope: 'global', priority: 50 });
22
+ const part = reg.getPart('plugin-a', 'foo');
23
+ expect(part.scope).toBe('global');
24
+ expect(part.priority).toBe(50);
25
+ });
26
+
20
27
  it('requires owner/name/provider', () => {
21
28
  expect(() => reg.register('', 'foo', () => 'x')).toThrow(/owner/);
22
29
  expect(() => reg.register('p', '', () => 'x')).toThrow(/name/);
@@ -47,46 +54,53 @@ describe('PromptRegistry', () => {
47
54
  });
48
55
  });
49
56
 
50
- describe('slot ordering', () => {
51
- it('orders by slot order', () => {
52
- reg.register('p', 'a', () => 'BEHAVIOR', { slot: 'BEHAVIOR' });
53
- reg.register('p', 'b', () => 'IDENTITY', { slot: 'IDENTITY' });
54
- reg.register('p', 'c', () => 'CAPABILITY', { slot: 'CAPABILITY' });
55
- const order = reg.list().map((p) => p.slot);
56
- expect(order).toEqual(['IDENTITY', 'CAPABILITY', 'BEHAVIOR']);
57
- });
58
-
59
- it('uses explicit order within same slot', () => {
60
- reg.register('p', 'late', () => 'late', { slot: 'IDENTITY', order: 5 });
61
- reg.register('p', 'early', () => 'early', { slot: 'IDENTITY', order: 1 });
62
- const names = reg.list().map((p) => p.name);
63
- expect(names).toEqual(['early', 'late']);
57
+ describe('priority ordering', () => {
58
+ it('orders by priority (smaller first)', () => {
59
+ reg.register('p', 'a', () => 'a', { priority: 100 });
60
+ reg.register('p', 'b', () => 'b', { priority: 10 });
61
+ reg.register('p', 'c', () => 'c', { priority: 50 });
62
+ const order = reg.list().map((p) => p.name);
63
+ expect(order).toEqual(['b', 'c', 'a']);
64
64
  });
65
65
 
66
- it('falls back to alphabetical when order is equal', () => {
67
- reg.register('zeta', 'z', () => 'z', { slot: 'IDENTITY' });
68
- reg.register('alpha', 'a', () => 'a', { slot: 'IDENTITY' });
66
+ it('falls back to owner alphabetical when priority is equal', () => {
67
+ reg.register('zeta', 'z', () => 'z', { priority: 50 });
68
+ reg.register('alpha', 'a', () => 'a', { priority: 50 });
69
69
  const owners = reg.list().map((p) => p.owner);
70
70
  expect(owners).toEqual(['alpha', 'zeta']);
71
71
  });
72
72
 
73
- it('PROMPT_SLOT exposes 7 named slots', () => {
74
- const names = Object.keys(PROMPT_SLOT);
75
- expect(names).toContain('IDENTITY');
76
- expect(names).toContain('ENVIRONMENT');
77
- expect(names).toContain('USER');
78
- expect(names).toContain('CAPABILITY');
79
- expect(names).toContain('BEHAVIOR');
80
- expect(names).toContain('CONTEXT');
81
- expect(names).toContain('CUSTOM');
73
+ it('defaults to priority 100', () => {
74
+ reg.register('p', 'a', () => 'a');
75
+ reg.register('p', 'b', () => 'b', { priority: 50 });
76
+ const order = reg.list().map((p) => p.name);
77
+ expect(order).toEqual(['b', 'a']);
78
+ });
79
+ });
80
+
81
+ describe('scope filtering', () => {
82
+ it('listByScope filters correctly', () => {
83
+ reg.register('p', 'a', () => 'a', { scope: 'global' });
84
+ reg.register('p', 'b', () => 'b', { scope: 'main' });
85
+ reg.register('p', 'c', () => 'c', { scope: 'sub-1' });
86
+ expect(reg.listByScope('global').map((p) => p.name)).toEqual(['a']);
87
+ expect(reg.listByScope('main').map((p) => p.name)).toEqual(['b']);
88
+ expect(reg.listByScope('sub-1').map((p) => p.name)).toEqual(['c']);
82
89
  });
83
90
 
84
- it('PROMPT_PRIORITY_TO_SLOT maps all legacy priorities', () => {
85
- expect(PROMPT_PRIORITY_TO_SLOT.DATETIME).toBe('ENVIRONMENT');
86
- expect(PROMPT_PRIORITY_TO_SLOT.ORIGINAL_PROMPT).toBe('IDENTITY');
87
- expect(PROMPT_PRIORITY_TO_SLOT.SHARED_PROMPT).toBe('USER');
88
- expect(PROMPT_PRIORITY_TO_SLOT.CAPABILITIES).toBe('CAPABILITY');
89
- expect(PROMPT_PRIORITY_TO_SLOT.TOOL_CORE_RULES).toBe('BEHAVIOR');
91
+ it('listForAgent includes global and matching scope', () => {
92
+ reg.register('p', 'global', () => 'g', { scope: 'global' });
93
+ reg.register('p', 'main', () => 'm', { scope: 'main' });
94
+ reg.register('p', 'sub1', () => 's1', { scope: 'sub-1' });
95
+ reg.register('p', 'sub2', () => 's2', { scope: 'sub-2' });
96
+
97
+ // Main agent sees global + main
98
+ const mainParts = reg.listForAgent(null).map((p) => p.name);
99
+ expect(mainParts).toEqual(['global', 'main']);
100
+
101
+ // sub-1 agent sees global + sub1
102
+ const sub1Parts = reg.listForAgent('sub-1').map((p) => p.name);
103
+ expect(sub1Parts).toEqual(['global', 'sub1']);
90
104
  });
91
105
  });
92
106
 
@@ -97,6 +111,13 @@ describe('PromptRegistry', () => {
97
111
  expect(reg.build()).toBe('AAA\n\nBBB');
98
112
  });
99
113
 
114
+ it('builds only parts for specific agent', () => {
115
+ reg.register('p', 'global', () => 'G', { scope: 'global' });
116
+ reg.register('p', 'main', () => 'M', { scope: 'main' });
117
+ reg.register('p', 'sub1', () => 'S1', { scope: 'sub-1' });
118
+ expect(reg.buildForAgent('sub-1')).toBe('G\n\nS1');
119
+ });
120
+
100
121
  it('skips null/empty content', () => {
101
122
  reg.register('p', 'a', () => 'AAA');
102
123
  reg.register('p', 'b', () => null);
@@ -116,7 +137,6 @@ describe('PromptRegistry', () => {
116
137
  console.warn = (msg) => warnings.push(msg);
117
138
  try {
118
139
  const result = reg.build();
119
- // 排序:after → bad(fail) → good → "BBB\n\nAAA"
120
140
  expect(result).toBe('BBB\n\nAAA');
121
141
  expect(warnings.length).toBe(1);
122
142
  } finally {
@@ -170,14 +190,14 @@ describe('PromptRegistry', () => {
170
190
 
171
191
  describe('inspect', () => {
172
192
  it('returns structured per-part metadata', () => {
173
- reg.register('plugin-a', 'foo', () => 'hello world', { slot: 'IDENTITY' });
193
+ reg.register('plugin-a', 'foo', () => 'hello world', { scope: 'global', priority: 50 });
174
194
  const out = reg.inspect();
175
195
  expect(out).toHaveLength(1);
176
196
  expect(out[0]).toMatchObject({
177
197
  owner: 'plugin-a',
178
198
  name: 'foo',
179
- slot: 'IDENTITY',
180
- order: 10,
199
+ scope: 'global',
200
+ priority: 50,
181
201
  hasContent: true,
182
202
  length: 11,
183
203
  });
@@ -190,20 +210,8 @@ describe('PromptRegistry', () => {
190
210
  const { Framework } = require('../../src/index');
191
211
  const fw = new Framework({ silent: true });
192
212
  expect(fw.prompts).toBeDefined();
193
- expect(fw.prompts).toBe(fw.promptRegistry);
194
213
  expect(typeof fw.prompts.register).toBe('function');
195
214
  expect(typeof fw.prompts.preview).toBe('function');
196
215
  });
197
-
198
- it('each agent has its own promptRegistry via BaseAgent', () => {
199
- const { BaseAgent } = require('../../src/agent/base');
200
- const { Framework } = require('../../src/index');
201
- const fw = new Framework({ silent: true });
202
- const agent = new BaseAgent(fw, { name: 'Test' });
203
- expect(agent.promptRegistry).toBeDefined();
204
- expect(agent.promptRegistry).toBe(agent._promptRegistry);
205
- agent.promptRegistry.register('test', 'foo', () => 'x', { slot: 'CUSTOM' });
206
- expect(agent.promptRegistry.count()).toBe(1);
207
- });
208
216
  });
209
- });
217
+ });