@dot-ai/core 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/boot-cache.d.ts +40 -0
  2. package/dist/boot-cache.d.ts.map +1 -0
  3. package/dist/boot-cache.js +72 -0
  4. package/dist/boot-cache.js.map +1 -0
  5. package/dist/capabilities.d.ts +35 -0
  6. package/dist/capabilities.d.ts.map +1 -0
  7. package/dist/capabilities.js +17 -0
  8. package/dist/capabilities.js.map +1 -0
  9. package/dist/config.d.ts +7 -23
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +131 -108
  12. package/dist/config.js.map +1 -1
  13. package/dist/extension-api.d.ts +65 -0
  14. package/dist/extension-api.d.ts.map +1 -0
  15. package/dist/extension-api.js +2 -0
  16. package/dist/extension-api.js.map +1 -0
  17. package/dist/extension-loader.d.ts +19 -0
  18. package/dist/extension-loader.d.ts.map +1 -0
  19. package/dist/extension-loader.js +113 -0
  20. package/dist/extension-loader.js.map +1 -0
  21. package/dist/extension-runner.d.ts +62 -0
  22. package/dist/extension-runner.d.ts.map +1 -0
  23. package/dist/extension-runner.js +260 -0
  24. package/dist/extension-runner.js.map +1 -0
  25. package/dist/extension-types.d.ts +312 -0
  26. package/dist/extension-types.d.ts.map +1 -0
  27. package/dist/extension-types.js +89 -0
  28. package/dist/extension-types.js.map +1 -0
  29. package/dist/format.d.ts +13 -1
  30. package/dist/format.d.ts.map +1 -1
  31. package/dist/format.js +131 -15
  32. package/dist/format.js.map +1 -1
  33. package/dist/format.spec.d.ts +2 -0
  34. package/dist/format.spec.d.ts.map +1 -0
  35. package/dist/format.spec.js +140 -0
  36. package/dist/format.spec.js.map +1 -0
  37. package/dist/index.d.ts +21 -14
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +21 -14
  40. package/dist/index.js.map +1 -1
  41. package/dist/logger.d.ts +1 -1
  42. package/dist/logger.d.ts.map +1 -1
  43. package/dist/package-manager.d.ts +30 -0
  44. package/dist/package-manager.d.ts.map +1 -0
  45. package/dist/package-manager.js +91 -0
  46. package/dist/package-manager.js.map +1 -0
  47. package/dist/runtime.d.ts +119 -0
  48. package/dist/runtime.d.ts.map +1 -0
  49. package/dist/runtime.js +441 -0
  50. package/dist/runtime.js.map +1 -0
  51. package/dist/types.d.ts +29 -10
  52. package/dist/types.d.ts.map +1 -1
  53. package/package.json +4 -1
  54. package/src/__tests__/capabilities.test.ts +72 -0
  55. package/src/__tests__/config.test.ts +22 -120
  56. package/src/__tests__/extension-loader.test.ts +84 -0
  57. package/src/__tests__/extension-runner.test.ts +228 -0
  58. package/src/__tests__/fixtures/extensions/ctx-aware.js +26 -0
  59. package/src/__tests__/fixtures/extensions/security-gate.js +20 -0
  60. package/src/__tests__/fixtures/extensions/session-analytics.js +28 -0
  61. package/src/__tests__/fixtures/extensions/smart-context.js +10 -0
  62. package/src/__tests__/format.test.ts +207 -2
  63. package/src/__tests__/runtime.test.ts +141 -0
  64. package/src/boot-cache.ts +104 -0
  65. package/src/capabilities.ts +49 -0
  66. package/src/config.ts +131 -133
  67. package/src/extension-api.ts +99 -0
  68. package/src/extension-loader.ts +127 -0
  69. package/src/extension-runner.ts +297 -0
  70. package/src/extension-types.ts +416 -0
  71. package/src/format.spec.ts +175 -0
  72. package/src/format.test.ts +218 -0
  73. package/src/format.ts +140 -16
  74. package/src/index.ts +68 -30
  75. package/src/logger.ts +1 -1
  76. package/src/package-manager.ts +119 -0
  77. package/src/runtime.ts +562 -0
  78. package/src/types.ts +36 -14
  79. package/tsconfig.json +1 -1
  80. package/tsconfig.tsbuildinfo +1 -1
  81. package/.ai/memory/2026-03-04.md +0 -2
  82. package/.ai/tasks.json +0 -7
  83. package/dist/__tests__/config.test.d.ts +0 -2
  84. package/dist/__tests__/config.test.d.ts.map +0 -1
  85. package/dist/__tests__/config.test.js +0 -128
  86. package/dist/__tests__/config.test.js.map +0 -1
  87. package/dist/__tests__/e2e.test.d.ts +0 -2
  88. package/dist/__tests__/e2e.test.d.ts.map +0 -1
  89. package/dist/__tests__/e2e.test.js +0 -211
  90. package/dist/__tests__/e2e.test.js.map +0 -1
  91. package/dist/__tests__/engine.test.d.ts +0 -2
  92. package/dist/__tests__/engine.test.d.ts.map +0 -1
  93. package/dist/__tests__/engine.test.js +0 -271
  94. package/dist/__tests__/engine.test.js.map +0 -1
  95. package/dist/__tests__/format.test.d.ts +0 -2
  96. package/dist/__tests__/format.test.d.ts.map +0 -1
  97. package/dist/__tests__/format.test.js +0 -200
  98. package/dist/__tests__/format.test.js.map +0 -1
  99. package/dist/__tests__/labels.test.d.ts +0 -2
  100. package/dist/__tests__/labels.test.d.ts.map +0 -1
  101. package/dist/__tests__/labels.test.js +0 -82
  102. package/dist/__tests__/labels.test.js.map +0 -1
  103. package/dist/__tests__/loader.test.d.ts +0 -2
  104. package/dist/__tests__/loader.test.d.ts.map +0 -1
  105. package/dist/__tests__/loader.test.js +0 -161
  106. package/dist/__tests__/loader.test.js.map +0 -1
  107. package/dist/__tests__/logger.test.d.ts +0 -2
  108. package/dist/__tests__/logger.test.d.ts.map +0 -1
  109. package/dist/__tests__/logger.test.js +0 -95
  110. package/dist/__tests__/logger.test.js.map +0 -1
  111. package/dist/__tests__/nodes.test.d.ts +0 -2
  112. package/dist/__tests__/nodes.test.d.ts.map +0 -1
  113. package/dist/__tests__/nodes.test.js +0 -83
  114. package/dist/__tests__/nodes.test.js.map +0 -1
  115. package/dist/contracts.d.ts +0 -56
  116. package/dist/contracts.d.ts.map +0 -1
  117. package/dist/contracts.js +0 -2
  118. package/dist/contracts.js.map +0 -1
  119. package/dist/engine.d.ts +0 -38
  120. package/dist/engine.d.ts.map +0 -1
  121. package/dist/engine.js +0 -88
  122. package/dist/engine.js.map +0 -1
  123. package/dist/loader.d.ts +0 -26
  124. package/dist/loader.d.ts.map +0 -1
  125. package/dist/loader.js +0 -120
  126. package/dist/loader.js.map +0 -1
  127. package/src/__tests__/e2e.test.ts +0 -257
  128. package/src/__tests__/engine.test.ts +0 -305
  129. package/src/__tests__/loader.test.ts +0 -191
  130. package/src/contracts.ts +0 -71
  131. package/src/engine.ts +0 -145
  132. package/src/loader.ts +0 -152
