jeopi-agent-core 16.2.13

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 (66) hide show
  1. package/CHANGELOG.md +1016 -0
  2. package/README.md +473 -0
  3. package/dist/types/agent-loop.d.ts +66 -0
  4. package/dist/types/agent.d.ts +427 -0
  5. package/dist/types/append-only-context.d.ts +133 -0
  6. package/dist/types/compaction/branch-summarization.d.ts +101 -0
  7. package/dist/types/compaction/compaction-v2-streaming.d.ts +82 -0
  8. package/dist/types/compaction/compaction.d.ts +283 -0
  9. package/dist/types/compaction/entries.d.ts +110 -0
  10. package/dist/types/compaction/errors.d.ts +26 -0
  11. package/dist/types/compaction/index.d.ts +12 -0
  12. package/dist/types/compaction/messages.d.ts +77 -0
  13. package/dist/types/compaction/openai.d.ts +77 -0
  14. package/dist/types/compaction/pruning.d.ts +105 -0
  15. package/dist/types/compaction/shake.d.ts +92 -0
  16. package/dist/types/compaction/tool-protection.d.ts +17 -0
  17. package/dist/types/compaction/utils.d.ts +58 -0
  18. package/dist/types/compaction.d.ts +1 -0
  19. package/dist/types/index.d.ts +12 -0
  20. package/dist/types/proxy.d.ts +85 -0
  21. package/dist/types/replay-policy.d.ts +5 -0
  22. package/dist/types/run-collector.d.ts +196 -0
  23. package/dist/types/telemetry.d.ts +590 -0
  24. package/dist/types/thinking.d.ts +17 -0
  25. package/dist/types/tokenizer.d.ts +1 -0
  26. package/dist/types/types.d.ts +640 -0
  27. package/dist/types/utils/yield.d.ts +71 -0
  28. package/package.json +78 -0
  29. package/src/agent-loop.ts +2188 -0
  30. package/src/agent.ts +1457 -0
  31. package/src/append-only-context.ts +348 -0
  32. package/src/compaction/branch-summarization.ts +370 -0
  33. package/src/compaction/compaction-v2-streaming.ts +719 -0
  34. package/src/compaction/compaction.ts +1553 -0
  35. package/src/compaction/entries.ts +142 -0
  36. package/src/compaction/errors.ts +31 -0
  37. package/src/compaction/index.ts +13 -0
  38. package/src/compaction/messages.ts +237 -0
  39. package/src/compaction/openai.ts +581 -0
  40. package/src/compaction/prompts/auto-handoff-threshold-focus.md +1 -0
  41. package/src/compaction/prompts/branch-summary-context.md +5 -0
  42. package/src/compaction/prompts/branch-summary-preamble.md +2 -0
  43. package/src/compaction/prompts/branch-summary.md +30 -0
  44. package/src/compaction/prompts/compaction-short-summary.md +9 -0
  45. package/src/compaction/prompts/compaction-summary-context.md +5 -0
  46. package/src/compaction/prompts/compaction-summary.md +38 -0
  47. package/src/compaction/prompts/compaction-turn-prefix.md +17 -0
  48. package/src/compaction/prompts/compaction-update-summary.md +45 -0
  49. package/src/compaction/prompts/file-operations.md +5 -0
  50. package/src/compaction/prompts/handoff-document.md +49 -0
  51. package/src/compaction/prompts/snapcompact-archive-context.md +3 -0
  52. package/src/compaction/prompts/summarization-system.md +3 -0
  53. package/src/compaction/pruning.ts +424 -0
  54. package/src/compaction/shake.ts +429 -0
  55. package/src/compaction/tool-protection.ts +55 -0
  56. package/src/compaction/utils.ts +323 -0
  57. package/src/compaction.ts +1 -0
  58. package/src/index.ts +24 -0
  59. package/src/proxy.ts +376 -0
  60. package/src/replay-policy.ts +13 -0
  61. package/src/run-collector.ts +631 -0
  62. package/src/telemetry.ts +2034 -0
  63. package/src/thinking.ts +19 -0
  64. package/src/tokenizer.ts +17 -0
  65. package/src/types.ts +718 -0
  66. package/src/utils/yield.ts +183 -0
