@gajae-code/agent-core 0.1.1

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 (55) hide show
  1. package/CHANGELOG.md +482 -0
  2. package/README.md +473 -0
  3. package/dist/types/agent-loop.d.ts +55 -0
  4. package/dist/types/agent.d.ts +334 -0
  5. package/dist/types/append-only-context.d.ts +113 -0
  6. package/dist/types/compaction/branch-summarization.d.ts +94 -0
  7. package/dist/types/compaction/compaction.d.ts +166 -0
  8. package/dist/types/compaction/entries.d.ts +103 -0
  9. package/dist/types/compaction/errors.d.ts +26 -0
  10. package/dist/types/compaction/index.d.ts +11 -0
  11. package/dist/types/compaction/messages.d.ts +61 -0
  12. package/dist/types/compaction/openai.d.ts +58 -0
  13. package/dist/types/compaction/pruning.d.ts +18 -0
  14. package/dist/types/compaction/utils.d.ts +32 -0
  15. package/dist/types/compaction.d.ts +1 -0
  16. package/dist/types/harmony-leak.d.ts +99 -0
  17. package/dist/types/index.d.ts +10 -0
  18. package/dist/types/proxy.d.ts +84 -0
  19. package/dist/types/run-collector.d.ts +196 -0
  20. package/dist/types/telemetry.d.ts +588 -0
  21. package/dist/types/thinking.d.ts +17 -0
  22. package/dist/types/types.d.ts +407 -0
  23. package/package.json +75 -0
  24. package/src/agent-loop.ts +1279 -0
  25. package/src/agent.ts +1399 -0
  26. package/src/append-only-context.ts +297 -0
  27. package/src/compaction/branch-summarization.ts +339 -0
  28. package/src/compaction/compaction.ts +1065 -0
  29. package/src/compaction/entries.ts +133 -0
  30. package/src/compaction/errors.ts +31 -0
  31. package/src/compaction/index.ts +12 -0
  32. package/src/compaction/messages.ts +212 -0
  33. package/src/compaction/openai.ts +552 -0
  34. package/src/compaction/prompts/auto-handoff-threshold-focus.md +1 -0
  35. package/src/compaction/prompts/branch-summary-context.md +5 -0
  36. package/src/compaction/prompts/branch-summary-preamble.md +2 -0
  37. package/src/compaction/prompts/branch-summary.md +30 -0
  38. package/src/compaction/prompts/compaction-short-summary.md +9 -0
  39. package/src/compaction/prompts/compaction-summary-context.md +5 -0
  40. package/src/compaction/prompts/compaction-summary.md +38 -0
  41. package/src/compaction/prompts/compaction-turn-prefix.md +17 -0
  42. package/src/compaction/prompts/compaction-update-summary.md +45 -0
  43. package/src/compaction/prompts/file-operations.md +10 -0
  44. package/src/compaction/prompts/handoff-document.md +49 -0
  45. package/src/compaction/prompts/summarization-system.md +3 -0
  46. package/src/compaction/pruning.ts +92 -0
  47. package/src/compaction/utils.ts +185 -0
  48. package/src/compaction.ts +1 -0
  49. package/src/harmony-leak.ts +427 -0
  50. package/src/index.ts +19 -0
  51. package/src/proxy.ts +326 -0
  52. package/src/run-collector.ts +631 -0
  53. package/src/telemetry.ts +2018 -0
  54. package/src/thinking.ts +19 -0
  55. package/src/types.ts +467 -0