@@ -0,0 +1,312 @@
1
+ import type { Label, RoutingResult } from './types.js';
2
+ /**
3
+ * Base context passed to every event handler (second argument).
4
+ * Adapters extend this with agent-specific state (providers, session control, etc.).
5
+ * Mirrors Pi's `ctx` pattern: handler(event, ctx).
6
+ */
7
+ export interface ExtensionContext {
8
+ /** Current workspace root */
9
+ workspaceRoot: string;
10
+ /** Inter-extension event bus */
11
+ events: {
12
+ on(event: string, handler: (...args: unknown[]) => void): void;
13
+ off(event: string, handler: (...args: unknown[]) => void): void;
14
+ emit(event: string, ...args: unknown[]): void;
15
+ };
16
+ }
17
+ /**
18
+ * A section is the atomic output unit of `context_enrich`.
19
+ * Extensions return sections; the formatter assembles them by priority.
20
+ */
21
+ export interface Section {
22
+ /** Unique identifier for this section (optional — anonymous sections are allowed) */
23
+ id?: string;
24
+ /** Section heading */
25
+ title: string;
26
+ /** Markdown content */
27
+ content: string;
28
+ /**
29
+ * Priority determines ordering and trim precedence.
30
+ * 100 = identity, 80 = memory, 60 = skills, 50 = tasks, 40 = tools, 30 = routing.
31
+ */
32
+ priority: number;
33
+ /** Which extension produced this section */
34
+ source: string;
35
+ /**
36
+ * How this section should be handled when the token budget is exceeded.
37
+ * - 'never': never trim (identity, critical context)
38
+ * - 'truncate': shorten content but keep section
39
+ * - 'drop': remove entirely (default)
40
+ */
41
+ trimStrategy?: 'never' | 'truncate' | 'drop';
42
+ }
43
+ /** A single resource entry discovered by an extension */
44
+ export interface ResourceEntry {
45
+ /** Resource type: 'skill', 'identity', 'tool', 'prompt', etc. */
46
+ type: string;
47
+ /** Path to the resource (absolute or relative to workspace) */
48
+ path: string;
49
+ /** Labels for this specific resource */
50
+ labels?: string[];
51
+ /** Provider-specific metadata */
52
+ metadata?: Record<string, unknown>;
53
+ }
54
+ /** Result returned by resources_discover handlers */
55
+ export interface ResourcesDiscoverResult {
56
+ /** Labels contributed to the global vocabulary */
57
+ labels?: string[];
58
+ /** Discovered resources (paths + metadata) */
59
+ resources?: ResourceEntry[];
60
+ }
61
+ /** Event for label_extract -- handlers modify and return the labels array */
62
+ export interface LabelExtractEvent {
63
+ /** The user's prompt text */
64
+ prompt: string;
65
+ /** Known label vocabulary (from resources_discover) */
66
+ vocabulary: string[];
67
+ /** Current labels -- handler returns modified array */
68
+ labels: Label[];
69
+ }
70
+ /** Event for context_enrich -- replaces context_inject in v6 */
71
+ export interface ContextEnrichEvent {
72
+ /** The user's prompt text */
73
+ prompt: string;
74
+ /** Matched labels for this turn */
75
+ labels: Label[];
76
+ }
77
+ /** Result from context_enrich handlers */
78
+ export interface ContextEnrichResult {
79
+ /** Sections to include in the formatted context */
80
+ sections?: Section[];
81
+ /** System prompt override (for Pi-like adapters that support it) */
82
+ systemPrompt?: string;
83
+ }
84
+ /** Aggregated result from fireCollectSections */
85
+ export interface CollectedSections {
86
+ sections: Section[];
87
+ systemPrompt: string;
88
+ }
89
+ /** Event for model routing */
90
+ export interface RouteEvent {
91
+ /** Matched labels for this turn */
92
+ labels: Label[];
93
+ }
94
+ /** Result from route handlers — alias for RoutingResult from types.ts */
95
+ export type RouteResult = RoutingResult;
96
+ /** Event for input interception (Pi adapter) */
97
+ export interface InputEvent {
98
+ /** Raw user input */
99
+ input: string;
100
+ }
101
+ /** Result from input handlers */
102
+ export interface InputResult {
103
+ /** Transformed input (if modified) */
104
+ input?: string;
105
+ /** If true, input was consumed and should not be forwarded */
106
+ consumed?: boolean;
107
+ }
108
+ /** A parameter for a command definition */
109
+ export interface CommandParameter {
110
+ /** Parameter name */
111
+ name: string;
112
+ /** Human-readable description */
113
+ description: string;
114
+ /** Whether this parameter is required */
115
+ required?: boolean;
116
+ }
117
+ /** Result returned by command execution */
118
+ export interface CommandResult {
119
+ /** Output text to display */
120
+ output?: string;
121
+ }
122
+ /**
123
+ * A command definition -- aligned with Pi's /command pattern.
124
+ * Extensions register commands via `exports.commands`.
125
+ */
126
+ export interface CommandDefinition {
127
+ /** Command name (without leading slash) */
128
+ name: string;
129
+ /** Human-readable description */
130
+ description: string;
131
+ /** Parameter definitions */
132
+ parameters?: CommandParameter[];
133
+ /** Execute the command */
134
+ execute(args: Record<string, string>, ctx: ExtensionContext): Promise<CommandResult | void>;
135
+ /** Tab-completion provider */
136
+ completions?(prefix: string): string[] | Promise<string[]>;
137
+ }
138
+ /** Tool definition for extensions -- structurally compatible with Pi */
139
+ export interface ToolDefinition {
140
+ name: string;
141
+ description: string;
142
+ /** JSON Schema object describing tool parameters */
143
+ parameters: Record<string, unknown>;
144
+ /** Execute the tool. ctx is optional for backward compatibility with v5 extensions. */
145
+ execute(input: Record<string, unknown>, ctx?: ExtensionContext): Promise<{
146
+ content: string;
147
+ details?: unknown;
148
+ isError?: boolean;
149
+ }>;
150
+ /** Injected into system prompt when tool is active */
151
+ promptSnippet?: string;
152
+ /** Guidelines for the LLM when using this tool */
153
+ promptGuidelines?: string;
154
+ }
155
+ /**
156
+ * @deprecated Use ContextEnrichEvent + ContextEnrichResult instead.
157
+ * Tier 1 (universal) -- context injection event.
158
+ */
159
+ export interface ContextInjectEvent {
160
+ prompt: string;
161
+ labels: Label[];
162
+ usage?: {
163
+ inputTokens: number;
164
+ contextWindow: number;
165
+ };
166
+ }
167
+ /**
168
+ * @deprecated Use ContextEnrichResult instead.
169
+ */
170
+ export interface ContextInjectResult {
171
+ inject?: string;
172
+ }
173
+ /**
174
+ * @deprecated Use ContextEnrichEvent with context_modify support.
175
+ * Tier 2 (rich agents only) -- message-level context modification.
176
+ */
177
+ export interface ContextModifyEvent {
178
+ messages: Message[];
179
+ usage?: {
180
+ inputTokens: number;
181
+ contextWindow: number;
182
+ };
183
+ }
184
+ /**
185
+ * @deprecated Use ContextEnrichResult instead.
186
+ */
187
+ export interface ContextModifyResult {
188
+ messages?: Message[];
189
+ inject?: string;
190
+ }
191
+ /** Message type for context_modify */
192
+ export interface Message {
193
+ role: 'user' | 'assistant' | 'system';
194
+ content: string;
195
+ }
196
+ /** Tool call event -- fired before tool execution */
197
+ export interface ToolCallEvent {
198
+ tool: string;
199
+ input: Record<string, unknown>;
200
+ }
201
+ export interface ToolCallResult {
202
+ decision?: 'allow' | 'block';
203
+ reason?: string;
204
+ }
205
+ /** Tool result event -- fired after tool execution */
206
+ export interface ToolResultEvent {
207
+ tool: string;
208
+ result: {
209
+ content: string;
210
+ };
211
+ isError: boolean;
212
+ }
213
+ /** Agent end event */
214
+ export interface AgentEndEvent {
215
+ response: string;
216
+ }
217
+ /** Union of all extension events (v5 legacy + v6) */
218
+ export type ExtensionEvent = {
219
+ type: 'resources_discover';
220
+ } | {
221
+ type: 'label_extract';
222
+ data: LabelExtractEvent;
223
+ } | {
224
+ type: 'context_enrich';
225
+ data: ContextEnrichEvent;
226
+ } | {
227
+ type: 'route';
228
+ data: RouteEvent;
229
+ } | {
230
+ type: 'input';
231
+ data: InputEvent;
232
+ } | {
233
+ type: 'context_modify';
234
+ data: ContextModifyEvent;
235
+ } | {
236
+ type: 'tool_call';
237
+ data: ToolCallEvent;
238
+ } | {
239
+ type: 'tool_result';
240
+ data: ToolResultEvent;
241
+ } | {
242
+ type: 'agent_start';
243
+ } | {
244
+ type: 'agent_end';
245
+ data: AgentEndEvent;
246
+ } | {
247
+ type: 'session_start';
248
+ } | {
249
+ type: 'session_end';
250
+ } | {
251
+ type: 'turn_start';
252
+ } | {
253
+ type: 'turn_end';
254
+ } | {
255
+ type: 'message_start';
256
+ } | {
257
+ type: 'message_update';
258
+ } | {
259
+ type: 'message_end';
260
+ } | {
261
+ type: 'model_select';
262
+ } | {
263
+ type: 'user_bash';
264
+ } | {
265
+ type: 'session_before_switch';
266
+ } | {
267
+ type: 'session_switch';
268
+ } | {
269
+ type: 'session_before_compact';
270
+ } | {
271
+ type: 'session_compact';
272
+ } | {
273
+ type: 'context_inject';
274
+ data: ContextInjectEvent;
275
+ };
276
+ /** Extension tier metadata */
277
+ export type ExtensionTier = 'universal' | 'rich';
278
+ /** Event name to tier mapping */
279
+ export declare const EVENT_TIERS: Record<string, ExtensionTier>;
280
+ /** All valid event names */
281
+ export type ExtensionEventName = keyof typeof EVENT_TIERS;
282
+ /** A loaded extension with its handlers, tools, and commands */
283
+ export interface LoadedExtension {
284
+ path: string;
285
+ handlers: Map<string, Function[]>;
286
+ tools: Map<string, ToolDefinition>;
287
+ /** Registered commands (v6) */
288
+ commands: Map<string, CommandDefinition>;
289
+ tiers: Set<ExtensionTier>;
290
+ }
291
+ /**
292
+ * Adapter capability matrix -- which events each adapter supports.
293
+ * v6 events listed first; legacy events marked with comments.
294
+ */
295
+ export declare const ADAPTER_CAPABILITIES: Record<string, Set<string>>;
296
+ /**
297
+ * Tool integration strategy per adapter.
298
+ * - 'native': adapter can register tools natively (Pi, OpenClaw)
299
+ * - 'cli': tools are exposed as CLI commands (Claude Code)
300
+ * - 'text': tools are described in the system prompt only (Cursor, Copilot)
301
+ */
302
+ export declare const TOOL_STRATEGY: Record<string, 'native' | 'cli' | 'text'>;
303
+ /** Extension diagnostics */
304
+ export interface ExtensionDiagnostic {
305
+ path: string;
306
+ handlerCounts: Record<string, number>;
307
+ toolNames: string[];
308
+ /** Command names registered by this extension */
309
+ commandNames: string[];
310
+ tiers: ExtensionTier[];
311
+ }
312
+ //# sourceMappingURL=extension-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-types.d.ts","sourceRoot":"","sources":["../src/extension-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /** Event name to tier mapping */
2
+ export const EVENT_TIERS = {
3
+ // v6 events (all universal)
4
+ resources_discover: 'universal',
5
+ label_extract: 'universal',
6
+ context_enrich: 'universal',
7
+ route: 'universal',
8
+ input: 'universal',
9
+ // Shared events
10
+ context_modify: 'rich',
11
+ tool_call: 'universal',
12
+ tool_result: 'rich',
13
+ agent_start: 'rich',
14
+ agent_end: 'universal',
15
+ session_start: 'universal',
16
+ session_end: 'universal',
17
+ turn_start: 'rich',
18
+ turn_end: 'rich',
19
+ message_start: 'rich',
20
+ message_update: 'rich',
21
+ message_end: 'rich',
22
+ model_select: 'rich',
23
+ user_bash: 'rich',
24
+ session_before_switch: 'rich',
25
+ session_switch: 'rich',
26
+ session_before_compact: 'rich',
27
+ session_compact: 'rich',
28
+ // v5 legacy (deprecated)
29
+ context_inject: 'universal',
30
+ };
31
+ /**
32
+ * Adapter capability matrix -- which events each adapter supports.
33
+ * v6 events listed first; legacy events marked with comments.
34
+ */
35
+ export const ADAPTER_CAPABILITIES = {
36
+ pi: new Set([
37
+ 'session_start', 'session_end',
38
+ 'resources_discover',
39
+ 'label_extract', 'context_enrich', 'context_modify', 'route',
40
+ 'input',
41
+ 'tool_call', 'tool_result',
42
+ 'agent_start', 'agent_end',
43
+ 'turn_start', 'turn_end',
44
+ 'message_start', 'message_update', 'message_end',
45
+ 'session_before_switch', 'session_switch',
46
+ 'session_before_compact', 'session_compact',
47
+ 'model_select', 'user_bash',
48
+ // Legacy (deprecated)
49
+ 'context_inject',
50
+ ]),
51
+ 'claude-code': new Set([
52
+ 'session_start', 'session_end',
53
+ 'resources_discover',
54
+ 'label_extract', 'context_enrich', 'route',
55
+ 'tool_call', 'tool_result',
56
+ 'agent_end',
57
+ // Legacy (deprecated)
58
+ 'context_inject',
59
+ ]),
60
+ openclaw: new Set([
61
+ 'session_start', 'session_end',
62
+ 'resources_discover',
63
+ 'label_extract', 'context_enrich', 'route',
64
+ 'agent_end',
65
+ // Legacy (deprecated)
66
+ 'context_inject',
67
+ ]),
68
+ sync: new Set([
69
+ 'resources_discover',
70
+ 'context_enrich', 'route',
71
+ // Legacy (deprecated)
72
+ 'context_inject',
73
+ ]),
74
+ };
75
+ /**
76
+ * Tool integration strategy per adapter.
77
+ * - 'native': adapter can register tools natively (Pi, OpenClaw)
78
+ * - 'cli': tools are exposed as CLI commands (Claude Code)
79
+ * - 'text': tools are described in the system prompt only (Cursor, Copilot)
80
+ */
81
+ export const TOOL_STRATEGY = {
82
+ pi: 'native',
83
+ openclaw: 'native',
84
+ 'claude-code': 'cli',
85
+ sync: 'text',
86
+ cursor: 'text',
87
+ copilot: 'text',
88
+ };
89
+ //# sourceMappingURL=extension-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-types.js","sourceRoot":"","sources":["../src/extension-types.ts"],"names":[],"mappings":"AAuSA,iCAAiC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAkC;IACxD,4BAA4B;IAC5B,kBAAkB,EAAE,WAAW;IAC/B,aAAa,EAAE,WAAW;IAC1B,cAAc,EAAE,WAAW;IAC3B,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,WAAW;IAClB,gBAAgB;IAChB,cAAc,EAAE,MAAM;IACtB,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,MAAM;IACnB,SAAS,EAAE,WAAW;IACtB,aAAa,EAAE,WAAW;IAC1B,WAAW,EAAE,WAAW;IACxB,UAAU,EAAE,MAAM;IAClB,QAAQ,EAAE,MAAM;IAChB,aAAa,EAAE,MAAM;IACrB,cAAc,EAAE,MAAM;IACtB,WAAW,EAAE,MAAM;IACnB,YAAY,EAAE,MAAM;IACpB,SAAS,EAAE,MAAM;IACjB,qBAAqB,EAAE,MAAM;IAC7B,cAAc,EAAE,MAAM;IACtB,sBAAsB,EAAE,MAAM;IAC9B,eAAe,EAAE,MAAM;IACvB,yBAAyB;IACzB,cAAc,EAAE,WAAW;CAC5B,CAAC;AAmBF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAgC;IAC/D,EAAE,EAAE,IAAI,GAAG,CAAC;QACV,eAAe,EAAE,aAAa;QAC9B,oBAAoB;QACpB,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO;QAC5D,OAAO;QACP,WAAW,EAAE,aAAa;QAC1B,aAAa,EAAE,WAAW;QAC1B,YAAY,EAAE,UAAU;QACxB,eAAe,EAAE,gBAAgB,EAAE,aAAa;QAChD,uBAAuB,EAAE,gBAAgB;QACzC,wBAAwB,EAAE,iBAAiB;QAC3C,cAAc,EAAE,WAAW;QAC3B,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;IACF,aAAa,EAAE,IAAI,GAAG,CAAC;QACrB,eAAe,EAAE,aAAa;QAC9B,oBAAoB;QACpB,eAAe,EAAE,gBAAgB,EAAE,OAAO;QAC1C,WAAW,EAAE,aAAa;QAC1B,WAAW;QACX,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;IACF,QAAQ,EAAE,IAAI,GAAG,CAAC;QAChB,eAAe,EAAE,aAAa;QAC9B,oBAAoB;QACpB,eAAe,EAAE,gBAAgB,EAAE,OAAO;QAC1C,WAAW;QACX,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;IACF,IAAI,EAAE,IAAI,GAAG,CAAC;QACZ,oBAAoB;QACpB,gBAAgB,EAAE,OAAO;QACzB,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAA8C;IACtE,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,QAAQ;IAClB,aAAa,EAAE,KAAK;IACpB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,MAAM;CAChB,CAAC"}
package/dist/format.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { EnrichedContext } from './types.js';
1
+ import type { EnrichedContext, BudgetWarning } from './types.js';
2
2
  import type { Logger } from './logger.js';