@@ -0,0 +1,142 @@
1
+ import type { ImageContent, MessageAttribution, ServiceTierByFamily, TextContent } from "jeopi-ai";
2
+ import type { AgentMessage } from "../types";
3
+
4
+ export interface SessionEntryBase {
5
+ type: string;
6
+ id: string;
7
+ parentId: string | null;
8
+ timestamp: string;
9
+ }
10
+
11
+ export interface SessionMessageEntry extends SessionEntryBase {
12
+ type: "message";
13
+ message: AgentMessage;
14
+ }
15
+
16
+ export interface ThinkingLevelChangeEntry extends SessionEntryBase {
17
+ type: "thinking_level_change";
18
+ thinkingLevel?: string | null;
19
+ }
20
+
21
+ export interface ModelChangeEntry extends SessionEntryBase {
22
+ type: "model_change";
23
+ /** Model in "provider/modelId" format */
24
+ model: string;
25
+ /** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
26
+ role?: string;
27
+ }
28
+
29
+ export interface ServiceTierChangeEntry extends SessionEntryBase {
30
+ type: "service_tier_change";
31
+ serviceTier: ServiceTierByFamily | null;
32
+ }
33
+
34
+ export interface CompactionEntry<T = unknown> extends SessionEntryBase {
35
+ type: "compaction";
36
+ summary: string;
37
+ shortSummary?: string;
38
+ firstKeptEntryId: string;
39
+ tokensBefore: number;
40
+ /** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
41
+ details?: T;
42
+ /** Hook-provided data to persist across compaction */
43
+ preserveData?: Record<string, unknown>;
44
+ /** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
45
+ fromExtension?: boolean;
46
+ }
47
+
48
+ export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
49
+ type: "branch_summary";
50
+ fromId: string;
51
+ summary: string;
52
+ /** Extension-specific data (not sent to LLM) */
53
+ details?: T;
54
+ /** True if generated by an extension, false if pi-generated */
55
+ fromExtension?: boolean;
56
+ }
57
+
58
+ export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
59
+ type: "custom_message";
60
+ customType: string;
61
+ content: string | (TextContent | ImageContent)[];
62
+ details?: T;
63
+ display: boolean;
64
+ /** Who initiated this message for billing/attribution semantics. */
65
+ attribution?: MessageAttribution;
66
+ }
67
+
68
+ export interface CustomEntry<T = unknown> extends SessionEntryBase {
69
+ type: "custom";
70
+ customType: string;
71
+ data?: T;
72
+ }
73
+
74
+ export interface LabelEntry extends SessionEntryBase {
75
+ type: "label";
76
+ targetId: string;
77
+ label: string | undefined;
78
+ }
79
+
80
+ export interface TitleChangeEntry extends SessionEntryBase {
81
+ type: "title_change";
82
+ title: string;
83
+ previousTitle?: string;
84
+ source: "auto" | "user";
85
+ trigger?: string;
86
+ }
87
+
88
+ export interface TtsrInjectionEntry extends SessionEntryBase {
89
+ type: "ttsr_injection";
90
+ /** Names of rules that were injected */
91
+ injectedRules: string[];
92
+ }
93
+
94
+ export interface MCPToolSelectionEntry extends SessionEntryBase {
95
+ type: "mcp_tool_selection";
96
+ /** MCP tool names selected for visibility in discovery mode. */
97
+ selectedToolNames: string[];
98
+ }
99
+
100
+ export interface SessionInitEntry extends SessionEntryBase {
101
+ type: "session_init";
102
+ /** Full system prompt sent to the model */
103
+ systemPrompt: string;
104
+ /** Initial task/user message */
105
+ task: string;
106
+ /** Tools available to the agent */
107
+ tools: string[];
108
+ /** Output schema if structured output was requested */
109
+ outputSchema?: unknown;
110
+ }
111
+
112
+ export interface ModeChangeEntry extends SessionEntryBase {
113
+ type: "mode_change";
114
+ /** Current mode name, or "none" when exiting a mode */
115
+ mode: string;
116
+ /** Optional mode-specific data (e.g. plan file path) */
117
+ data?: Record<string, unknown>;
118
+ }
119
+
120
+ export interface CustomCompactionSessionEntries {}
121
+
122
+ export type SessionEntry =
123
+ | SessionMessageEntry
124
+ | ThinkingLevelChangeEntry
125
+ | ModelChangeEntry
126
+ | ServiceTierChangeEntry
127
+ | CompactionEntry
128
+ | BranchSummaryEntry
129
+ | CustomEntry
130
+ | CustomMessageEntry
131
+ | LabelEntry
132
+ | TitleChangeEntry
133
+ | TtsrInjectionEntry
134
+ | MCPToolSelectionEntry
135
+ | SessionInitEntry
136
+ | ModeChangeEntry
137
+ | CustomCompactionSessionEntries[keyof CustomCompactionSessionEntries];
138
+
139
+ export interface ReadonlySessionManager {
140
+ getBranch(leafId?: string | null): SessionEntry[];
141
+ getEntry(id: string): SessionEntry | undefined;
142
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Compaction error types.
3
+ *
4
+ * `CompactionCancelledError` is the canonical signal raised when a compaction
5
+ * is explicitly aborted — operator Esc, extension hook returning `cancel`,
6
+ * programmatic `session.abortCompaction()` call, or any other deliberate
7
+ * abort source. Downstream callers (e.g. `executeCompaction`) discriminate
8
+ * cancellation from other failures via `instanceof CompactionCancelledError`
9
+ * rather than introspecting error messages or `name` fields — the typed
10
+ * sentinel makes classification source-agnostic and refactor-stable.
11
+ */
12
+
13
+ export class CompactionCancelledError extends Error {
14
+ readonly name = "CompactionCancelledError" as const;
15
+
16
+ constructor(message = "Compaction cancelled") {
17
+ super(message);
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Outcome of a compaction attempt, surfaced by `CommandController.executeCompaction`
23
+ * so callers (e.g. the plan-mode approval flow) can distinguish a deliberate abort
24
+ * from an unrelated failure.
25
+ *
26
+ * "ok" — compaction completed; transcript was summarized.
27
+ * "cancelled" — `CompactionCancelledError` was raised. Operator Esc, extension
28
+ * hook, programmatic abort — all source-agnostic.
29
+ * "failed" — any other rejection from `session.compact()`.
30
+ */
31
+ export type CompactionOutcome = "ok" | "cancelled" | "failed";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Compaction and summarization utilities.
3
+ */
4
+
5
+ export * from "./branch-summarization";
6
+ export * from "./compaction";
7
+ export * from "./entries";
8
+ export * from "./errors";
9
+ export * from "./messages";
10
+ export * from "./openai";
11
+ export * from "./pruning";
12
+ export * from "./shake";
13
+ export * from "./utils";
@@ -0,0 +1,237 @@
1
+ import type {
2
+ ImageContent,
3
+ Message,
4
+ MessageAttribution,
5
+ ProviderPayload,
6
+ TextContent,
7
+ ToolResultMessage,
8
+ } from "jeopi-ai";
9
+ import { prompt } from "jeopi-utils";
10
+ import type { AgentMessage } from "../types";
11
+ import branchSummaryContextPrompt from "./prompts/branch-summary-context.md" with { type: "text" };
12
+ import compactionSummaryContextPrompt from "./prompts/compaction-summary-context.md" with { type: "text" };
13
+
14
+ const COMPACTION_SUMMARY_TEMPLATE = compactionSummaryContextPrompt;
15
+ const BRANCH_SUMMARY_TEMPLATE = branchSummaryContextPrompt;
16
+
17
+ export interface CustomMessage<T = unknown> {
18
+ role: "custom";
19
+ customType: string;
20
+ content: string | (TextContent | ImageContent)[];
21
+ display: boolean;
22
+ details?: T;
23
+ /** Who initiated this message for billing/attribution semantics. */
24
+ attribution?: MessageAttribution;
25
+ timestamp: number;
26
+ }
27
+
28
+ /** Legacy hook message type (pre-extensions). Kept for session migration. */
29
+ export interface HookMessage<T = unknown> {
30
+ role: "hookMessage";
31
+ customType: string;
32
+ content: string | (TextContent | ImageContent)[];
33
+ display: boolean;
34
+ details?: T;
35
+ /** Who initiated this message for billing/attribution semantics. */
36
+ attribution?: MessageAttribution;
37
+ timestamp: number;
38
+ }
39
+
40
+ export interface BranchSummaryMessage {
41
+ role: "branchSummary";
42
+ summary: string;
43
+ fromId: string;
44
+ timestamp: number;
45
+ }
46
+
47
+ export interface CompactionSummaryMessage {
48
+ role: "compactionSummary";
49
+ summary: string;
50
+ shortSummary?: string;
51
+ tokensBefore: number;
52
+ providerPayload?: ProviderPayload;
53
+ /** Runtime-only ordered archive blocks for snapcompact: old text region,
54
+ * imaged middle, then new text region. When present, `summary` is already
55
+ * the final lead-in text (no legacy wrapper applied). */
56
+ blocks?: (TextContent | ImageContent)[];
57
+ /** Snapcompact image blocks, kept for display counts / legacy consumers. */
58
+ images?: ImageContent[];
59
+ timestamp: number;
60
+ }
61
+
62
+ export type CoreCompactionMessage = CustomMessage | HookMessage | BranchSummaryMessage | CompactionSummaryMessage;
63
+
64
+ declare module "../types" {
65
+ interface CustomAgentMessages {
66
+ custom: CustomMessage;
67
+ hookMessage: HookMessage;
68
+ branchSummary: BranchSummaryMessage;
69
+ compactionSummary: CompactionSummaryMessage;
70
+ }
71
+ }
72
+ export type ConvertToLlm = (messages: AgentMessage[]) => Message[];
73
+
74
+ function getPrunedToolResultContent(message: ToolResultMessage): (TextContent | ImageContent)[] {
75
+ if (message.prunedAt === undefined) {
76
+ return message.content;
77
+ }
78
+ const textBlocks = message.content.filter((content): content is TextContent => content.type === "text");
79
+ const text = textBlocks.map(block => block.text).join("") || "[Output truncated]";
80
+ return [{ type: "text", text }];
81
+ }
82
+
83
+ export function renderBranchSummaryContext(summary: string): string {
84
+ return prompt.render(BRANCH_SUMMARY_TEMPLATE, { summary });
85
+ }
86
+
87
+ export function renderCompactionSummaryContext(summary: string): string {
88
+ return prompt.render(COMPACTION_SUMMARY_TEMPLATE, { summary });
89
+ }
90
+
91
+ export function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {
92
+ return {
93
+ role: "branchSummary",
94
+ summary,
95
+ fromId,
96
+ timestamp: new Date(timestamp).getTime(),
97
+ };
98
+ }
99
+
100
+ export function createCompactionSummaryMessage(
101
+ summary: string,
102
+ tokensBefore: number,
103
+ timestamp: string,
104
+ shortSummary?: string,
105
+ providerPayload?: ProviderPayload,
106
+ images?: ImageContent[],
107
+ blocks?: (TextContent | ImageContent)[],
108
+ ): CompactionSummaryMessage {
109
+ const imageBlocks =
110
+ blocks?.filter((block): block is ImageContent => block.type === "image") ??
111
+ (images && images.length > 0 ? images : undefined);
112
+ return {
113
+ role: "compactionSummary",
114
+ summary,
115
+ shortSummary,
116
+ tokensBefore,
117
+ providerPayload,
118
+ blocks: blocks && blocks.length > 0 ? blocks : undefined,
119
+ images: imageBlocks && imageBlocks.length > 0 ? imageBlocks : undefined,
120
+ timestamp: new Date(timestamp).getTime(),
121
+ };
122
+ }
123
+
124
+ export function createCustomMessage(
125
+ customType: string,
126
+ content: string | (TextContent | ImageContent)[],
127
+ display: boolean,
128
+ details: unknown | undefined,
129
+ timestamp: string,
130
+ attribution?: MessageAttribution,
131
+ ): CustomMessage {
132
+ return {
133
+ role: "custom",
134
+ customType,
135
+ content,
136
+ display,
137
+ details,
138
+ attribution,
139
+ timestamp: new Date(timestamp).getTime(),
140
+ };
141
+ }
142
+
143
+ function isCoreCompactionMessage(message: AgentMessage): message is AgentMessage & CoreCompactionMessage {
144
+ return (
145
+ message.role === "custom" ||
146
+ message.role === "hookMessage" ||
147
+ message.role === "branchSummary" ||
148
+ message.role === "compactionSummary"
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Transform a single core-domain agent message to its LLM form; `undefined`
154
+ * drops it from the provider request.
155
+ *
156
+ * Single source of truth for the core roles (user/developer/assistant/
157
+ * toolResult) and the compaction messages owned by this package. Embedders
158
+ * with their own app messages (e.g. the coding agent) handle their custom
159
+ * roles and delegate every core role here — duplicating these cases is how
160
+ * snapcompact frames once silently fell off the provider request.
161
+ */
162
+ export function convertMessageToLlm(message: AgentMessage): Message | undefined {
163
+ if (isCoreCompactionMessage(message)) {
164
+ switch (message.role) {
165
+ case "custom":
166
+ case "hookMessage": {
167
+ const content =
168
+ typeof message.content === "string"
169
+ ? [{ type: "text" as const, text: message.content }]
170
+ : message.content;
171
+ return {
172
+ role: "developer",
173
+ content,
174
+ attribution: message.attribution,
175
+ timestamp: message.timestamp,
176
+ };
177
+ }
178
+ case "branchSummary":
179
+ return {
180
+ role: "user",
181
+ content: [
182
+ {
183
+ type: "text" as const,
184
+ text: renderBranchSummaryContext(message.summary),
185
+ },
186
+ ],
187
+ attribution: "agent",
188
+ timestamp: message.timestamp,
189
+ };
190
+ case "compactionSummary":
191
+ return {
192
+ role: "user",
193
+ content:
194
+ message.blocks !== undefined
195
+ ? [{ type: "text" as const, text: message.summary }, ...message.blocks]
196
+ : [
197
+ {
198
+ type: "text" as const,
199
+ text: renderCompactionSummaryContext(message.summary),
200
+ },
201
+ ...(message.images ?? []),
202
+ ],
203
+ attribution: "agent",
204
+ providerPayload: message.providerPayload,
205
+ timestamp: message.timestamp,
206
+ };
207
+ }
208
+ }
209
+
210
+ switch (message.role) {
211
+ case "user":
212
+ return { ...message, attribution: message.attribution ?? "user" };
213
+ case "developer":
214
+ return { ...message, attribution: message.attribution ?? "agent" };
215
+ case "assistant":
216
+ return message;
217
+ case "toolResult":
218
+ return {
219
+ ...message,
220
+ content: getPrunedToolResultContent(message as ToolResultMessage),
221
+ attribution: message.attribution ?? "agent",
222
+ };
223
+ default:
224
+ return undefined;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Default compaction-domain transformer.
230
+ *
231
+ * Embedders with their own app messages should pass a richer transformer through
232
+ * `SummaryOptions.convertToLlm`; this default intentionally preserves only the
233
+ * core LLM roles and the compaction messages owned by this package.
234
+ */
235
+ export function defaultConvertToLlm(messages: AgentMessage[]): Message[] {
236
+ return messages.map(convertMessageToLlm).filter(message => message !== undefined);
237
+ }