@@ -0,0 +1,133 @@
1
+ import type { ImageContent, MessageAttribution, ServiceTier, TextContent } from "@gajae-code/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: ServiceTier | 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 TtsrInjectionEntry extends SessionEntryBase {
81
+ type: "ttsr_injection";
82
+ /** Names of rules that were injected */
83
+ injectedRules: string[];
84
+ }
85
+
86
+ export interface MCPToolSelectionEntry extends SessionEntryBase {
87
+ type: "mcp_tool_selection";
88
+ /** MCP tool names selected for visibility in discovery mode. */
89
+ selectedToolNames: string[];
90
+ }
91
+
92
+ export interface SessionInitEntry extends SessionEntryBase {
93
+ type: "session_init";
94
+ /** Full system prompt sent to the model */
95
+ systemPrompt: string;
96
+ /** Initial task/user message */
97
+ task: string;
98
+ /** Tools available to the agent */
99
+ tools: string[];
100
+ /** Output schema if structured output was requested */
101
+ outputSchema?: unknown;
102
+ }
103
+
104
+ export interface ModeChangeEntry extends SessionEntryBase {
105
+ type: "mode_change";
106
+ /** Current mode name, or "none" when exiting a mode */
107
+ mode: string;
108
+ /** Optional mode-specific data (e.g. plan file path) */
109
+ data?: Record<string, unknown>;
110
+ }
111
+
112
+ export interface CustomCompactionSessionEntries {}
113
+
114
+ export type SessionEntry =
115
+ | SessionMessageEntry
116
+ | ThinkingLevelChangeEntry
117
+ | ModelChangeEntry
118
+ | ServiceTierChangeEntry
119
+ | CompactionEntry
120
+ | BranchSummaryEntry
121
+ | CustomEntry
122
+ | CustomMessageEntry
123
+ | LabelEntry
124
+ | TtsrInjectionEntry
125
+ | MCPToolSelectionEntry
126
+ | SessionInitEntry
127
+ | ModeChangeEntry
128
+ | CustomCompactionSessionEntries[keyof CustomCompactionSessionEntries];
129
+
130
+ export interface ReadonlySessionManager {
131
+ getBranch(leafId?: string | null): SessionEntry[];
132
+ getEntry(id: string): SessionEntry | undefined;
133
+ }
@@ -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,12 @@
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 "./utils";
@@ -0,0 +1,212 @@
1
+ import type {
2
+ AssistantMessage,
3
+ ImageContent,
4
+ Message,
5
+ MessageAttribution,
6
+ ProviderPayload,
7
+ TextContent,
8
+ ToolResultMessage,
9
+ } from "@gajae-code/ai";
10
+ import { prompt } from "@gajae-code/utils";
11
+ import type { AgentMessage } from "../types";
12
+ import branchSummaryContextPrompt from "./prompts/branch-summary-context.md" with { type: "text" };
13
+ import compactionSummaryContextPrompt from "./prompts/compaction-summary-context.md" with { type: "text" };
14
+
15
+ const COMPACTION_SUMMARY_TEMPLATE = compactionSummaryContextPrompt;
16
+ const BRANCH_SUMMARY_TEMPLATE = branchSummaryContextPrompt;
17
+
18
+ export interface CustomMessage<T = unknown> {
19
+ role: "custom";
20
+ customType: string;
21
+ content: string | (TextContent | ImageContent)[];
22
+ display: boolean;
23
+ details?: T;
24
+ /** Who initiated this message for billing/attribution semantics. */
25
+ attribution?: MessageAttribution;
26
+ timestamp: number;
27
+ }
28
+
29
+ /** Legacy hook message type (pre-extensions). Kept for session migration. */
30
+ export interface HookMessage<T = unknown> {
31
+ role: "hookMessage";
32
+ customType: string;
33
+ content: string | (TextContent | ImageContent)[];
34
+ display: boolean;
35
+ details?: T;
36
+ /** Who initiated this message for billing/attribution semantics. */
37
+ attribution?: MessageAttribution;
38
+ timestamp: number;
39
+ }
40
+
41
+ export interface BranchSummaryMessage {
42
+ role: "branchSummary";
43
+ summary: string;
44
+ fromId: string;
45
+ timestamp: number;
46
+ }
47
+
48
+ export interface CompactionSummaryMessage {
49
+ role: "compactionSummary";
50
+ summary: string;
51
+ shortSummary?: string;
52
+ tokensBefore: number;
53
+ providerPayload?: ProviderPayload;
54
+ timestamp: number;
55
+ }
56
+
57
+ export type CoreCompactionMessage = CustomMessage | HookMessage | BranchSummaryMessage | CompactionSummaryMessage;
58
+
59
+ declare module "../types" {
60
+ interface CustomAgentMessages {
61
+ custom: CustomMessage;
62
+ hookMessage: HookMessage;
63
+ branchSummary: BranchSummaryMessage;
64
+ compactionSummary: CompactionSummaryMessage;
65
+ }
66
+ }
67
+ export type ConvertToLlm = (messages: AgentMessage[]) => Message[];
68
+
69
+ function getPrunedToolResultContent(message: ToolResultMessage): (TextContent | ImageContent)[] {
70
+ if (message.prunedAt === undefined) {
71
+ return message.content;
72
+ }
73
+ const textBlocks = message.content.filter((content): content is TextContent => content.type === "text");
74
+ const text = textBlocks.map(block => block.text).join("") || "[Output truncated]";
75
+ return [{ type: "text", text }];
76
+ }
77
+
78
+ export function renderBranchSummaryContext(summary: string): string {
79
+ return prompt.render(BRANCH_SUMMARY_TEMPLATE, { summary });
80
+ }
81
+
82
+ export function renderCompactionSummaryContext(summary: string): string {
83
+ return prompt.render(COMPACTION_SUMMARY_TEMPLATE, { summary });
84
+ }
85
+
86
+ export function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {
87
+ return {
88
+ role: "branchSummary",
89
+ summary,
90
+ fromId,
91
+ timestamp: new Date(timestamp).getTime(),
92
+ };
93
+ }
94
+
95
+ export function createCompactionSummaryMessage(
96
+ summary: string,
97
+ tokensBefore: number,
98
+ timestamp: string,
99
+ shortSummary?: string,
100
+ providerPayload?: ProviderPayload,
101
+ ): CompactionSummaryMessage {
102
+ return {
103
+ role: "compactionSummary",
104
+ summary,
105
+ shortSummary,
106
+ tokensBefore,
107
+ providerPayload,
108
+ timestamp: new Date(timestamp).getTime(),
109
+ };
110
+ }
111
+
112
+ export function createCustomMessage(
113
+ customType: string,
114
+ content: string | (TextContent | ImageContent)[],
115
+ display: boolean,
116
+ details: unknown | undefined,
117
+ timestamp: string,
118
+ attribution?: MessageAttribution,
119
+ ): CustomMessage {
120
+ return {
121
+ role: "custom",
122
+ customType,
123
+ content,
124
+ display,
125
+ details,
126
+ attribution,
127
+ timestamp: new Date(timestamp).getTime(),
128
+ };
129
+ }
130
+
131
+ function isCoreCompactionMessage(message: AgentMessage): message is AgentMessage & CoreCompactionMessage {
132
+ return (
133
+ message.role === "custom" ||
134
+ message.role === "hookMessage" ||
135
+ message.role === "branchSummary" ||
136
+ message.role === "compactionSummary"
137
+ );
138
+ }
139
+
140
+ /**
141
+ * Default compaction-domain transformer.
142
+ *
143
+ * Embedders with their own app messages should pass a richer transformer through
144
+ * `SummaryOptions.convertToLlm`; this default intentionally preserves only the
145
+ * core LLM roles and the compaction messages owned by this package.
146
+ */
147
+ export function defaultConvertToLlm(messages: AgentMessage[]): Message[] {
148
+ return messages
149
+ .map((message): Message | undefined => {
150
+ if (isCoreCompactionMessage(message)) {
151
+ switch (message.role) {
152
+ case "custom":
153
+ case "hookMessage": {
154
+ const content =
155
+ typeof message.content === "string"
156
+ ? [{ type: "text" as const, text: message.content }]
157
+ : message.content;
158
+ return {
159
+ role: "user",
160
+ content,
161
+ attribution: message.attribution,
162
+ timestamp: message.timestamp,
163
+ };
164
+ }
165
+ case "branchSummary":
166
+ return {
167
+ role: "user",
168
+ content: [
169
+ {
170
+ type: "text" as const,
171
+ text: renderBranchSummaryContext(message.summary),
172
+ },
173
+ ],
174
+ attribution: "agent",
175
+ timestamp: message.timestamp,
176
+ };
177
+ case "compactionSummary":
178
+ return {
179
+ role: "user",
180
+ content: [
181
+ {
182
+ type: "text" as const,
183
+ text: renderCompactionSummaryContext(message.summary),
184
+ },
185
+ ],
186
+ attribution: "agent",
187
+ providerPayload: message.providerPayload,
188
+ timestamp: message.timestamp,
189
+ };
190
+ }
191
+ }
192
+
193
+ switch (message.role) {
194
+ case "user":
195
+ return { ...message, attribution: message.attribution ?? "user" };
196
+ case "developer":
197
+ return { ...message, attribution: message.attribution ?? "agent" };
198
+ case "assistant":
199
+ return message as AssistantMessage;
200
+ case "toolResult":
201
+ return {
202
+ ...message,
203
+ content: getPrunedToolResultContent(message as ToolResultMessage),
204
+ attribution: message.attribution ?? "agent",
205
+ };
206
+ default:
207
+ return undefined;
208
+ }
209
+ })
210
+ .filter(message => message !== undefined);
211
+ }
212
+ export const convertToLlm = defaultConvertToLlm;