3
+ import type { Capability } from './capabilities.js';
3
4
  export interface FormatOptions {
4
5
  /** Skip identity sections (useful when already injected at session start) */
5
6
  skipIdentities?: boolean;
@@ -7,12 +8,23 @@ export interface FormatOptions {
7
8
  maxSkillLength?: number;
8
9
  /** Max number of skills to include (already sorted by match relevance). Default: unlimited */
9
10
  maxSkills?: number;
11
+ /** Max estimated tokens (chars / 4). When exceeded, content is trimmed. Default: no limit */
12
+ tokenBudget?: number;
13
+ /** Called when budget was exceeded and trimming occurred. Diagnostic signal. */
14
+ onBudgetExceeded?: (warning: BudgetWarning) => void;
10
15
  /** Optional logger for tracing */
11
16
  logger?: Logger;
17
+ /** Skill disclosure mode. 'progressive' shows name+description only, 'full' shows entire content */
18
+ skillDisclosure?: 'full' | 'progressive';
12
19
  }
13
20
  /**
14
21
  * Format an EnrichedContext into markdown sections for injection into agent context.
15
22
  * Sections are ordered by priority: identity > memory > skills > tools > routing.
16
23
  */
17
24
  export declare function formatContext(ctx: EnrichedContext, options?: FormatOptions): string;
25
+ /**
26
+ * Format tool hints from capabilities that have promptSnippet or promptGuidelines.
27
+ * Returns empty string if no capabilities have hints.
28
+ */
29
+ export declare function formatToolHints(capabilities: Capability[]): string;
18
30
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA2C,MAAM,YAAY,CAAC;AAC3F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oGAAoG;IACpG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAyDnF"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAiD,aAAa,EAAE,MAAM,YAAY,CAAC;AAChH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oGAAoG;IACpG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CA6InF;AAkDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,MAAM,CAYlE"}
package/dist/format.js CHANGED
@@ -5,35 +5,117 @@
5
5
  export function formatContext(ctx, options) {
6
6
  const start = performance.now();
7
7
  const sections = [];
8
- // Identity sections (sorted by priority, highest first)
8
+ // Identity sections (sorted by priority DESC, then by type alphabetically for stability)
9
9
  if (!options?.skipIdentities) {
10
- const sortedIdentities = [...ctx.identities].sort((a, b) => b.priority - a.priority);
10
+ const sortedIdentities = [...ctx.identities].sort((a, b) => {
11
+ if (b.priority !== a.priority)
12
+ return b.priority - a.priority;
13
+ return a.type.localeCompare(b.type);
14
+ });
11
15
  for (const identity of sortedIdentities) {
12
16
  if (identity.content) {
13
17
  sections.push(identity.content);
14
18
  }
15
19
  }
16
20
  }
17
- // Memory section
18
- if (ctx.memories.length > 0) {
19
- sections.push(formatMemory(ctx.memories));
21
+ // Memory section (sorted by date DESC for stability)
22
+ const sortedMemories = [...ctx.memories].sort((a, b) => {
23
+ if (!a.date && !b.date)
24
+ return 0;
25
+ if (!a.date)
26
+ return 1;
27
+ if (!b.date)
28
+ return -1;
29
+ return b.date.localeCompare(a.date);
30
+ });
31
+ if (sortedMemories.length > 0 || ctx.memoryDescription) {
32
+ sections.push(formatMemory(sortedMemories, ctx.memoryDescription));
33
+ }
34
+ // Recent tasks section
35
+ if (ctx.recentTasks && ctx.recentTasks.length > 0) {
36
+ sections.push(formatTasks(ctx.recentTasks));
20
37
  }
21
- // Skills section
22
- let loadedSkills = ctx.skills.filter(s => s.content);
38
+ // Skills section (sorted by name alphabetically for determinism)
39
+ let loadedSkills = [...ctx.skills].sort((a, b) => a.name.localeCompare(b.name)).filter(s => s.content);
23
40
  if (options?.maxSkills != null) {
24
41
  loadedSkills = loadedSkills.slice(0, options.maxSkills);
25
42
  }
26
43
  if (loadedSkills.length > 0) {
27
- sections.push(formatSkills(loadedSkills, options?.maxSkillLength));
44
+ sections.push(formatSkills(loadedSkills, options?.maxSkillLength, options?.skillDisclosure));
28
45
  }
29
- // Tools section
30
- if (ctx.tools.length > 0) {
31
- sections.push(formatTools(ctx.tools));
46
+ // Tools section (sorted by name alphabetically for determinism)
47
+ const sortedTools = [...ctx.tools].sort((a, b) => a.name.localeCompare(b.name));
48
+ if (sortedTools.length > 0) {
49
+ sections.push(formatTools(sortedTools));
32
50
  }
33
51
  // Routing hint
34
52
  if (ctx.routing.model !== 'default') {
35
53
  sections.push(formatRouting(ctx.routing));
36
54
  }
55
+ // Budget enforcement — trim if over token budget
56
+ if (options?.tokenBudget != null) {
57
+ const estimate = () => Math.round(sections.join('\n\n---\n\n').length / 4);
58
+ let current = estimate();
59
+ if (current > options.tokenBudget) {
60
+ const actions = [];
61
+ const skillSectionIdx = sections.findIndex(s => s.startsWith('## Active Skills'));
62
+ const memorySectionIdx = sections.findIndex(s => s.startsWith('## Relevant Memory'));
63
+ // Strategy 1: Truncate skill content to 2000 chars
64
+ if (current > options.tokenBudget && skillSectionIdx !== -1 && options?.maxSkillLength == null) {
65
+ const longSkills = loadedSkills.filter(s => (s.content?.length ?? 0) > 2000).length;
66
+ if (longSkills > 0) {
67
+ sections[skillSectionIdx] = formatSkills(loadedSkills, 2000, options?.skillDisclosure);
68
+ actions.push(`truncated ${longSkills} skills to 2000 chars`);
69
+ current = estimate();
70
+ }
71
+ }
72
+ // Strategy 2: Drop oldest memories (keep most recent 5)
73
+ if (current > options.tokenBudget && memorySectionIdx !== -1 && sortedMemories.length > 5) {
74
+ const kept = sortedMemories.slice(0, 5);
75
+ const dropped = sortedMemories.length - 5;
76
+ sections[memorySectionIdx] = formatMemory(kept, ctx.memoryDescription);
77
+ actions.push(`dropped ${dropped} oldest memories`);
78
+ current = estimate();
79
+ }
80
+ // Strategy 3: Drop skills by reverse order
81
+ if (current > options.tokenBudget && skillSectionIdx !== -1 && loadedSkills.length > 1) {
82
+ while (loadedSkills.length > 1 && current > options.tokenBudget) {
83
+ const dropped = loadedSkills.pop();
84
+ actions.push(`dropped skill: ${dropped.name}`);
85
+ sections[skillSectionIdx] = formatSkills(loadedSkills, options?.maxSkillLength ?? 2000, options?.skillDisclosure);
86
+ current = estimate();
87
+ }
88
+ }
89
+ if (actions.length > 0) {
90
+ const warning = { budget: options.tokenBudget, actual: current, actions };
91
+ options.onBudgetExceeded?.(warning);
92
+ options?.logger?.log({
93
+ timestamp: new Date().toISOString(),
94
+ level: current > options.tokenBudget ? 'warn' : 'info',
95
+ phase: 'format',
96
+ event: 'budget_trimmed',
97
+ data: warning,
98
+ durationMs: Math.round(performance.now() - start),
99
+ });
100
+ }
101
+ else if (current > options.tokenBudget) {
102
+ const warning = {
103
+ budget: options.tokenBudget,
104
+ actual: current,
105
+ actions: ['budget exceeded by non-trimmable content (identities)'],
106
+ };
107
+ options.onBudgetExceeded?.(warning);
108
+ options?.logger?.log({
109
+ timestamp: new Date().toISOString(),
110
+ level: 'warn',
111
+ phase: 'format',
112
+ event: 'budget_exceeded_no_action',
113
+ data: warning,
114
+ durationMs: Math.round(performance.now() - start),
115
+ });
116
+ }
117
+ }
118
+ }
37
119
  const result = sections.join('\n\n---\n\n');
38
120
  options?.logger?.log({
39
121
  timestamp: new Date().toISOString(),
@@ -52,19 +134,34 @@ export function formatContext(ctx, options) {
52
134
  });
53
135
  return result;
54
136
  }
55
- function formatMemory(memories) {
137
+ function formatMemory(memories, description) {
56
138
  const lines = ['## Relevant Memory\n'];
57
- for (const m of memories.slice(0, 10)) { // Limit to 10 most relevant
139
+ if (description) {
140
+ lines.push(`> ${description}\n`);
141
+ }
142
+ for (const m of memories.slice(0, 10)) {
58
143
  const date = m.date ? ` (${m.date})` : '';
59
144
  lines.push(`- ${m.content}${date}`);
60
145
  }
61
146
  return lines.join('\n');
62
147
  }
63
- function formatSkills(skills, maxLength) {
148
+ function formatTasks(tasks) {
149
+ const lines = ['## Current Tasks (In Progress)\n'];
150
+ for (const t of tasks.slice(0, 10)) {
151
+ const project = t.project ? ` [${t.project}]` : '';
152
+ const priority = t.priority ? ` (${t.priority})` : '';
153
+ lines.push(`- ${t.text}${project}${priority}`);
154
+ }
155
+ return lines.join('\n');
156
+ }
157
+ function formatSkills(skills, maxLength, disclosure) {
64
158
  const lines = ['## Active Skills\n'];
65
159
  for (const s of skills) {
66
160
  lines.push(`### ${s.name}`);
67
- if (s.content) {
161
+ if (disclosure === 'progressive') {
162
+ lines.push(s.description);
163
+ }
164
+ else if (s.content) {
68
165
  if (maxLength != null && s.content.length > maxLength) {
69
166
  lines.push(s.content.slice(0, maxLength) + '\n\n[...truncated]');
70
167
  }
@@ -83,6 +180,25 @@ function formatTools(tools) {
83
180
  }
84
181
  return lines.join('\n');
85
182
  }
183
+ /**
184
+ * Format tool hints from capabilities that have promptSnippet or promptGuidelines.
185
+ * Returns empty string if no capabilities have hints.
186
+ */
187
+ export function formatToolHints(capabilities) {
188
+ const withHints = capabilities.filter(c => c.promptSnippet || c.promptGuidelines);
189
+ if (withHints.length === 0)
190
+ return '';
191
+ const lines = ['## Tool Hints\n'];
192
+ for (const cap of withHints) {
193
+ lines.push(`### ${cap.name}`);
194
+ if (cap.promptSnippet)
195
+ lines.push(cap.promptSnippet);
196
+ if (cap.promptGuidelines)
197
+ lines.push(`\n> ${cap.promptGuidelines}`);
198
+ lines.push('');
199
+ }
200
+ return lines.join('\n');
201
+ }
86
202
  function formatRouting(routing) {
87
203
  return `## Model Routing\n\nRecommended model: **${routing.model}** (${routing.reason})`;
88
204
  }