@ethosagent/core 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ethos Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,173 @@
1
+ import { LLMProvider, ToolRegistry, PersonalityRegistry, MemoryProvider, SessionStore, HookRegistry, ContextInjector, Session, SessionFilter, StoredMessage, SessionUsage, SearchResult, MemoryLoadContext, MemoryUpdate, PersonalityConfig, VoidHooks, ModifyingHooks, ClaimingHooks, Tool, ToolContext, ToolResult } from '@ethosagent/types';
2
+
3
+ type AgentEvent = {
4
+ type: 'text_delta';
5
+ text: string;
6
+ } | {
7
+ type: 'thinking_delta';
8
+ thinking: string;
9
+ } | {
10
+ type: 'tool_start';
11
+ toolCallId: string;
12
+ toolName: string;
13
+ args: unknown;
14
+ } | {
15
+ type: 'tool_progress';
16
+ toolName: string;
17
+ message: string;
18
+ percent?: number;
19
+ } | {
20
+ type: 'tool_end';
21
+ toolCallId: string;
22
+ toolName: string;
23
+ ok: boolean;
24
+ durationMs: number;
25
+ } | {
26
+ type: 'usage';
27
+ inputTokens: number;
28
+ outputTokens: number;
29
+ estimatedCostUsd: number;
30
+ } | {
31
+ type: 'error';
32
+ error: string;
33
+ code: string;
34
+ } | {
35
+ type: 'done';
36
+ text: string;
37
+ turnCount: number;
38
+ };
39
+ interface AgentLoopConfig {
40
+ llm: LLMProvider;
41
+ tools?: ToolRegistry;
42
+ personalities?: PersonalityRegistry;
43
+ memory?: MemoryProvider;
44
+ session?: SessionStore;
45
+ hooks?: HookRegistry;
46
+ injectors?: ContextInjector[];
47
+ options?: {
48
+ maxIterations?: number;
49
+ historyLimit?: number;
50
+ platform?: string;
51
+ workingDir?: string;
52
+ resultBudgetChars?: number;
53
+ };
54
+ }
55
+ interface RunOptions {
56
+ sessionKey?: string;
57
+ personalityId?: string;
58
+ abortSignal?: AbortSignal;
59
+ }
60
+ declare class AgentLoop {
61
+ private readonly llm;
62
+ private readonly tools;
63
+ private readonly personalities;
64
+ private readonly memory;
65
+ private readonly session;
66
+ private readonly hooks;
67
+ private readonly injectors;
68
+ private readonly maxIterations;
69
+ private readonly historyLimit;
70
+ private readonly platform;
71
+ private readonly workingDir;
72
+ private readonly resultBudgetChars;
73
+ constructor(config: AgentLoopConfig);
74
+ run(text: string, opts?: RunOptions): AsyncGenerator<AgentEvent>;
75
+ private handleChunk;
76
+ private toLLMMessages;
77
+ }
78
+
79
+ declare class InMemorySessionStore implements SessionStore {
80
+ private sessions;
81
+ private messages;
82
+ private idCounter;
83
+ createSession(data: Omit<Session, 'id' | 'createdAt' | 'updatedAt'>): Promise<Session>;
84
+ getSession(id: string): Promise<Session | null>;
85
+ getSessionByKey(key: string): Promise<Session | null>;
86
+ updateSession(id: string, patch: Partial<Session>): Promise<void>;
87
+ deleteSession(id: string): Promise<void>;
88
+ listSessions(filter?: SessionFilter): Promise<Session[]>;
89
+ appendMessage(data: Omit<StoredMessage, 'id' | 'timestamp'>): Promise<StoredMessage>;
90
+ getMessages(sessionId: string, options?: {
91
+ limit?: number;
92
+ offset?: number;
93
+ }): Promise<StoredMessage[]>;
94
+ updateUsage(sessionId: string, delta: Partial<SessionUsage>): Promise<void>;
95
+ search(query: string, options?: {
96
+ limit?: number;
97
+ sessionId?: string;
98
+ }): Promise<SearchResult[]>;
99
+ pruneOldSessions(olderThan: Date): Promise<number>;
100
+ vacuum(): Promise<void>;
101
+ }
102
+
103
+ declare class NoopMemoryProvider implements MemoryProvider {
104
+ prefetch(_ctx: MemoryLoadContext): Promise<null>;
105
+ sync(_ctx: MemoryLoadContext, _updates: MemoryUpdate[]): Promise<void>;
106
+ }
107
+
108
+ declare class DefaultPersonalityRegistry implements PersonalityRegistry {
109
+ private readonly personalities;
110
+ private defaultId;
111
+ define(config: PersonalityConfig): void;
112
+ get(id: string): PersonalityConfig | undefined;
113
+ list(): PersonalityConfig[];
114
+ getDefault(): PersonalityConfig;
115
+ setDefault(id: string): void;
116
+ loadFromDirectory(_dir: string): Promise<void>;
117
+ }
118
+
119
+ declare class DefaultHookRegistry implements HookRegistry {
120
+ private readonly voidHandlers;
121
+ private readonly modifyingHandlers;
122
+ private readonly claimingHandlers;
123
+ registerVoid<K extends keyof VoidHooks>(name: K, handler: (payload: VoidHooks[K]) => Promise<void>, opts?: {
124
+ pluginId?: string;
125
+ failurePolicy?: 'fail-open' | 'fail-closed';
126
+ }): () => void;
127
+ registerModifying<K extends keyof ModifyingHooks>(name: K, handler: (payload: ModifyingHooks[K][0]) => Promise<Partial<ModifyingHooks[K][1]> | null>, opts?: {
128
+ pluginId?: string;
129
+ }): () => void;
130
+ registerClaiming<K extends keyof ClaimingHooks>(name: K, handler: (payload: ClaimingHooks[K][0]) => Promise<ClaimingHooks[K][1]>, opts?: {
131
+ pluginId?: string;
132
+ }): () => void;
133
+ fireVoid<K extends keyof VoidHooks>(name: K, payload: VoidHooks[K]): Promise<void>;
134
+ fireModifying<K extends keyof ModifyingHooks>(name: K, payload: ModifyingHooks[K][0]): Promise<ModifyingHooks[K][1]>;
135
+ fireClaiming<K extends keyof ClaimingHooks>(name: K, payload: ClaimingHooks[K][0]): Promise<ClaimingHooks[K][1]>;
136
+ unregisterPlugin(pluginId: string): void;
137
+ private remove;
138
+ }
139
+
140
+ type PluginFactory<T, C = unknown> = (config: C) => T | null;
141
+ declare class PluginRegistry<T, C = unknown> {
142
+ private readonly factories;
143
+ register(type: string, factory: PluginFactory<T, C>): void;
144
+ create(type: string, config: C): T;
145
+ has(type: string): boolean;
146
+ types(): string[];
147
+ }
148
+
149
+ declare class DefaultToolRegistry implements ToolRegistry {
150
+ private readonly tools;
151
+ register(tool: Tool): void;
152
+ registerAll(tools: Tool[]): void;
153
+ unregister(name: string): void;
154
+ get(name: string): Tool | undefined;
155
+ getAvailable(): Tool[];
156
+ getForToolset(toolset: string): Tool[];
157
+ toDefinitions(): {
158
+ name: string;
159
+ description: string;
160
+ parameters: Record<string, unknown>;
161
+ }[];
162
+ executeParallel(calls: Array<{
163
+ toolCallId: string;
164
+ name: string;
165
+ args: unknown;
166
+ }>, ctx: ToolContext): Promise<Array<{
167
+ toolCallId: string;
168
+ name: string;
169
+ result: ToolResult;
170
+ }>>;
171
+ }
172
+
173
+ export { type AgentEvent, AgentLoop, type AgentLoopConfig, DefaultHookRegistry, DefaultPersonalityRegistry, DefaultToolRegistry, InMemorySessionStore, NoopMemoryProvider, type PluginFactory, PluginRegistry, type RunOptions };
package/dist/index.js ADDED
@@ -0,0 +1,759 @@
1
+ // src/defaults/in-memory-session.ts
2
+ var InMemorySessionStore = class {
3
+ sessions = /* @__PURE__ */ new Map();
4
+ messages = /* @__PURE__ */ new Map();
5
+ idCounter = 0;
6
+ async createSession(data) {
7
+ const session = {
8
+ ...data,
9
+ id: `session_${++this.idCounter}`,
10
+ createdAt: /* @__PURE__ */ new Date(),
11
+ updatedAt: /* @__PURE__ */ new Date()
12
+ };
13
+ this.sessions.set(session.id, session);
14
+ this.messages.set(session.id, []);
15
+ return session;
16
+ }
17
+ async getSession(id) {
18
+ return this.sessions.get(id) ?? null;
19
+ }
20
+ async getSessionByKey(key) {
21
+ for (const s of this.sessions.values()) {
22
+ if (s.key === key) return s;
23
+ }
24
+ return null;
25
+ }
26
+ async updateSession(id, patch) {
27
+ const session = this.sessions.get(id);
28
+ if (!session) throw new Error(`Session not found: ${id}`);
29
+ this.sessions.set(id, { ...session, ...patch, updatedAt: /* @__PURE__ */ new Date() });
30
+ }
31
+ async deleteSession(id) {
32
+ this.sessions.delete(id);
33
+ this.messages.delete(id);
34
+ }
35
+ async listSessions(filter) {
36
+ let results = [...this.sessions.values()];
37
+ if (filter?.platform) results = results.filter((s) => s.platform === filter.platform);
38
+ if (filter?.personalityId)
39
+ results = results.filter((s) => s.personalityId === filter.personalityId);
40
+ if (filter?.workingDir) results = results.filter((s) => s.workingDir === filter.workingDir);
41
+ if (filter?.since) {
42
+ const since = filter.since;
43
+ results = results.filter((s) => s.createdAt >= since);
44
+ }
45
+ results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
46
+ const offset = filter?.offset ?? 0;
47
+ const limit = filter?.limit ?? results.length;
48
+ return results.slice(offset, offset + limit);
49
+ }
50
+ async appendMessage(data) {
51
+ const message = {
52
+ ...data,
53
+ id: `msg_${++this.idCounter}`,
54
+ timestamp: /* @__PURE__ */ new Date()
55
+ };
56
+ const list = this.messages.get(data.sessionId) ?? [];
57
+ list.push(message);
58
+ this.messages.set(data.sessionId, list);
59
+ return message;
60
+ }
61
+ async getMessages(sessionId, options) {
62
+ const all = this.messages.get(sessionId) ?? [];
63
+ const offset = options?.offset ?? 0;
64
+ const end = all.length - offset;
65
+ const start = options?.limit ? Math.max(0, end - options.limit) : 0;
66
+ return all.slice(start, end);
67
+ }
68
+ async updateUsage(sessionId, delta) {
69
+ const session = this.sessions.get(sessionId);
70
+ if (!session) return;
71
+ const usage = { ...session.usage };
72
+ for (const [k, v] of Object.entries(delta)) {
73
+ usage[k] += v;
74
+ }
75
+ this.sessions.set(sessionId, { ...session, usage, updatedAt: /* @__PURE__ */ new Date() });
76
+ }
77
+ async search(query, options) {
78
+ const results = [];
79
+ const lower = query.toLowerCase();
80
+ for (const [sessionId, msgs] of this.messages.entries()) {
81
+ if (options?.sessionId && sessionId !== options.sessionId) continue;
82
+ for (const msg of msgs) {
83
+ const idx = msg.content.toLowerCase().indexOf(lower);
84
+ if (idx >= 0) {
85
+ results.push({
86
+ sessionId,
87
+ messageId: msg.id,
88
+ snippet: msg.content.slice(Math.max(0, idx - 50), idx + 150),
89
+ score: 1,
90
+ timestamp: msg.timestamp
91
+ });
92
+ }
93
+ }
94
+ }
95
+ results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
96
+ return results.slice(0, options?.limit ?? 20);
97
+ }
98
+ async pruneOldSessions(olderThan) {
99
+ let count = 0;
100
+ for (const [id, session] of this.sessions.entries()) {
101
+ if (session.updatedAt < olderThan) {
102
+ this.sessions.delete(id);
103
+ this.messages.delete(id);
104
+ count++;
105
+ }
106
+ }
107
+ return count;
108
+ }
109
+ async vacuum() {
110
+ }
111
+ };
112
+
113
+ // src/defaults/noop-memory.ts
114
+ var NoopMemoryProvider = class {
115
+ async prefetch(_ctx) {
116
+ return null;
117
+ }
118
+ async sync(_ctx, _updates) {
119
+ }
120
+ };
121
+
122
+ // src/defaults/noop-personality.ts
123
+ var DEFAULT_PERSONALITY = {
124
+ id: "default",
125
+ name: "Default",
126
+ description: "Default Ethos personality"
127
+ };
128
+ var DefaultPersonalityRegistry = class {
129
+ personalities = /* @__PURE__ */ new Map([
130
+ ["default", DEFAULT_PERSONALITY]
131
+ ]);
132
+ defaultId = "default";
133
+ define(config) {
134
+ this.personalities.set(config.id, config);
135
+ }
136
+ get(id) {
137
+ return this.personalities.get(id);
138
+ }
139
+ list() {
140
+ return [...this.personalities.values()];
141
+ }
142
+ getDefault() {
143
+ return this.personalities.get(this.defaultId) ?? DEFAULT_PERSONALITY;
144
+ }
145
+ setDefault(id) {
146
+ if (!this.personalities.has(id)) {
147
+ throw new Error(`Unknown personality: ${id}`);
148
+ }
149
+ this.defaultId = id;
150
+ }
151
+ async loadFromDirectory(_dir) {
152
+ }
153
+ };
154
+
155
+ // src/hook-registry.ts
156
+ var DefaultHookRegistry = class {
157
+ voidHandlers = /* @__PURE__ */ new Map();
158
+ modifyingHandlers = /* @__PURE__ */ new Map();
159
+ claimingHandlers = /* @__PURE__ */ new Map();
160
+ registerVoid(name, handler, opts) {
161
+ const entry = {
162
+ handler,
163
+ pluginId: opts?.pluginId,
164
+ failurePolicy: opts?.failurePolicy ?? "fail-open"
165
+ };
166
+ const list = this.voidHandlers.get(name) ?? [];
167
+ list.push(entry);
168
+ this.voidHandlers.set(name, list);
169
+ return () => this.remove(this.voidHandlers, name, entry);
170
+ }
171
+ registerModifying(name, handler, opts) {
172
+ const entry = {
173
+ handler,
174
+ pluginId: opts?.pluginId,
175
+ failurePolicy: "fail-open"
176
+ };
177
+ const list = this.modifyingHandlers.get(name) ?? [];
178
+ list.push(entry);
179
+ this.modifyingHandlers.set(name, list);
180
+ return () => this.remove(this.modifyingHandlers, name, entry);
181
+ }
182
+ registerClaiming(name, handler, opts) {
183
+ const entry = {
184
+ handler,
185
+ pluginId: opts?.pluginId,
186
+ failurePolicy: "fail-open"
187
+ };
188
+ const list = this.claimingHandlers.get(name) ?? [];
189
+ list.push(entry);
190
+ this.claimingHandlers.set(name, list);
191
+ return () => this.remove(this.claimingHandlers, name, entry);
192
+ }
193
+ // Void hooks: all handlers run in parallel via Promise.allSettled.
194
+ // Failures are logged but never propagate (fail-open by default).
195
+ async fireVoid(name, payload) {
196
+ const handlers = this.voidHandlers.get(name) ?? [];
197
+ await Promise.allSettled(handlers.map((h) => h.handler(payload)));
198
+ }
199
+ // Modifying hooks: handlers run sequentially; results are merged (first non-null value per key wins).
200
+ async fireModifying(name, payload) {
201
+ const handlers = this.modifyingHandlers.get(name) ?? [];
202
+ const merged = {};
203
+ for (const h of handlers) {
204
+ try {
205
+ const result = await h.handler(payload);
206
+ if (result && typeof result === "object") {
207
+ for (const [k, v] of Object.entries(result)) {
208
+ if (!(k in merged) && v !== null && v !== void 0) {
209
+ merged[k] = v;
210
+ }
211
+ }
212
+ }
213
+ } catch {
214
+ }
215
+ }
216
+ return merged;
217
+ }
218
+ // Claiming hooks: handlers run sequentially, stop after first { handled: true }.
219
+ async fireClaiming(name, payload) {
220
+ const handlers = this.claimingHandlers.get(name) ?? [];
221
+ for (const h of handlers) {
222
+ try {
223
+ const result = await h.handler(payload);
224
+ if (result && result.handled) {
225
+ return result;
226
+ }
227
+ } catch {
228
+ }
229
+ }
230
+ return { handled: false };
231
+ }
232
+ unregisterPlugin(pluginId) {
233
+ for (const map of [this.voidHandlers, this.modifyingHandlers, this.claimingHandlers]) {
234
+ for (const [name, handlers] of map.entries()) {
235
+ map.set(
236
+ name,
237
+ handlers.filter((h) => h.pluginId !== pluginId)
238
+ );
239
+ }
240
+ }
241
+ }
242
+ remove(map, name, entry) {
243
+ const list = map.get(name) ?? [];
244
+ map.set(
245
+ name,
246
+ list.filter((h) => h !== entry)
247
+ );
248
+ }
249
+ };
250
+
251
+ // src/tool-registry.ts
252
+ var DefaultToolRegistry = class {
253
+ tools = /* @__PURE__ */ new Map();
254
+ register(tool) {
255
+ this.tools.set(tool.name, tool);
256
+ }
257
+ registerAll(tools) {
258
+ for (const tool of tools) {
259
+ this.register(tool);
260
+ }
261
+ }
262
+ unregister(name) {
263
+ this.tools.delete(name);
264
+ }
265
+ get(name) {
266
+ return this.tools.get(name);
267
+ }
268
+ getAvailable() {
269
+ return [...this.tools.values()].filter((t) => !t.isAvailable || t.isAvailable());
270
+ }
271
+ getForToolset(toolset) {
272
+ return this.getAvailable().filter((t) => t.toolset === toolset);
273
+ }
274
+ toDefinitions() {
275
+ return this.getAvailable().map((t) => ({
276
+ name: t.name,
277
+ description: t.description,
278
+ parameters: t.schema
279
+ }));
280
+ }
281
+ // Runs all tool calls in parallel. Results are returned in input order.
282
+ // Budget is split evenly across parallel calls; each result is post-trimmed to budget.
283
+ async executeParallel(calls, ctx) {
284
+ const perCallBudget = Math.floor(ctx.resultBudgetChars / Math.max(calls.length, 1));
285
+ const results = await Promise.allSettled(
286
+ calls.map(async (call) => {
287
+ const tool = this.tools.get(call.name);
288
+ if (!tool) {
289
+ return {
290
+ toolCallId: call.toolCallId,
291
+ name: call.name,
292
+ result: {
293
+ ok: false,
294
+ error: `Unknown tool: ${call.name}`,
295
+ code: "not_available"
296
+ }
297
+ };
298
+ }
299
+ if (tool.isAvailable && !tool.isAvailable()) {
300
+ return {
301
+ toolCallId: call.toolCallId,
302
+ name: call.name,
303
+ result: {
304
+ ok: false,
305
+ error: `Tool ${call.name} is not currently available`,
306
+ code: "not_available"
307
+ }
308
+ };
309
+ }
310
+ const budget = Math.min(perCallBudget, tool.maxResultChars ?? perCallBudget);
311
+ const toolCtx = { ...ctx, resultBudgetChars: budget };
312
+ try {
313
+ const result = await tool.execute(call.args, toolCtx);
314
+ if (result.ok && result.value.length > budget) {
315
+ return {
316
+ toolCallId: call.toolCallId,
317
+ name: call.name,
318
+ result: {
319
+ ok: true,
320
+ value: `${result.value.slice(0, budget)}
321
+ [truncated \u2014 ${result.value.length} chars total]`
322
+ }
323
+ };
324
+ }
325
+ return { toolCallId: call.toolCallId, name: call.name, result };
326
+ } catch (err) {
327
+ return {
328
+ toolCallId: call.toolCallId,
329
+ name: call.name,
330
+ result: {
331
+ ok: false,
332
+ error: err instanceof Error ? err.message : String(err),
333
+ code: "execution_failed"
334
+ }
335
+ };
336
+ }
337
+ })
338
+ );
339
+ return results.map((r, i) => {
340
+ if (r.status === "fulfilled") return r.value;
341
+ const call = calls[i] ?? { toolCallId: "unknown", name: "unknown", args: {} };
342
+ return {
343
+ toolCallId: call.toolCallId,
344
+ name: call.name,
345
+ result: {
346
+ ok: false,
347
+ error: String(r.reason),
348
+ code: "execution_failed"
349
+ }
350
+ };
351
+ });
352
+ }
353
+ };
354
+
355
+ // src/agent-loop.ts
356
+ var AgentLoop = class {
357
+ llm;
358
+ tools;
359
+ personalities;
360
+ memory;
361
+ session;
362
+ hooks;
363
+ injectors;
364
+ maxIterations;
365
+ historyLimit;
366
+ platform;
367
+ workingDir;
368
+ resultBudgetChars;
369
+ constructor(config) {
370
+ this.llm = config.llm;
371
+ this.tools = config.tools ?? new DefaultToolRegistry();
372
+ this.personalities = config.personalities ?? new DefaultPersonalityRegistry();
373
+ this.memory = config.memory ?? new NoopMemoryProvider();
374
+ this.session = config.session ?? new InMemorySessionStore();
375
+ this.hooks = config.hooks ?? new DefaultHookRegistry();
376
+ this.injectors = (config.injectors ?? []).sort((a, b) => b.priority - a.priority);
377
+ this.maxIterations = config.options?.maxIterations ?? 50;
378
+ this.historyLimit = config.options?.historyLimit ?? 200;
379
+ this.platform = config.options?.platform ?? "cli";
380
+ this.workingDir = config.options?.workingDir ?? process.cwd();
381
+ this.resultBudgetChars = config.options?.resultBudgetChars ?? 8e4;
382
+ }
383
+ async *run(text, opts = {}) {
384
+ const abortSignal = opts.abortSignal ?? new AbortController().signal;
385
+ const sessionKey = opts.sessionKey ?? `${this.platform}:default`;
386
+ const ethosSession = await this.session.getSessionByKey(sessionKey) ?? await this.session.createSession({
387
+ key: sessionKey,
388
+ platform: this.platform,
389
+ model: this.llm.model,
390
+ provider: this.llm.name,
391
+ personalityId: opts.personalityId,
392
+ workingDir: this.workingDir,
393
+ usage: {
394
+ inputTokens: 0,
395
+ outputTokens: 0,
396
+ cacheReadTokens: 0,
397
+ cacheCreationTokens: 0,
398
+ estimatedCostUsd: 0,
399
+ apiCallCount: 0,
400
+ compactionCount: 0
401
+ }
402
+ });
403
+ const sessionId = ethosSession.id;
404
+ const personality = (opts.personalityId ? this.personalities.get(opts.personalityId) : null) ?? this.personalities.getDefault();
405
+ await this.hooks.fireVoid("session_start", {
406
+ sessionId,
407
+ sessionKey,
408
+ platform: this.platform,
409
+ personalityId: personality.id
410
+ });
411
+ await this.session.appendMessage({
412
+ sessionId,
413
+ role: "user",
414
+ content: text
415
+ });
416
+ const allMessages = await this.session.getMessages(sessionId, { limit: this.historyLimit });
417
+ const history = allMessages.filter((m) => m.role !== "system");
418
+ const memCtx = await this.memory.prefetch({
419
+ sessionId,
420
+ sessionKey,
421
+ platform: this.platform,
422
+ workingDir: this.workingDir,
423
+ personalityId: personality.id
424
+ });
425
+ const promptCtx = {
426
+ sessionId,
427
+ sessionKey,
428
+ platform: this.platform,
429
+ model: this.llm.model,
430
+ history,
431
+ workingDir: this.workingDir,
432
+ isDm: true,
433
+ turnNumber: allMessages.length,
434
+ personalityId: personality.id
435
+ };
436
+ const systemParts = [];
437
+ if (personality.ethosFile) {
438
+ try {
439
+ const fs = await import("fs/promises");
440
+ const identity = await fs.readFile(personality.ethosFile, "utf-8");
441
+ systemParts.push(identity.trim());
442
+ } catch {
443
+ }
444
+ }
445
+ for (const injector of this.injectors) {
446
+ if (injector.shouldInject && !injector.shouldInject(promptCtx)) continue;
447
+ const result = await injector.inject(promptCtx);
448
+ if (result) {
449
+ if (result.position === "prepend") {
450
+ systemParts.unshift(result.content);
451
+ } else {
452
+ systemParts.push(result.content);
453
+ }
454
+ }
455
+ }
456
+ if (memCtx) {
457
+ systemParts.push(`## Memory
458
+
459
+ ${memCtx.content}`);
460
+ }
461
+ const buildResult = await this.hooks.fireModifying("before_prompt_build", {
462
+ sessionId,
463
+ personalityId: personality.id,
464
+ history
465
+ });
466
+ if (buildResult.overrideSystem) {
467
+ systemParts.length = 0;
468
+ systemParts.push(buildResult.overrideSystem);
469
+ } else {
470
+ if (buildResult.prependSystem) systemParts.unshift(buildResult.prependSystem);
471
+ if (buildResult.appendSystem) systemParts.push(buildResult.appendSystem);
472
+ }
473
+ const systemPrompt = systemParts.join("\n\n").trim() || void 0;
474
+ const llmMessages = this.toLLMMessages(history);
475
+ let fullText = "";
476
+ let turnCount = 0;
477
+ for (let iteration = 0; iteration < this.maxIterations; iteration++) {
478
+ if (abortSignal.aborted) {
479
+ yield { type: "error", error: "Aborted", code: "aborted" };
480
+ return;
481
+ }
482
+ await this.hooks.fireVoid("before_llm_call", {
483
+ sessionId,
484
+ model: this.llm.model,
485
+ turnNumber: turnCount
486
+ });
487
+ const pendingToolCalls = [];
488
+ let chunkText = "";
489
+ try {
490
+ const stream = this.llm.complete(llmMessages, this.tools.toDefinitions(), {
491
+ system: systemPrompt,
492
+ cacheSystemPrompt: true,
493
+ abortSignal
494
+ });
495
+ for await (const chunk of stream) {
496
+ if (abortSignal.aborted) break;
497
+ yield* this.handleChunk(chunk, pendingToolCalls, (t) => {
498
+ chunkText += t;
499
+ fullText += t;
500
+ });
501
+ }
502
+ } catch (err) {
503
+ const msg = err instanceof Error ? err.message : String(err);
504
+ yield { type: "error", error: msg, code: "llm_error" };
505
+ return;
506
+ }
507
+ turnCount++;
508
+ const completedToolCalls = pendingToolCalls.filter((tc) => tc.args !== void 0);
509
+ await this.session.appendMessage({
510
+ sessionId,
511
+ role: "assistant",
512
+ content: chunkText,
513
+ ...completedToolCalls.length > 0 && {
514
+ toolCalls: completedToolCalls.map((tc) => ({
515
+ id: tc.toolCallId,
516
+ name: tc.toolName,
517
+ input: tc.args
518
+ }))
519
+ }
520
+ });
521
+ await this.hooks.fireVoid("after_llm_call", {
522
+ sessionId,
523
+ text: chunkText,
524
+ usage: { inputTokens: 0, outputTokens: 0 }
525
+ });
526
+ if (completedToolCalls.length > 0) {
527
+ const assistantContent = [];
528
+ if (chunkText) assistantContent.push({ type: "text", text: chunkText });
529
+ for (const tc of completedToolCalls) {
530
+ assistantContent.push({
531
+ type: "tool_use",
532
+ id: tc.toolCallId,
533
+ name: tc.toolName,
534
+ input: tc.args
535
+ });
536
+ }
537
+ llmMessages.push({ role: "assistant", content: assistantContent });
538
+ } else {
539
+ llmMessages.push({ role: "assistant", content: chunkText });
540
+ break;
541
+ }
542
+ const toolCtxBase = {
543
+ sessionId,
544
+ sessionKey,
545
+ platform: this.platform,
546
+ workingDir: this.workingDir,
547
+ currentTurn: turnCount,
548
+ messageCount: allMessages.length + turnCount,
549
+ abortSignal,
550
+ emit: (_event) => {
551
+ },
552
+ resultBudgetChars: this.resultBudgetChars
553
+ };
554
+ const prepped = [];
555
+ for (const tc of completedToolCalls) {
556
+ const beforeResult = await this.hooks.fireModifying("before_tool_call", {
557
+ sessionId,
558
+ toolName: tc.toolName,
559
+ args: tc.args
560
+ });
561
+ if (beforeResult.error) {
562
+ yield {
563
+ type: "tool_end",
564
+ toolCallId: tc.toolCallId,
565
+ toolName: tc.toolName,
566
+ ok: false,
567
+ durationMs: 0
568
+ };
569
+ prepped.push({
570
+ toolCallId: tc.toolCallId,
571
+ name: tc.toolName,
572
+ args: tc.args,
573
+ rejected: beforeResult.error
574
+ });
575
+ continue;
576
+ }
577
+ const effectiveArgs = beforeResult.args ?? tc.args;
578
+ yield {
579
+ type: "tool_start",
580
+ toolCallId: tc.toolCallId,
581
+ toolName: tc.toolName,
582
+ args: effectiveArgs
583
+ };
584
+ prepped.push({ toolCallId: tc.toolCallId, name: tc.toolName, args: effectiveArgs });
585
+ }
586
+ const execInputs = prepped.filter((p) => p.rejected === void 0).map((p) => ({ toolCallId: p.toolCallId, name: p.name, args: p.args }));
587
+ const startedAt = Date.now();
588
+ const execResults = execInputs.length > 0 ? await this.tools.executeParallel(execInputs, toolCtxBase) : [];
589
+ const execResultMap = new Map(execResults.map((r) => [r.toolCallId, r]));
590
+ const toolResultContent = [];
591
+ for (const p of prepped) {
592
+ const durationMs = Date.now() - startedAt;
593
+ let result;
594
+ if (p.rejected !== void 0) {
595
+ result = { ok: false, error: p.rejected, code: "execution_failed" };
596
+ } else {
597
+ const execResult = execResultMap.get(p.toolCallId);
598
+ result = execResult?.result ?? {
599
+ ok: false,
600
+ error: "Tool result missing",
601
+ code: "execution_failed"
602
+ };
603
+ yield {
604
+ type: "tool_end",
605
+ toolCallId: p.toolCallId,
606
+ toolName: p.name,
607
+ ok: result.ok,
608
+ durationMs
609
+ };
610
+ await this.hooks.fireVoid("after_tool_call", {
611
+ sessionId,
612
+ toolName: p.name,
613
+ result,
614
+ durationMs
615
+ });
616
+ }
617
+ await this.session.appendMessage({
618
+ sessionId,
619
+ role: "tool_result",
620
+ content: result.ok ? result.value : result.error,
621
+ toolCallId: p.toolCallId,
622
+ toolName: p.name
623
+ });
624
+ toolResultContent.push({
625
+ type: "tool_result",
626
+ tool_use_id: p.toolCallId,
627
+ content: result.ok ? result.value : result.error,
628
+ is_error: !result.ok
629
+ });
630
+ }
631
+ llmMessages.push({ role: "user", content: toolResultContent });
632
+ }
633
+ await this.memory.sync(
634
+ { sessionId, sessionKey, platform: this.platform, workingDir: this.workingDir },
635
+ []
636
+ );
637
+ await this.session.updateUsage(sessionId, { apiCallCount: turnCount });
638
+ await this.hooks.fireVoid("agent_done", { sessionId, text: fullText, turnCount });
639
+ yield { type: "done", text: fullText, turnCount };
640
+ }
641
+ *handleChunk(chunk, pendingToolCalls, onText) {
642
+ switch (chunk.type) {
643
+ case "text_delta":
644
+ onText(chunk.text);
645
+ yield { type: "text_delta", text: chunk.text };
646
+ break;
647
+ case "thinking_delta":
648
+ yield { type: "thinking_delta", thinking: chunk.thinking };
649
+ break;
650
+ case "tool_use_start":
651
+ pendingToolCalls.push({
652
+ toolCallId: chunk.toolCallId,
653
+ toolName: chunk.toolName,
654
+ partialJson: ""
655
+ });
656
+ break;
657
+ case "tool_use_delta": {
658
+ const tc = pendingToolCalls.find((t) => t.toolCallId === chunk.toolCallId);
659
+ if (tc) tc.partialJson += chunk.partialJson;
660
+ break;
661
+ }
662
+ case "tool_use_end": {
663
+ const tc = pendingToolCalls.find((t) => t.toolCallId === chunk.toolCallId);
664
+ if (tc) {
665
+ try {
666
+ tc.args = JSON.parse(chunk.inputJson || tc.partialJson);
667
+ } catch {
668
+ tc.args = {};
669
+ }
670
+ }
671
+ break;
672
+ }
673
+ case "usage":
674
+ yield {
675
+ type: "usage",
676
+ inputTokens: chunk.usage.inputTokens,
677
+ outputTokens: chunk.usage.outputTokens,
678
+ estimatedCostUsd: chunk.usage.estimatedCostUsd
679
+ };
680
+ break;
681
+ case "done":
682
+ break;
683
+ }
684
+ }
685
+ // Reconstruct LLM-ready messages from stored history.
686
+ // Assistant messages with tool calls produce proper tool_use content blocks.
687
+ // Consecutive tool_result rows are grouped into a single user message.
688
+ toLLMMessages(stored) {
689
+ const messages = [];
690
+ for (const msg of stored) {
691
+ if (msg.role === "system") continue;
692
+ if (msg.role === "user") {
693
+ messages.push({ role: "user", content: msg.content });
694
+ } else if (msg.role === "assistant") {
695
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
696
+ const content = [];
697
+ if (msg.content) content.push({ type: "text", text: msg.content });
698
+ for (const tc of msg.toolCalls) {
699
+ content.push({ type: "tool_use", id: tc.id, name: tc.name, input: tc.input });
700
+ }
701
+ messages.push({ role: "assistant", content });
702
+ } else {
703
+ messages.push({ role: "assistant", content: msg.content });
704
+ }
705
+ } else if (msg.role === "tool_result") {
706
+ const resultBlock = {
707
+ type: "tool_result",
708
+ tool_use_id: msg.toolCallId ?? "",
709
+ content: msg.content,
710
+ is_error: false
711
+ };
712
+ const last = messages[messages.length - 1];
713
+ if (last?.role === "user" && Array.isArray(last.content)) {
714
+ last.content.push(resultBlock);
715
+ } else {
716
+ messages.push({ role: "user", content: [resultBlock] });
717
+ }
718
+ }
719
+ }
720
+ return messages;
721
+ }
722
+ };
723
+
724
+ // src/plugin-registry.ts
725
+ var PluginRegistry = class {
726
+ factories = /* @__PURE__ */ new Map();
727
+ register(type, factory) {
728
+ this.factories.set(type, factory);
729
+ }
730
+ create(type, config) {
731
+ const factory = this.factories.get(type);
732
+ if (!factory) {
733
+ throw new Error(
734
+ `Unknown plugin type: "${type}". Registered: ${[...this.factories.keys()].join(", ")}`
735
+ );
736
+ }
737
+ const instance = factory(config);
738
+ if (!instance) {
739
+ throw new Error(`Plugin factory for "${type}" returned null`);
740
+ }
741
+ return instance;
742
+ }
743
+ has(type) {
744
+ return this.factories.has(type);
745
+ }
746
+ types() {
747
+ return [...this.factories.keys()];
748
+ }
749
+ };
750
+ export {
751
+ AgentLoop,
752
+ DefaultHookRegistry,
753
+ DefaultPersonalityRegistry,
754
+ DefaultToolRegistry,
755
+ InMemorySessionStore,
756
+ NoopMemoryProvider,
757
+ PluginRegistry
758
+ };
759
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/defaults/in-memory-session.ts","../src/defaults/noop-memory.ts","../src/defaults/noop-personality.ts","../src/hook-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/plugin-registry.ts"],"sourcesContent":["import type {\n SearchResult,\n Session,\n SessionFilter,\n SessionStore,\n SessionUsage,\n StoredMessage,\n} from '@ethosagent/types';\n\nexport class InMemorySessionStore implements SessionStore {\n private sessions = new Map<string, Session>();\n private messages = new Map<string, StoredMessage[]>();\n private idCounter = 0;\n\n async createSession(data: Omit<Session, 'id' | 'createdAt' | 'updatedAt'>): Promise<Session> {\n const session: Session = {\n ...data,\n id: `session_${++this.idCounter}`,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.sessions.set(session.id, session);\n this.messages.set(session.id, []);\n return session;\n }\n\n async getSession(id: string): Promise<Session | null> {\n return this.sessions.get(id) ?? null;\n }\n\n async getSessionByKey(key: string): Promise<Session | null> {\n for (const s of this.sessions.values()) {\n if (s.key === key) return s;\n }\n return null;\n }\n\n async updateSession(id: string, patch: Partial<Session>): Promise<void> {\n const session = this.sessions.get(id);\n if (!session) throw new Error(`Session not found: ${id}`);\n this.sessions.set(id, { ...session, ...patch, updatedAt: new Date() });\n }\n\n async deleteSession(id: string): Promise<void> {\n this.sessions.delete(id);\n this.messages.delete(id);\n }\n\n async listSessions(filter?: SessionFilter): Promise<Session[]> {\n let results = [...this.sessions.values()];\n if (filter?.platform) results = results.filter((s) => s.platform === filter.platform);\n if (filter?.personalityId)\n results = results.filter((s) => s.personalityId === filter.personalityId);\n if (filter?.workingDir) results = results.filter((s) => s.workingDir === filter.workingDir);\n if (filter?.since) {\n const since = filter.since;\n results = results.filter((s) => s.createdAt >= since);\n }\n results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n const offset = filter?.offset ?? 0;\n const limit = filter?.limit ?? results.length;\n return results.slice(offset, offset + limit);\n }\n\n async appendMessage(data: Omit<StoredMessage, 'id' | 'timestamp'>): Promise<StoredMessage> {\n const message: StoredMessage = {\n ...data,\n id: `msg_${++this.idCounter}`,\n timestamp: new Date(),\n };\n const list = this.messages.get(data.sessionId) ?? [];\n list.push(message);\n this.messages.set(data.sessionId, list);\n return message;\n }\n\n async getMessages(\n sessionId: string,\n options?: { limit?: number; offset?: number },\n ): Promise<StoredMessage[]> {\n const all = this.messages.get(sessionId) ?? [];\n const offset = options?.offset ?? 0;\n // Return most-recent messages: trim from the tail, then skip `offset` from the end\n const end = all.length - offset;\n const start = options?.limit ? Math.max(0, end - options.limit) : 0;\n return all.slice(start, end);\n }\n\n async updateUsage(sessionId: string, delta: Partial<SessionUsage>): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return;\n const usage = { ...session.usage };\n for (const [k, v] of Object.entries(delta) as [keyof SessionUsage, number][]) {\n (usage[k] as number) += v;\n }\n this.sessions.set(sessionId, { ...session, usage, updatedAt: new Date() });\n }\n\n async search(\n query: string,\n options?: { limit?: number; sessionId?: string },\n ): Promise<SearchResult[]> {\n const results: SearchResult[] = [];\n const lower = query.toLowerCase();\n for (const [sessionId, msgs] of this.messages.entries()) {\n if (options?.sessionId && sessionId !== options.sessionId) continue;\n for (const msg of msgs) {\n const idx = msg.content.toLowerCase().indexOf(lower);\n if (idx >= 0) {\n results.push({\n sessionId,\n messageId: msg.id,\n snippet: msg.content.slice(Math.max(0, idx - 50), idx + 150),\n score: 1,\n timestamp: msg.timestamp,\n });\n }\n }\n }\n results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n return results.slice(0, options?.limit ?? 20);\n }\n\n async pruneOldSessions(olderThan: Date): Promise<number> {\n let count = 0;\n for (const [id, session] of this.sessions.entries()) {\n if (session.updatedAt < olderThan) {\n this.sessions.delete(id);\n this.messages.delete(id);\n count++;\n }\n }\n return count;\n }\n\n async vacuum(): Promise<void> {\n // No-op for in-memory store\n }\n}\n","import type { MemoryLoadContext, MemoryProvider, MemoryUpdate } from '@ethosagent/types';\n\nexport class NoopMemoryProvider implements MemoryProvider {\n async prefetch(_ctx: MemoryLoadContext) {\n return null;\n }\n\n async sync(_ctx: MemoryLoadContext, _updates: MemoryUpdate[]): Promise<void> {\n // No-op\n }\n}\n","import type { PersonalityConfig, PersonalityRegistry } from '@ethosagent/types';\n\nconst DEFAULT_PERSONALITY: PersonalityConfig = {\n id: 'default',\n name: 'Default',\n description: 'Default Ethos personality',\n};\n\nexport class DefaultPersonalityRegistry implements PersonalityRegistry {\n private readonly personalities = new Map<string, PersonalityConfig>([\n ['default', DEFAULT_PERSONALITY],\n ]);\n private defaultId = 'default';\n\n define(config: PersonalityConfig): void {\n this.personalities.set(config.id, config);\n }\n\n get(id: string): PersonalityConfig | undefined {\n return this.personalities.get(id);\n }\n\n list(): PersonalityConfig[] {\n return [...this.personalities.values()];\n }\n\n getDefault(): PersonalityConfig {\n return this.personalities.get(this.defaultId) ?? DEFAULT_PERSONALITY;\n }\n\n setDefault(id: string): void {\n if (!this.personalities.has(id)) {\n throw new Error(`Unknown personality: ${id}`);\n }\n this.defaultId = id;\n }\n\n async loadFromDirectory(_dir: string): Promise<void> {\n // Implemented in extensions/personalities\n }\n}\n","import type { ClaimingHooks, HookRegistry, ModifyingHooks, VoidHooks } from '@ethosagent/types';\n\ntype AnyHandler = (...args: unknown[]) => Promise<unknown>;\n\ninterface RegisteredHandler {\n handler: AnyHandler;\n pluginId?: string;\n failurePolicy: 'fail-open' | 'fail-closed';\n}\n\nexport class DefaultHookRegistry implements HookRegistry {\n private readonly voidHandlers = new Map<string, RegisteredHandler[]>();\n private readonly modifyingHandlers = new Map<string, RegisteredHandler[]>();\n private readonly claimingHandlers = new Map<string, RegisteredHandler[]>();\n\n registerVoid<K extends keyof VoidHooks>(\n name: K,\n handler: (payload: VoidHooks[K]) => Promise<void>,\n opts?: { pluginId?: string; failurePolicy?: 'fail-open' | 'fail-closed' },\n ): () => void {\n const entry: RegisteredHandler = {\n handler: handler as AnyHandler,\n pluginId: opts?.pluginId,\n failurePolicy: opts?.failurePolicy ?? 'fail-open',\n };\n const list = this.voidHandlers.get(name) ?? [];\n list.push(entry);\n this.voidHandlers.set(name, list);\n return () => this.remove(this.voidHandlers, name, entry);\n }\n\n registerModifying<K extends keyof ModifyingHooks>(\n name: K,\n handler: (payload: ModifyingHooks[K][0]) => Promise<Partial<ModifyingHooks[K][1]> | null>,\n opts?: { pluginId?: string },\n ): () => void {\n const entry: RegisteredHandler = {\n handler: handler as AnyHandler,\n pluginId: opts?.pluginId,\n failurePolicy: 'fail-open',\n };\n const list = this.modifyingHandlers.get(name) ?? [];\n list.push(entry);\n this.modifyingHandlers.set(name, list);\n return () => this.remove(this.modifyingHandlers, name, entry);\n }\n\n registerClaiming<K extends keyof ClaimingHooks>(\n name: K,\n handler: (payload: ClaimingHooks[K][0]) => Promise<ClaimingHooks[K][1]>,\n opts?: { pluginId?: string },\n ): () => void {\n const entry: RegisteredHandler = {\n handler: handler as AnyHandler,\n pluginId: opts?.pluginId,\n failurePolicy: 'fail-open',\n };\n const list = this.claimingHandlers.get(name) ?? [];\n list.push(entry);\n this.claimingHandlers.set(name, list);\n return () => this.remove(this.claimingHandlers, name, entry);\n }\n\n // Void hooks: all handlers run in parallel via Promise.allSettled.\n // Failures are logged but never propagate (fail-open by default).\n async fireVoid<K extends keyof VoidHooks>(name: K, payload: VoidHooks[K]): Promise<void> {\n const handlers = this.voidHandlers.get(name) ?? [];\n await Promise.allSettled(handlers.map((h) => h.handler(payload)));\n }\n\n // Modifying hooks: handlers run sequentially; results are merged (first non-null value per key wins).\n async fireModifying<K extends keyof ModifyingHooks>(\n name: K,\n payload: ModifyingHooks[K][0],\n ): Promise<ModifyingHooks[K][1]> {\n const handlers = this.modifyingHandlers.get(name) ?? [];\n const merged: Record<string, unknown> = {};\n for (const h of handlers) {\n try {\n const result = await h.handler(payload);\n if (result && typeof result === 'object') {\n for (const [k, v] of Object.entries(result)) {\n if (!(k in merged) && v !== null && v !== undefined) {\n merged[k] = v;\n }\n }\n }\n } catch {\n // fail-open: continue with other handlers\n }\n }\n return merged as ModifyingHooks[K][1];\n }\n\n // Claiming hooks: handlers run sequentially, stop after first { handled: true }.\n async fireClaiming<K extends keyof ClaimingHooks>(\n name: K,\n payload: ClaimingHooks[K][0],\n ): Promise<ClaimingHooks[K][1]> {\n const handlers = this.claimingHandlers.get(name) ?? [];\n for (const h of handlers) {\n try {\n const result = (await h.handler(payload)) as ClaimingHooks[K][1];\n if (result && (result as { handled: boolean }).handled) {\n return result;\n }\n } catch {\n // fail-open: try next handler\n }\n }\n return { handled: false } as ClaimingHooks[K][1];\n }\n\n unregisterPlugin(pluginId: string): void {\n for (const map of [this.voidHandlers, this.modifyingHandlers, this.claimingHandlers]) {\n for (const [name, handlers] of map.entries()) {\n map.set(\n name,\n handlers.filter((h) => h.pluginId !== pluginId),\n );\n }\n }\n }\n\n private remove(\n map: Map<string, RegisteredHandler[]>,\n name: string,\n entry: RegisteredHandler,\n ): void {\n const list = map.get(name) ?? [];\n map.set(\n name,\n list.filter((h) => h !== entry),\n );\n }\n}\n","import type { Tool, ToolContext, ToolRegistry, ToolResult } from '@ethosagent/types';\n\nexport class DefaultToolRegistry implements ToolRegistry {\n private readonly tools = new Map<string, Tool>();\n\n register(tool: Tool): void {\n this.tools.set(tool.name, tool);\n }\n\n registerAll(tools: Tool[]): void {\n for (const tool of tools) {\n this.register(tool);\n }\n }\n\n unregister(name: string): void {\n this.tools.delete(name);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n getAvailable(): Tool[] {\n return [...this.tools.values()].filter((t) => !t.isAvailable || t.isAvailable());\n }\n\n getForToolset(toolset: string): Tool[] {\n return this.getAvailable().filter((t) => t.toolset === toolset);\n }\n\n toDefinitions() {\n return this.getAvailable().map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.schema,\n }));\n }\n\n // Runs all tool calls in parallel. Results are returned in input order.\n // Budget is split evenly across parallel calls; each result is post-trimmed to budget.\n async executeParallel(\n calls: Array<{ toolCallId: string; name: string; args: unknown }>,\n ctx: ToolContext,\n ): Promise<Array<{ toolCallId: string; name: string; result: ToolResult }>> {\n const perCallBudget = Math.floor(ctx.resultBudgetChars / Math.max(calls.length, 1));\n\n const results = await Promise.allSettled(\n calls.map(async (call) => {\n const tool = this.tools.get(call.name);\n if (!tool) {\n return {\n toolCallId: call.toolCallId,\n name: call.name,\n result: {\n ok: false,\n error: `Unknown tool: ${call.name}`,\n code: 'not_available',\n } as ToolResult,\n };\n }\n\n if (tool.isAvailable && !tool.isAvailable()) {\n return {\n toolCallId: call.toolCallId,\n name: call.name,\n result: {\n ok: false,\n error: `Tool ${call.name} is not currently available`,\n code: 'not_available',\n } as ToolResult,\n };\n }\n\n const budget = Math.min(perCallBudget, tool.maxResultChars ?? perCallBudget);\n const toolCtx: ToolContext = { ...ctx, resultBudgetChars: budget };\n\n try {\n const result = await tool.execute(call.args, toolCtx);\n // Post-trim result to budget\n if (result.ok && result.value.length > budget) {\n return {\n toolCallId: call.toolCallId,\n name: call.name,\n result: {\n ok: true,\n value: `${result.value.slice(0, budget)}\\n[truncated — ${result.value.length} chars total]`,\n } as ToolResult,\n };\n }\n return { toolCallId: call.toolCallId, name: call.name, result };\n } catch (err) {\n return {\n toolCallId: call.toolCallId,\n name: call.name,\n result: {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n code: 'execution_failed',\n } as ToolResult,\n };\n }\n }),\n );\n\n // Unwrap settled results — always return, never throw\n return results.map((r, i) => {\n if (r.status === 'fulfilled') return r.value;\n const call = calls[i] ?? { toolCallId: 'unknown', name: 'unknown', args: {} };\n return {\n toolCallId: call.toolCallId,\n name: call.name,\n result: {\n ok: false,\n error: String(r.reason),\n code: 'execution_failed',\n } as ToolResult,\n };\n });\n }\n}\n","import type {\n CompletionChunk,\n ContextInjector,\n HookRegistry,\n LLMProvider,\n MemoryProvider,\n Message,\n MessageContent,\n PersonalityRegistry,\n SessionStore,\n StoredMessage,\n ToolRegistry,\n ToolResult,\n} from '@ethosagent/types';\n\nimport { InMemorySessionStore } from './defaults/in-memory-session';\nimport { NoopMemoryProvider } from './defaults/noop-memory';\nimport { DefaultPersonalityRegistry } from './defaults/noop-personality';\nimport { DefaultHookRegistry } from './hook-registry';\nimport { DefaultToolRegistry } from './tool-registry';\n\n// ---------------------------------------------------------------------------\n// Agent events emitted by run()\n// ---------------------------------------------------------------------------\n\nexport type AgentEvent =\n | { type: 'text_delta'; text: string }\n | { type: 'thinking_delta'; thinking: string }\n | { type: 'tool_start'; toolCallId: string; toolName: string; args: unknown }\n | { type: 'tool_progress'; toolName: string; message: string; percent?: number }\n | { type: 'tool_end'; toolCallId: string; toolName: string; ok: boolean; durationMs: number }\n | { type: 'usage'; inputTokens: number; outputTokens: number; estimatedCostUsd: number }\n | { type: 'error'; error: string; code: string }\n | { type: 'done'; text: string; turnCount: number };\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nexport interface AgentLoopConfig {\n llm: LLMProvider;\n tools?: ToolRegistry;\n personalities?: PersonalityRegistry;\n memory?: MemoryProvider;\n session?: SessionStore;\n hooks?: HookRegistry;\n injectors?: ContextInjector[];\n options?: {\n maxIterations?: number;\n historyLimit?: number;\n platform?: string;\n workingDir?: string;\n resultBudgetChars?: number;\n };\n}\n\nexport interface RunOptions {\n sessionKey?: string;\n personalityId?: string;\n abortSignal?: AbortSignal;\n}\n\n// ---------------------------------------------------------------------------\n// AgentLoop\n// ---------------------------------------------------------------------------\n\nexport class AgentLoop {\n private readonly llm: LLMProvider;\n private readonly tools: ToolRegistry;\n private readonly personalities: PersonalityRegistry;\n private readonly memory: MemoryProvider;\n private readonly session: SessionStore;\n private readonly hooks: HookRegistry;\n private readonly injectors: ContextInjector[];\n private readonly maxIterations: number;\n private readonly historyLimit: number;\n private readonly platform: string;\n private readonly workingDir: string;\n private readonly resultBudgetChars: number;\n\n constructor(config: AgentLoopConfig) {\n this.llm = config.llm;\n this.tools = config.tools ?? new DefaultToolRegistry();\n this.personalities = config.personalities ?? new DefaultPersonalityRegistry();\n this.memory = config.memory ?? new NoopMemoryProvider();\n this.session = config.session ?? new InMemorySessionStore();\n this.hooks = config.hooks ?? new DefaultHookRegistry();\n this.injectors = (config.injectors ?? []).sort((a, b) => b.priority - a.priority);\n this.maxIterations = config.options?.maxIterations ?? 50;\n this.historyLimit = config.options?.historyLimit ?? 200;\n this.platform = config.options?.platform ?? 'cli';\n this.workingDir = config.options?.workingDir ?? process.cwd();\n this.resultBudgetChars = config.options?.resultBudgetChars ?? 80_000;\n }\n\n async *run(text: string, opts: RunOptions = {}): AsyncGenerator<AgentEvent> {\n const abortSignal = opts.abortSignal ?? new AbortController().signal;\n const sessionKey = opts.sessionKey ?? `${this.platform}:default`;\n\n // Step 1: Resolve or create session\n const ethosSession =\n (await this.session.getSessionByKey(sessionKey)) ??\n (await this.session.createSession({\n key: sessionKey,\n platform: this.platform,\n model: this.llm.model,\n provider: this.llm.name,\n personalityId: opts.personalityId,\n workingDir: this.workingDir,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n estimatedCostUsd: 0,\n apiCallCount: 0,\n compactionCount: 0,\n },\n }));\n\n const sessionId = ethosSession.id;\n const personality =\n (opts.personalityId ? this.personalities.get(opts.personalityId) : null) ??\n this.personalities.getDefault();\n\n // Step 2: Fire session_start hooks\n await this.hooks.fireVoid('session_start', {\n sessionId,\n sessionKey,\n platform: this.platform,\n personalityId: personality.id,\n });\n\n // Step 3: Persist the user message\n await this.session.appendMessage({\n sessionId,\n role: 'user',\n content: text,\n });\n\n // Step 4: Load history (trimmed to most-recent limit)\n const allMessages = await this.session.getMessages(sessionId, { limit: this.historyLimit });\n const history = allMessages.filter((m) => m.role !== 'system');\n\n // Step 5: Prefetch memory\n const memCtx = await this.memory.prefetch({\n sessionId,\n sessionKey,\n platform: this.platform,\n workingDir: this.workingDir,\n personalityId: personality.id,\n });\n\n // Step 6: Build system prompt from injectors\n const promptCtx = {\n sessionId,\n sessionKey,\n platform: this.platform,\n model: this.llm.model,\n history,\n workingDir: this.workingDir,\n isDm: true,\n turnNumber: allMessages.length,\n personalityId: personality.id,\n };\n\n const systemParts: string[] = [];\n\n // ETHOS.md / personality identity\n if (personality.ethosFile) {\n try {\n const fs = await import('node:fs/promises');\n const identity = await fs.readFile(personality.ethosFile, 'utf-8');\n systemParts.push(identity.trim());\n } catch {\n // ethosFile not readable — skip\n }\n }\n\n // Context injectors sorted by priority (already sorted in constructor)\n for (const injector of this.injectors) {\n if (injector.shouldInject && !injector.shouldInject(promptCtx)) continue;\n const result = await injector.inject(promptCtx);\n if (result) {\n if (result.position === 'prepend') {\n systemParts.unshift(result.content);\n } else {\n systemParts.push(result.content);\n }\n }\n }\n\n // Memory injected last, as context about the user\n if (memCtx) {\n systemParts.push(`## Memory\\n\\n${memCtx.content}`);\n }\n\n // Step 7: Before-prompt-build modifying hooks (plugins can prepend/append/override)\n const buildResult = await this.hooks.fireModifying('before_prompt_build', {\n sessionId,\n personalityId: personality.id,\n history,\n });\n\n if (buildResult.overrideSystem) {\n systemParts.length = 0;\n systemParts.push(buildResult.overrideSystem);\n } else {\n if (buildResult.prependSystem) systemParts.unshift(buildResult.prependSystem);\n if (buildResult.appendSystem) systemParts.push(buildResult.appendSystem);\n }\n\n const systemPrompt = systemParts.join('\\n\\n').trim() || undefined;\n\n // Step 8: Agentic loop — LLM call → tool use → LLM call → ...\n const llmMessages = this.toLLMMessages(history);\n let fullText = '';\n let turnCount = 0;\n\n for (let iteration = 0; iteration < this.maxIterations; iteration++) {\n if (abortSignal.aborted) {\n yield { type: 'error', error: 'Aborted', code: 'aborted' };\n return;\n }\n\n // Fire before_llm_call\n await this.hooks.fireVoid('before_llm_call', {\n sessionId,\n model: this.llm.model,\n turnNumber: turnCount,\n });\n\n // Stream LLM response\n const pendingToolCalls: Array<{\n toolCallId: string;\n toolName: string;\n partialJson: string;\n args?: unknown;\n }> = [];\n let chunkText = '';\n\n try {\n const stream = this.llm.complete(llmMessages, this.tools.toDefinitions(), {\n system: systemPrompt,\n cacheSystemPrompt: true,\n abortSignal,\n });\n\n for await (const chunk of stream) {\n if (abortSignal.aborted) break;\n yield* this.handleChunk(chunk, pendingToolCalls, (t) => {\n chunkText += t;\n fullText += t;\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n yield { type: 'error', error: msg, code: 'llm_error' };\n return;\n }\n\n turnCount++;\n\n // Determine which tool calls completed parsing\n const completedToolCalls = pendingToolCalls.filter((tc) => tc.args !== undefined);\n\n // Persist assistant message — include tool_use references so history is LLM-replayable\n await this.session.appendMessage({\n sessionId,\n role: 'assistant',\n content: chunkText,\n ...(completedToolCalls.length > 0 && {\n toolCalls: completedToolCalls.map((tc) => ({\n id: tc.toolCallId,\n name: tc.toolName,\n input: tc.args,\n })),\n }),\n });\n\n // Fire after_llm_call\n await this.hooks.fireVoid('after_llm_call', {\n sessionId,\n text: chunkText,\n usage: { inputTokens: 0, outputTokens: 0 },\n });\n\n // Push assistant message with proper content blocks for next iteration\n if (completedToolCalls.length > 0) {\n const assistantContent: MessageContent[] = [];\n if (chunkText) assistantContent.push({ type: 'text', text: chunkText });\n for (const tc of completedToolCalls) {\n assistantContent.push({\n type: 'tool_use',\n id: tc.toolCallId,\n name: tc.toolName,\n input: tc.args,\n });\n }\n llmMessages.push({ role: 'assistant', content: assistantContent });\n } else {\n llmMessages.push({ role: 'assistant', content: chunkText });\n break;\n }\n\n // Step 9: Pre-flight hooks → execute non-rejected tools → collect all results\n const toolCtxBase = {\n sessionId,\n sessionKey,\n platform: this.platform,\n workingDir: this.workingDir,\n currentTurn: turnCount,\n messageCount: allMessages.length + turnCount,\n abortSignal,\n emit: (_event: {\n type: 'progress';\n toolName: string;\n message: string;\n percent?: number;\n }) => {\n // Progress emission wired in Phase 6 (terminal streaming)\n },\n resultBudgetChars: this.resultBudgetChars,\n };\n\n // Run before_tool_call hooks; build exec list with effective args\n // Rejected tools get tool_end ok:false + an error tool_result sent back to LLM\n type Prepped = { toolCallId: string; name: string; args: unknown; rejected?: string };\n const prepped: Prepped[] = [];\n\n for (const tc of completedToolCalls) {\n const beforeResult = await this.hooks.fireModifying('before_tool_call', {\n sessionId,\n toolName: tc.toolName,\n args: tc.args,\n });\n\n if (beforeResult.error) {\n yield {\n type: 'tool_end',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n ok: false,\n durationMs: 0,\n };\n prepped.push({\n toolCallId: tc.toolCallId,\n name: tc.toolName,\n args: tc.args,\n rejected: beforeResult.error,\n });\n continue;\n }\n\n const effectiveArgs = beforeResult.args ?? tc.args;\n yield {\n type: 'tool_start',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n args: effectiveArgs,\n };\n prepped.push({ toolCallId: tc.toolCallId, name: tc.toolName, args: effectiveArgs });\n }\n\n // Execute only non-rejected tools; results keyed by toolCallId\n const execInputs = prepped\n .filter((p) => p.rejected === undefined)\n .map((p) => ({ toolCallId: p.toolCallId, name: p.name, args: p.args }));\n\n const startedAt = Date.now();\n const execResults =\n execInputs.length > 0 ? await this.tools.executeParallel(execInputs, toolCtxBase) : [];\n const execResultMap = new Map(execResults.map((r) => [r.toolCallId, r]));\n\n // Persist results + emit tool_end + build tool_result content blocks (original order)\n const toolResultContent: MessageContent[] = [];\n\n for (const p of prepped) {\n const durationMs = Date.now() - startedAt;\n let result: ToolResult;\n\n if (p.rejected !== undefined) {\n result = { ok: false, error: p.rejected, code: 'execution_failed' };\n // tool_end already emitted above; no after_tool_call hook for blocked tools\n } else {\n const execResult = execResultMap.get(p.toolCallId);\n result = execResult?.result ?? {\n ok: false,\n error: 'Tool result missing',\n code: 'execution_failed',\n };\n yield {\n type: 'tool_end',\n toolCallId: p.toolCallId,\n toolName: p.name,\n ok: result.ok,\n durationMs,\n };\n await this.hooks.fireVoid('after_tool_call', {\n sessionId,\n toolName: p.name,\n result,\n durationMs,\n });\n }\n\n // Persist every result (rejected or not) so history matches what LLM sees\n await this.session.appendMessage({\n sessionId,\n role: 'tool_result',\n content: result.ok ? result.value : result.error,\n toolCallId: p.toolCallId,\n toolName: p.name,\n });\n\n toolResultContent.push({\n type: 'tool_result',\n tool_use_id: p.toolCallId,\n content: result.ok ? result.value : result.error,\n is_error: !result.ok,\n });\n }\n\n // Feed all tool results back to LLM as a single user message with content blocks\n llmMessages.push({ role: 'user', content: toolResultContent });\n }\n\n // Step 10: Sync memory\n await this.memory.sync(\n { sessionId, sessionKey, platform: this.platform, workingDir: this.workingDir },\n [],\n );\n\n // Step 11: Update usage\n await this.session.updateUsage(sessionId, { apiCallCount: turnCount });\n\n // Step 12: Fire agent_done\n await this.hooks.fireVoid('agent_done', { sessionId, text: fullText, turnCount });\n\n yield { type: 'done', text: fullText, turnCount };\n }\n\n private *handleChunk(\n chunk: CompletionChunk,\n pendingToolCalls: Array<{\n toolCallId: string;\n toolName: string;\n partialJson: string;\n args?: unknown;\n }>,\n onText: (t: string) => void,\n ): Generator<AgentEvent> {\n switch (chunk.type) {\n case 'text_delta':\n onText(chunk.text);\n yield { type: 'text_delta', text: chunk.text };\n break;\n\n case 'thinking_delta':\n yield { type: 'thinking_delta', thinking: chunk.thinking };\n break;\n\n case 'tool_use_start':\n pendingToolCalls.push({\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n partialJson: '',\n });\n break;\n\n case 'tool_use_delta': {\n const tc = pendingToolCalls.find((t) => t.toolCallId === chunk.toolCallId);\n if (tc) tc.partialJson += chunk.partialJson;\n break;\n }\n\n case 'tool_use_end': {\n const tc = pendingToolCalls.find((t) => t.toolCallId === chunk.toolCallId);\n if (tc) {\n try {\n tc.args = JSON.parse(chunk.inputJson || tc.partialJson);\n } catch {\n tc.args = {};\n }\n }\n break;\n }\n\n case 'usage':\n yield {\n type: 'usage',\n inputTokens: chunk.usage.inputTokens,\n outputTokens: chunk.usage.outputTokens,\n estimatedCostUsd: chunk.usage.estimatedCostUsd,\n };\n break;\n\n case 'done':\n // finishReason available here for future context-compaction (Phase 3)\n break;\n }\n }\n\n // Reconstruct LLM-ready messages from stored history.\n // Assistant messages with tool calls produce proper tool_use content blocks.\n // Consecutive tool_result rows are grouped into a single user message.\n private toLLMMessages(stored: StoredMessage[]): Message[] {\n const messages: Message[] = [];\n\n for (const msg of stored) {\n if (msg.role === 'system') continue;\n\n if (msg.role === 'user') {\n messages.push({ role: 'user', content: msg.content });\n } else if (msg.role === 'assistant') {\n if (msg.toolCalls && msg.toolCalls.length > 0) {\n const content: MessageContent[] = [];\n if (msg.content) content.push({ type: 'text', text: msg.content });\n for (const tc of msg.toolCalls) {\n content.push({ type: 'tool_use', id: tc.id, name: tc.name, input: tc.input });\n }\n messages.push({ role: 'assistant', content });\n } else {\n messages.push({ role: 'assistant', content: msg.content });\n }\n } else if (msg.role === 'tool_result') {\n const resultBlock: MessageContent = {\n type: 'tool_result',\n tool_use_id: msg.toolCallId ?? '',\n content: msg.content,\n is_error: false,\n };\n const last = messages[messages.length - 1];\n // Append to existing tool_result user message, or start a new one\n if (last?.role === 'user' && Array.isArray(last.content)) {\n (last.content as MessageContent[]).push(resultBlock);\n } else {\n messages.push({ role: 'user', content: [resultBlock] });\n }\n }\n }\n\n return messages;\n }\n}\n","// Generic plugin registry — adapted from praxis PluginRegistry pattern.\n// Each subsystem (tools, channels, memory backends) gets its own instance.\n\nexport type PluginFactory<T, C = unknown> = (config: C) => T | null;\n\nexport class PluginRegistry<T, C = unknown> {\n private readonly factories = new Map<string, PluginFactory<T, C>>();\n\n register(type: string, factory: PluginFactory<T, C>): void {\n this.factories.set(type, factory);\n }\n\n create(type: string, config: C): T {\n const factory = this.factories.get(type);\n if (!factory) {\n throw new Error(\n `Unknown plugin type: \"${type}\". Registered: ${[...this.factories.keys()].join(', ')}`,\n );\n }\n const instance = factory(config);\n if (!instance) {\n throw new Error(`Plugin factory for \"${type}\" returned null`);\n }\n return instance;\n }\n\n has(type: string): boolean {\n return this.factories.has(type);\n }\n\n types(): string[] {\n return [...this.factories.keys()];\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@ethosagent/core",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Core agent loop, tool registry, and hook registry for the Ethos agent framework",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ethosdev/ethos"
10
+ },
11
+ "license": "MIT",
12
+ "files": [
13
+ "dist/"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/index.js",
18
+ "types": "./dist/index.d.ts"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@ethosagent/types": "0.1.0"
23
+ },
24
+ "scripts": {
25
+ "build": "tsup src/index.ts --format esm --dts --sourcemap"
26
+ }
27
+ }