@ethosagent/core 0.2.7 → 0.3.2
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/dist/index.d.ts +680 -7
- package/dist/index.js +2019 -43
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,175 @@
|
|
|
1
1
|
import * as _ethosagent_types from '@ethosagent/types';
|
|
2
|
-
import { HookRegistry, LLMProvider, ToolRegistry, PersonalityRegistry, MemoryProvider, SessionStore, ContextInjector, Storage, Session, SessionFilter, StoredMessage, SessionUsage, SearchResult,
|
|
2
|
+
import { ClarifyStore, PendingClarify, ClarifyResponse, ClarifyAnswerableBy, ClarifySurfaceType, PersonalityObservabilityConfig, SpanKind, EventSeverity, HookRegistry, LLMProvider, ToolRegistry, PersonalityRegistry, MemoryProvider, SessionStore, ContextInjector, Storage, ContextEngineRegistry, RequestDumpStore, SteerSink, Attachment, KeyValueStore, SecretRef, ToolCapabilities, ToolContext, Tool, PersonalityConfig, ContextEngine, ContextEngineCompactInput, ContextEngineCompactOutput, Message, Session, SessionFilter, StoredMessage, SessionUsage, SearchResult, CompressionEvent, MemoryContext, MemorySnapshot, MemoryEntry, SearchOpts, MemoryUpdate, ListOpts, MemoryEntryRef, VoidHooks, ModifyingHooks, ClaimingHooks, ToolDefinitionLite, CompletionOptions, CompletionChunk, LLMProviderRegistry, LLMProviderFactory, MemoryProviderRegistry, MemoryProviderFactory, RequestDumpRecord, ScopedFetch, ScopedFs, ScopedFsEntry, ScopedProcess, SpawnOpts, ProcessResult, ScopedSecretsResolver, ToolFilterOpts, ToolResult } from '@ethosagent/types';
|
|
3
|
+
export { MemoryConflictError } from '@ethosagent/types';
|
|
4
|
+
import * as _ethosagent_safety_watcher from '@ethosagent/safety-watcher';
|
|
5
|
+
import { InjectionClassifier } from '@ethosagent/safety-injection';
|
|
6
|
+
import { NetworkPolicy } from '@ethosagent/safety-network';
|
|
3
7
|
|
|
8
|
+
/** Raised by `request()` when a clarify is already pending for the session (plan Q5). */
|
|
9
|
+
declare class ClarifyBusyError extends Error {
|
|
10
|
+
readonly code: "CLARIFY_BUSY";
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
13
|
+
/** Raised by `request()` when the timeout fires and no `default` was provided (plan Q4/C). */
|
|
14
|
+
declare class ClarifyTimedOutNoDefaultError extends Error {
|
|
15
|
+
readonly code: "CLARIFY_TIMED_OUT_NO_DEFAULT";
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
/** Raised by `request()` when no interactive surface has registered a presenter. */
|
|
19
|
+
declare class ClarifyNoSurfaceError extends Error {
|
|
20
|
+
readonly code: "CLARIFY_NO_SURFACE";
|
|
21
|
+
constructor();
|
|
22
|
+
}
|
|
23
|
+
interface ClarifyRequestInput {
|
|
24
|
+
question: string;
|
|
25
|
+
options?: string[];
|
|
26
|
+
default?: string;
|
|
27
|
+
timeoutMs: number;
|
|
28
|
+
answerableBy: ClarifyAnswerableBy;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
surfaceType: ClarifySurfaceType;
|
|
31
|
+
surfaceContext?: Record<string, unknown>;
|
|
32
|
+
/** When the turn aborts, the pending clarify resolves as cancelled. */
|
|
33
|
+
abortSignal?: AbortSignal;
|
|
34
|
+
}
|
|
35
|
+
/** A surface registers this to present a pending clarify to the user. */
|
|
36
|
+
type ClarifyPresenter = (req: PendingClarify) => void | Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Fired when a pending clarify resolves (user answer, timeout, or cancel) —
|
|
39
|
+
* surfaces use it to tear down the prompt/modal/card they presented. The
|
|
40
|
+
* `row` carries the session id and request id; `response` is `null` for the
|
|
41
|
+
* timeout-no-default case (no answer was produced).
|
|
42
|
+
*/
|
|
43
|
+
type ClarifyResolvedListener = (row: PendingClarify, response: ClarifyResponse | null) => void;
|
|
44
|
+
declare class ClarifyBridge {
|
|
45
|
+
readonly store: ClarifyStore;
|
|
46
|
+
private readonly pending;
|
|
47
|
+
private presenter;
|
|
48
|
+
private readonly resolvedListeners;
|
|
49
|
+
/**
|
|
50
|
+
* `store` is exposed read-only so a surface (e.g. TelegramClarifySurface)
|
|
51
|
+
* can patch `surfaceContext` after presenting the prompt and look up rows
|
|
52
|
+
* by id without proxying every call through the bridge.
|
|
53
|
+
*/
|
|
54
|
+
constructor(store: ClarifyStore);
|
|
55
|
+
/** A surface registers how it presents a pending clarify to the user. */
|
|
56
|
+
setPresenter(presenter: ClarifyPresenter): void;
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to clarify resolutions so a surface can tear down its prompt
|
|
59
|
+
* when the request is answered, times out, or is cancelled. Returns an
|
|
60
|
+
* unsubscribe function.
|
|
61
|
+
*/
|
|
62
|
+
onResolved(listener: ClarifyResolvedListener): () => void;
|
|
63
|
+
/** True iff a clarify is currently pending for the given session. */
|
|
64
|
+
hasPending(sessionId: string): boolean;
|
|
65
|
+
/** Pending rows still awaiting an answer — for SSE reconnect re-presentation. */
|
|
66
|
+
listPending(sessionId?: string): PendingClarify[];
|
|
67
|
+
/**
|
|
68
|
+
* Persisted pending rows from the store — for boot-time hydration (a surface
|
|
69
|
+
* that outlives a single process needs to find rows that survived a
|
|
70
|
+
* restart). `listPending()` only sees in-memory rows; this is the source of
|
|
71
|
+
* truth across restarts.
|
|
72
|
+
*/
|
|
73
|
+
listPersisted(filter?: {
|
|
74
|
+
surfaceType?: string;
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
}): Promise<PendingClarify[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Issue a clarify request. Resolves when the user answers, the timeout fires
|
|
79
|
+
* (with `default`), or the turn aborts (as cancelled). Rejects with
|
|
80
|
+
* `ClarifyBusyError` if one is already pending for the session, or with
|
|
81
|
+
* `ClarifyTimedOutNoDefaultError` on timeout when no `default` was given.
|
|
82
|
+
*/
|
|
83
|
+
request(input: ClarifyRequestInput): Promise<ClarifyResponse>;
|
|
84
|
+
/**
|
|
85
|
+
* Resolve a pending clarify. Called by a surface when the user answers or
|
|
86
|
+
* cancels, and internally on timeout. Unknown / already-resolved ids are
|
|
87
|
+
* swallowed (another surface or the timeout beat this one).
|
|
88
|
+
*
|
|
89
|
+
* Degraded-mode fallback: when no in-process entry exists but the row is
|
|
90
|
+
* still persisted (gateway crashed mid-clarify, then the user tapped the
|
|
91
|
+
* button after restart), still clear the row and notify listeners so the
|
|
92
|
+
* surface can edit its UI to the resolved state. The original `request()`
|
|
93
|
+
* promise is gone — the agent waiting on it died with the process — so
|
|
94
|
+
* the answer can't reach the LLM, but at least the visible prompt updates.
|
|
95
|
+
*/
|
|
96
|
+
respond(response: ClarifyResponse): Promise<void>;
|
|
97
|
+
private notifyResolved;
|
|
98
|
+
/**
|
|
99
|
+
* Restart recovery: fire timeout responses for any persisted rows that have
|
|
100
|
+
* already passed their deadline. Called on boot and on an interval by
|
|
101
|
+
* surfaces that outlive a single turn (web-api, gateway).
|
|
102
|
+
*
|
|
103
|
+
* Listeners are notified for swept rows so surfaces can edit their UI in
|
|
104
|
+
* place — a card whose prompt timed out while the process was down should
|
|
105
|
+
* still update to the "timed out" state instead of hanging on buttons.
|
|
106
|
+
*/
|
|
107
|
+
sweep(now?: Date): Promise<void>;
|
|
108
|
+
private fireTimeout;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface RecordEventOpts {
|
|
112
|
+
traceId?: string;
|
|
113
|
+
spanId?: string;
|
|
114
|
+
code?: string;
|
|
115
|
+
cause?: string;
|
|
116
|
+
details?: Record<string, unknown>;
|
|
117
|
+
severity?: EventSeverity;
|
|
118
|
+
}
|
|
119
|
+
interface AgentLoopObservability {
|
|
120
|
+
startTurnTrace(opts: {
|
|
121
|
+
sessionId?: string;
|
|
122
|
+
personalityId?: string;
|
|
123
|
+
snapshotId?: string;
|
|
124
|
+
obsConfig?: PersonalityObservabilityConfig;
|
|
125
|
+
attrs?: Record<string, unknown>;
|
|
126
|
+
}): string;
|
|
127
|
+
endTrace(traceId: string, status: 'ok' | 'error' | 'aborted'): void;
|
|
128
|
+
startSpan(opts: {
|
|
129
|
+
traceId: string;
|
|
130
|
+
parentSpanId?: string;
|
|
131
|
+
kind: SpanKind;
|
|
132
|
+
name: string;
|
|
133
|
+
attrs?: Record<string, unknown>;
|
|
134
|
+
obsConfig?: PersonalityObservabilityConfig;
|
|
135
|
+
}): string;
|
|
136
|
+
endSpan(spanId: string, status: 'ok' | 'error' | 'blocked', attrs?: Record<string, unknown>): void;
|
|
137
|
+
recordSafetyBlock(opts: RecordEventOpts): void;
|
|
138
|
+
recordCompaction(opts: RecordEventOpts): void;
|
|
139
|
+
recordTierEscalation(opts: RecordEventOpts & {
|
|
140
|
+
from: string;
|
|
141
|
+
to: string;
|
|
142
|
+
reason: string;
|
|
143
|
+
personalityId: string;
|
|
144
|
+
}): void;
|
|
145
|
+
recordTierOverride(opts: RecordEventOpts & {
|
|
146
|
+
actor: 'user' | 'framework';
|
|
147
|
+
tier: string;
|
|
148
|
+
personalityId: string;
|
|
149
|
+
}): void;
|
|
150
|
+
flush(): void;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
declare const KNOWN_AGENT_EVENT_TYPES: readonly ["text_delta", "thinking_delta", "tool_start", "tool_progress", "tool_end", "usage", "error", "done", "context_meta", "run_start"];
|
|
154
|
+
type KnownAgentEventType = (typeof KNOWN_AGENT_EVENT_TYPES)[number];
|
|
155
|
+
/**
|
|
156
|
+
* Returns true when the event's `type` is one a current consumer knows
|
|
157
|
+
* about. Useful for development-mode warnings:
|
|
158
|
+
*
|
|
159
|
+
* for await (const event of loop.run(...)) {
|
|
160
|
+
* if (!isKnownAgentEvent(event)) {
|
|
161
|
+
* console.warn('Unknown AgentEvent type:', event.type);
|
|
162
|
+
* continue;
|
|
163
|
+
* }
|
|
164
|
+
* switch (event.type) { ... }
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* Production code should silently skip unknown events; this helper is for
|
|
168
|
+
* test runs and dev surfaces that want to alert on newly-added variants.
|
|
169
|
+
*/
|
|
170
|
+
declare function isKnownAgentEvent(event: {
|
|
171
|
+
type: string;
|
|
172
|
+
}): event is AgentEvent;
|
|
4
173
|
type AgentEvent = {
|
|
5
174
|
type: 'text_delta';
|
|
6
175
|
text: string;
|
|
@@ -17,14 +186,14 @@ type AgentEvent = {
|
|
|
17
186
|
toolName: string;
|
|
18
187
|
message: string;
|
|
19
188
|
percent?: number;
|
|
20
|
-
audience: 'internal' | 'user';
|
|
189
|
+
audience: 'internal' | 'user' | 'dashboard';
|
|
21
190
|
} | {
|
|
22
191
|
type: 'tool_end';
|
|
23
192
|
toolCallId: string;
|
|
24
193
|
toolName: string;
|
|
25
194
|
ok: boolean;
|
|
26
195
|
durationMs: number;
|
|
27
|
-
audience?: 'internal' | 'user';
|
|
196
|
+
audience?: 'internal' | 'user' | 'dashboard';
|
|
28
197
|
/**
|
|
29
198
|
* Tool output body — the success value when `ok`, or the error
|
|
30
199
|
* message when `ok: false`. Optional so consumers that only care
|
|
@@ -67,6 +236,12 @@ interface AgentLoopConfig {
|
|
|
67
236
|
tools?: ToolRegistry;
|
|
68
237
|
personalities?: PersonalityRegistry;
|
|
69
238
|
memory?: MemoryProvider;
|
|
239
|
+
/**
|
|
240
|
+
* Phase 3 — team id. When set, AgentLoop stamps `teamId` on every
|
|
241
|
+
* `ToolContext` so team memory tools can route to the correct team scope.
|
|
242
|
+
* Absent when running solo.
|
|
243
|
+
*/
|
|
244
|
+
teamId?: string;
|
|
70
245
|
session?: SessionStore;
|
|
71
246
|
hooks?: HookRegistry;
|
|
72
247
|
injectors?: ContextInjector[];
|
|
@@ -90,7 +265,63 @@ interface AgentLoopConfig {
|
|
|
90
265
|
* `storage` is set.
|
|
91
266
|
*/
|
|
92
267
|
dataDir?: string;
|
|
268
|
+
/**
|
|
269
|
+
* Optional observability adapter. When provided, AgentLoop records traces,
|
|
270
|
+
* spans, and events for LLM calls, tool calls, and errors via typed
|
|
271
|
+
* domain helpers. When absent, behaviour is identical to before — no
|
|
272
|
+
* observability writes occur.
|
|
273
|
+
*/
|
|
274
|
+
observability?: AgentLoopObservability;
|
|
275
|
+
/**
|
|
276
|
+
* Ch.3c — Tier-2 LLM injection classifier. When provided, AgentLoop calls
|
|
277
|
+
* it after wrapping any `outputIsUntrusted` tool result whose Tier-1
|
|
278
|
+
* pattern check fired, whose content is > 500 chars, or when the active
|
|
279
|
+
* personality's `safety.injectionDefense.classifier.alwaysCallLLM` is set.
|
|
280
|
+
* When unset, only Tier-1 (regex) classification runs.
|
|
281
|
+
*/
|
|
282
|
+
injectionClassifier?: InjectionClassifier;
|
|
283
|
+
/**
|
|
284
|
+
* Ch.6a — In-process watcher. When provided, AgentLoop forwards every
|
|
285
|
+
* tool_start / tool_end / usage event into watcher.observe() and acts
|
|
286
|
+
* on non-`allow` decisions:
|
|
287
|
+
* - `terminate` → yield an `error` event and end the turn
|
|
288
|
+
* - `pause` → yield a user-visible `tool_progress` chip and end
|
|
289
|
+
* the turn (the user's next message resumes; the
|
|
290
|
+
* watcher's state is fresh per run via resetTurn())
|
|
291
|
+
* - `force_approval` → set a per-iteration flag that promotes the
|
|
292
|
+
* next tool to requiresApproval (TODO — needs the
|
|
293
|
+
* approval-hook plumbing; for v1 we treat it as
|
|
294
|
+
* `pause` to fail safe)
|
|
295
|
+
* `allow` is the no-op path. Watcher decisions are recorded as
|
|
296
|
+
* `audit.watcher` events on the optional ObservabilityWriter.
|
|
297
|
+
*/
|
|
298
|
+
watcher?: _ethosagent_safety_watcher.Watcher;
|
|
93
299
|
modelRouting?: Record<string, string>;
|
|
300
|
+
/**
|
|
301
|
+
* Per-personality memory provider registry. Maps provider names ('markdown',
|
|
302
|
+
* 'vector', plugin-registered names) to factory functions. When a personality
|
|
303
|
+
* declares `memory.provider`, AgentLoop resolves from this map.
|
|
304
|
+
*/
|
|
305
|
+
memoryProviders?: Map<string, (options?: Record<string, unknown>) => MemoryProvider | Promise<MemoryProvider>>;
|
|
306
|
+
/**
|
|
307
|
+
* E4 — Pluggable context-engine registry. When unset, AgentLoop builds
|
|
308
|
+
* a `DefaultContextEngineRegistry` (drop_oldest + semantic_summary
|
|
309
|
+
* placeholder + reference_preserving). Each personality picks an engine
|
|
310
|
+
* via `personality.context_engine`; unknown names fall back to
|
|
311
|
+
* `drop_oldest` with a one-line warning.
|
|
312
|
+
*/
|
|
313
|
+
contextEngines?: ContextEngineRegistry;
|
|
314
|
+
/**
|
|
315
|
+
* Bridge for the `clarify` tool — the agent asks the user a structured
|
|
316
|
+
* question mid-turn and waits. Optional: when unset, the `clarify` tool
|
|
317
|
+
* reports `CLARIFY_NO_SURFACE` and the agent falls back to plain prose.
|
|
318
|
+
*/
|
|
319
|
+
clarifyBridge?: ClarifyBridge;
|
|
320
|
+
/**
|
|
321
|
+
* Optional request dump store. When provided, AgentLoop appends a full
|
|
322
|
+
* record of each LLM request/response for offline analysis and debugging.
|
|
323
|
+
*/
|
|
324
|
+
requestDumpStore?: RequestDumpStore;
|
|
94
325
|
options?: {
|
|
95
326
|
maxIterations?: number;
|
|
96
327
|
historyLimit?: number;
|
|
@@ -128,6 +359,26 @@ interface RunOptions {
|
|
|
128
359
|
* `MAX_SPAWN_DEPTH` can be enforced across recursive sub-agent calls.
|
|
129
360
|
*/
|
|
130
361
|
agentId?: string;
|
|
362
|
+
/**
|
|
363
|
+
* FW-9 — `steer` busy-input mode. Surfaces (CLI REPL) push user-typed text
|
|
364
|
+
* here while the agent is mid-turn. AgentLoop drains the sink at the
|
|
365
|
+
* iteration seam (after tool_results land, before the next LLM call) and
|
|
366
|
+
* folds each entry in as a `[USER STEER]: <text>` text block on the user
|
|
367
|
+
* message carrying the tool_results.
|
|
368
|
+
*
|
|
369
|
+
* Pre-first-iteration (no tool_results yet) and idle (no run in flight)
|
|
370
|
+
* steering falls back to `queue` at the surface, never reaching AgentLoop.
|
|
371
|
+
*/
|
|
372
|
+
steerSink?: SteerSink;
|
|
373
|
+
/** Per-turn inbound attachments from the user message. Persisted as an
|
|
374
|
+
* `<attachments>` annotation prepended to the user text. Threaded to the
|
|
375
|
+
* capability resolver via `ToolRegistry.setTurnAttachments()`. */
|
|
376
|
+
attachments?: _ethosagent_types.Attachment[];
|
|
377
|
+
/**
|
|
378
|
+
* Override model tier for this run only (from /tier command).
|
|
379
|
+
* Consumed once; does not persist across runs.
|
|
380
|
+
*/
|
|
381
|
+
tierOverride?: _ethosagent_types.ModelTierName;
|
|
131
382
|
}
|
|
132
383
|
declare class AgentLoop {
|
|
133
384
|
private readonly llm;
|
|
@@ -151,11 +402,30 @@ declare class AgentLoop {
|
|
|
151
402
|
private readonly maxIdenticalToolCalls;
|
|
152
403
|
private readonly streamingTimeoutMs;
|
|
153
404
|
private readonly modelRouting;
|
|
405
|
+
private readonly memoryProviders;
|
|
154
406
|
private readonly storage?;
|
|
155
407
|
private readonly dataDir?;
|
|
408
|
+
private readonly observability?;
|
|
409
|
+
private readonly injectionClassifier?;
|
|
410
|
+
private readonly watcher?;
|
|
411
|
+
private readonly contextEngines;
|
|
412
|
+
/** Bridge for the `clarify` tool; undefined when no interactive surface is wired. */
|
|
413
|
+
readonly clarifyBridge?: ClarifyBridge;
|
|
414
|
+
/** Optional request dump store for full LLM request/response recording. */
|
|
415
|
+
private readonly requestDumpStore?;
|
|
416
|
+
/** Phase 3 — team id stamped onto ToolContext when loop runs inside a team. */
|
|
417
|
+
private readonly teamId?;
|
|
156
418
|
/** Per-session accumulated spend in USD. Keyed by sessionKey. Reset via resetSessionCost(). */
|
|
157
419
|
private readonly sessionCosts;
|
|
420
|
+
/** FW-28 — per-session mtime registry. Keyed by sessionKey → (absPath → record). */
|
|
421
|
+
private readonly sessionReadMtimes;
|
|
158
422
|
constructor(config: AgentLoopConfig);
|
|
423
|
+
/**
|
|
424
|
+
* Resolve a pending clarify request — called by an interactive surface when
|
|
425
|
+
* the user answers or cancels. No-op when no clarify bridge is wired or the
|
|
426
|
+
* request id is unknown (already resolved / timed out).
|
|
427
|
+
*/
|
|
428
|
+
respondToClarify(response: _ethosagent_types.ClarifyResponse): Promise<void>;
|
|
159
429
|
/** Returns all available tools for inventory display (e.g. TUI splash screen). */
|
|
160
430
|
getAvailableTools(): _ethosagent_types.Tool[];
|
|
161
431
|
/** Returns all registered personalities for inventory display. */
|
|
@@ -166,15 +436,118 @@ declare class AgentLoop {
|
|
|
166
436
|
getSessionCost(sessionKey: string): number;
|
|
167
437
|
/** Resets the session spend counter — call after /new or /personality switch. */
|
|
168
438
|
resetSessionCost(sessionKey: string): void;
|
|
439
|
+
/**
|
|
440
|
+
* Resolve the effective model for an LLM call, respecting tier config.
|
|
441
|
+
* Returns the model string to pass as modelOverride, and the tier name used.
|
|
442
|
+
*/
|
|
443
|
+
private resolveModelWithTier;
|
|
169
444
|
run(text: string, opts?: RunOptions): AsyncGenerator<AgentEvent>;
|
|
170
445
|
private handleChunk;
|
|
446
|
+
private dedupHistory;
|
|
171
447
|
private toLLMMessages;
|
|
448
|
+
private handleUntrustedResult;
|
|
449
|
+
private maybeCompact;
|
|
172
450
|
private buildScopedStorage;
|
|
173
451
|
}
|
|
174
452
|
|
|
453
|
+
declare function buildAttachmentAnnotation(attachments: Attachment[]): string;
|
|
454
|
+
|
|
455
|
+
interface CapabilityBackends {
|
|
456
|
+
kvStoreFactory?: (tool: string, scopeId: string) => KeyValueStore;
|
|
457
|
+
secretsBackend?: (ref: SecretRef) => Promise<string>;
|
|
458
|
+
storage?: Storage;
|
|
459
|
+
personalityFsReach?: {
|
|
460
|
+
read: string[];
|
|
461
|
+
write: string[];
|
|
462
|
+
};
|
|
463
|
+
/**
|
|
464
|
+
* Full personality network policy. The `allow` list is intersected
|
|
465
|
+
* with each tool's declared `allowedHosts`; `deny` and
|
|
466
|
+
* `allow_private_urls` plus the always-on safety floor (cloud-metadata,
|
|
467
|
+
* private-network, scheme, DNS-rebinding) flow through `safeFetch`.
|
|
468
|
+
*/
|
|
469
|
+
personalityNetworkPolicy?: NetworkPolicy;
|
|
470
|
+
attachmentCache?: _ethosagent_types.AttachmentCache;
|
|
471
|
+
inboundAttachments?: _ethosagent_types.Attachment[];
|
|
472
|
+
}
|
|
473
|
+
type ResolvedFields = Partial<Pick<ToolContext, 'kvStore' | 'secretsResolver' | 'scopedFetch' | 'scopedFs' | 'scopedProcess' | 'attachments'>>;
|
|
474
|
+
interface CapabilityScopeIds {
|
|
475
|
+
sessionId: string;
|
|
476
|
+
personalityId?: string;
|
|
477
|
+
}
|
|
478
|
+
declare function resolveCapabilities(toolName: string, capabilities: ToolCapabilities | undefined, scopeIds: CapabilityScopeIds, backends: CapabilityBackends): ResolvedFields;
|
|
479
|
+
|
|
480
|
+
interface CapabilityValidationError {
|
|
481
|
+
tool: string;
|
|
482
|
+
capability: string;
|
|
483
|
+
message: string;
|
|
484
|
+
}
|
|
485
|
+
declare function validateRegistration(tool: Tool, personality: PersonalityConfig): CapabilityValidationError[];
|
|
486
|
+
|
|
487
|
+
declare class FileClarifyStore implements ClarifyStore {
|
|
488
|
+
private readonly storage;
|
|
489
|
+
private readonly root;
|
|
490
|
+
private readonly pendingPath;
|
|
491
|
+
/** Serializes the read-modify-write cycle within this process. */
|
|
492
|
+
private mutex;
|
|
493
|
+
/** `root` is the absolute `~/.ethos/clarify` directory (caller-resolved). */
|
|
494
|
+
constructor(storage: Storage, root: string);
|
|
495
|
+
add(req: PendingClarify): Promise<void>;
|
|
496
|
+
get(requestId: string): Promise<PendingClarify | null>;
|
|
497
|
+
list(filter?: {
|
|
498
|
+
surfaceType?: string;
|
|
499
|
+
sessionId?: string;
|
|
500
|
+
}): Promise<PendingClarify[]>;
|
|
501
|
+
remove(requestId: string): Promise<void>;
|
|
502
|
+
update(requestId: string, patch: Partial<PendingClarify>): Promise<void>;
|
|
503
|
+
expired(now: Date): Promise<PendingClarify[]>;
|
|
504
|
+
private readAll;
|
|
505
|
+
/** Run a read-modify-write under the per-process mutex with an atomic write. */
|
|
506
|
+
private mutate;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
declare class DropOldestEngine implements ContextEngine {
|
|
510
|
+
readonly name = "drop_oldest";
|
|
511
|
+
compact(opts: ContextEngineCompactInput): Promise<ContextEngineCompactOutput>;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
declare class ReferencePreservingEngine implements ContextEngine {
|
|
515
|
+
readonly name = "reference_preserving";
|
|
516
|
+
compact(opts: ContextEngineCompactInput): Promise<ContextEngineCompactOutput>;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
type SummarizerFn = (middle: Message[], targetTokens: number) => Promise<string>;
|
|
520
|
+
declare class SemanticSummaryEngine implements ContextEngine {
|
|
521
|
+
readonly name = "semantic_summary";
|
|
522
|
+
private readonly summarize;
|
|
523
|
+
constructor(opts?: {
|
|
524
|
+
summarize?: SummarizerFn;
|
|
525
|
+
});
|
|
526
|
+
compact(opts: ContextEngineCompactInput): Promise<ContextEngineCompactOutput>;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
interface DefaultContextEngineRegistryOptions {
|
|
530
|
+
/** Optional summarizer wired into the SemanticSummaryEngine. Without it
|
|
531
|
+
* that engine falls back to a placeholder summary (no LLM call). */
|
|
532
|
+
summarize?: SummarizerFn;
|
|
533
|
+
}
|
|
534
|
+
declare class DefaultContextEngineRegistry implements ContextEngineRegistry {
|
|
535
|
+
private readonly engines;
|
|
536
|
+
constructor(opts?: DefaultContextEngineRegistryOptions);
|
|
537
|
+
register(engine: ContextEngine): void;
|
|
538
|
+
get(name: string): ContextEngine | undefined;
|
|
539
|
+
names(): string[];
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
declare function estimateTokens(text: string): number;
|
|
543
|
+
declare function estimateMessageTokens(message: Message): number;
|
|
544
|
+
declare function estimateMessagesTokens(input: Message | Message[] | string): number;
|
|
545
|
+
|
|
175
546
|
declare class InMemorySessionStore implements SessionStore {
|
|
176
547
|
private sessions;
|
|
177
548
|
private messages;
|
|
549
|
+
private compressions;
|
|
550
|
+
private turnState;
|
|
178
551
|
private idCounter;
|
|
179
552
|
createSession(data: Omit<Session, 'id' | 'createdAt' | 'updatedAt'>): Promise<Session>;
|
|
180
553
|
getSession(id: string): Promise<Session | null>;
|
|
@@ -192,13 +565,36 @@ declare class InMemorySessionStore implements SessionStore {
|
|
|
192
565
|
limit?: number;
|
|
193
566
|
sessionId?: string;
|
|
194
567
|
}): Promise<SearchResult[]>;
|
|
568
|
+
recordCompression(event: Omit<CompressionEvent, 'id' | 'createdAt'>): Promise<CompressionEvent>;
|
|
569
|
+
listCompressions(sessionId: string): Promise<CompressionEvent[]>;
|
|
570
|
+
recordTurnStart(sessionId: string): Promise<{
|
|
571
|
+
turnNumber: number;
|
|
572
|
+
lastCompactionTurn: number;
|
|
573
|
+
}>;
|
|
574
|
+
recordCompactionTurn(sessionId: string, turnNumber: number): Promise<void>;
|
|
195
575
|
pruneOldSessions(olderThan: Date): Promise<number>;
|
|
196
576
|
vacuum(): Promise<void>;
|
|
197
577
|
}
|
|
198
578
|
|
|
579
|
+
interface InMemoryToolContextOptions {
|
|
580
|
+
sessionId?: string;
|
|
581
|
+
sessionKey?: string;
|
|
582
|
+
platform?: string;
|
|
583
|
+
workingDir?: string;
|
|
584
|
+
personalityId?: string;
|
|
585
|
+
currentTurn?: number;
|
|
586
|
+
messageCount?: number;
|
|
587
|
+
resultBudgetChars?: number;
|
|
588
|
+
withStorage?: boolean;
|
|
589
|
+
}
|
|
590
|
+
declare function makeTestToolContext(opts?: InMemoryToolContextOptions): ToolContext;
|
|
591
|
+
|
|
199
592
|
declare class NoopMemoryProvider implements MemoryProvider {
|
|
200
|
-
prefetch(_ctx:
|
|
201
|
-
|
|
593
|
+
prefetch(_ctx: MemoryContext): Promise<MemorySnapshot | null>;
|
|
594
|
+
read(_key: string, _ctx: MemoryContext): Promise<MemoryEntry | null>;
|
|
595
|
+
search(_query: string, _ctx: MemoryContext, _opts?: SearchOpts): Promise<MemoryEntry[]>;
|
|
596
|
+
sync(_updates: MemoryUpdate[], _ctx: MemoryContext): Promise<void>;
|
|
597
|
+
list(_ctx: MemoryContext, _opts?: ListOpts): Promise<MemoryEntryRef[]>;
|
|
202
598
|
}
|
|
203
599
|
|
|
204
600
|
declare class DefaultPersonalityRegistry implements PersonalityRegistry {
|
|
@@ -234,6 +630,115 @@ declare class DefaultHookRegistry implements HookRegistry {
|
|
|
234
630
|
private remove;
|
|
235
631
|
}
|
|
236
632
|
|
|
633
|
+
/**
|
|
634
|
+
* Pass-through decorator that makes the wiring intent explicit: this provider
|
|
635
|
+
* uses eager prefetch (all content injected at session start). The AgentLoop
|
|
636
|
+
* already calls `prefetch()` on every session open; this wrapper delegates all
|
|
637
|
+
* five methods unchanged. Used for personality memory.
|
|
638
|
+
*/
|
|
639
|
+
declare class EagerPrefetchPolicy implements MemoryProvider {
|
|
640
|
+
private readonly inner;
|
|
641
|
+
constructor(inner: MemoryProvider);
|
|
642
|
+
prefetch(ctx: MemoryContext): Promise<MemorySnapshot | null>;
|
|
643
|
+
read(key: string, ctx: MemoryContext): Promise<MemoryEntry | null>;
|
|
644
|
+
search(query: string, ctx: MemoryContext, opts?: SearchOpts): Promise<MemoryEntry[]>;
|
|
645
|
+
sync(updates: MemoryUpdate[], ctx: MemoryContext): Promise<void>;
|
|
646
|
+
list(ctx: MemoryContext, opts?: ListOpts): Promise<MemoryEntryRef[]>;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Suppresses bulk prefetch. `prefetch()` returns null so the AgentLoop does
|
|
650
|
+
* not inject all content at session start. The existing
|
|
651
|
+
* `createTeamMemoryIndexInjector` in wiring handles the lightweight topic-index
|
|
652
|
+
* injection via `list()`. All other methods delegate unchanged.
|
|
653
|
+
*
|
|
654
|
+
* Used for team memory: agents see a topic index and load content on demand via
|
|
655
|
+
* team_memory_read.
|
|
656
|
+
*/
|
|
657
|
+
declare class LazyOnDemandPolicy implements MemoryProvider {
|
|
658
|
+
private readonly inner;
|
|
659
|
+
constructor(inner: MemoryProvider);
|
|
660
|
+
prefetch(_ctx: MemoryContext): Promise<MemorySnapshot | null>;
|
|
661
|
+
read(key: string, ctx: MemoryContext): Promise<MemoryEntry | null>;
|
|
662
|
+
search(query: string, ctx: MemoryContext, opts?: SearchOpts): Promise<MemoryEntry[]>;
|
|
663
|
+
sync(updates: MemoryUpdate[], ctx: MemoryContext): Promise<void>;
|
|
664
|
+
list(ctx: MemoryContext, opts?: ListOpts): Promise<MemoryEntryRef[]>;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Wraps `sync()` with an optimistic-concurrency precondition check.
|
|
668
|
+
*
|
|
669
|
+
* The policy records the `mtime` (from `MemoryEntry.metadata.lastUpdatedAt`)
|
|
670
|
+
* each time `read()` or `search()` returns an entry, keyed by
|
|
671
|
+
* `${scopeId}:${key}`. When `sync()` is called for a key the policy has a
|
|
672
|
+
* read-timestamp for, it re-reads the current `mtime` from the inner provider
|
|
673
|
+
* and rejects the write with a `MemoryConflictError` if the file has been
|
|
674
|
+
* modified since the caller last saw it.
|
|
675
|
+
*
|
|
676
|
+
* Keys never read (no timestamp recorded) pass through unconditionally —
|
|
677
|
+
* this avoids blocking blind adds on new keys.
|
|
678
|
+
*
|
|
679
|
+
* **Known limitation — not fully atomic:** the mtime check and the subsequent
|
|
680
|
+
* `inner.sync()` are not a single atomic operation. Two concurrent writers
|
|
681
|
+
* that both pass the mtime check in the same millisecond can both write. This
|
|
682
|
+
* is an inherent property of the decorator approach over a filesystem backend;
|
|
683
|
+
* a fully atomic compare-and-swap would require support in the storage layer.
|
|
684
|
+
* The policy catches the common case of sequential-but-concurrent agents where
|
|
685
|
+
* writes are spaced by network and tool-call latency.
|
|
686
|
+
*
|
|
687
|
+
* **Instance scope:** one `LastWriteWinsPolicy` instance tracks timestamps for
|
|
688
|
+
* one caller (typically one AgentLoop / session). Do not share an instance
|
|
689
|
+
* across concurrent callers — the read-timestamp map is not thread-isolated and
|
|
690
|
+
* cross-caller reads would invalidate each other's preconditions.
|
|
691
|
+
*
|
|
692
|
+
* Used for team memory to prevent silent overwrites when two agents write the
|
|
693
|
+
* same file within the same session boundary.
|
|
694
|
+
*/
|
|
695
|
+
declare class LastWriteWinsPolicy implements MemoryProvider {
|
|
696
|
+
private readonly inner;
|
|
697
|
+
/** scopeId:key → mtime at last read (ms). */
|
|
698
|
+
private readonly lastReadAt;
|
|
699
|
+
constructor(inner: MemoryProvider);
|
|
700
|
+
prefetch(ctx: MemoryContext): Promise<MemorySnapshot | null>;
|
|
701
|
+
/** Records the entry's mtime so sync() can detect concurrent modifications. */
|
|
702
|
+
read(key: string, ctx: MemoryContext): Promise<MemoryEntry | null>;
|
|
703
|
+
/**
|
|
704
|
+
* Records mtimes for entries returned by search so that a write based on
|
|
705
|
+
* search results also benefits from conflict detection.
|
|
706
|
+
*
|
|
707
|
+
* Only sets the mtime when no prior timestamp is recorded for the key.
|
|
708
|
+
* Overwriting an existing timestamp from a search result would allow a
|
|
709
|
+
* stale write to pass: caller reads at mtime 1, external writer bumps to
|
|
710
|
+
* mtime 2, caller searches and the result records mtime 2, caller syncs
|
|
711
|
+
* stale content — conflict check passes because currentAt === recordedAt.
|
|
712
|
+
* Preserving the oldest (first-read) mtime ensures that risk does not apply.
|
|
713
|
+
*/
|
|
714
|
+
search(query: string, ctx: MemoryContext, opts?: SearchOpts): Promise<MemoryEntry[]>;
|
|
715
|
+
/**
|
|
716
|
+
* For each key that was previously read, check the current mtime against
|
|
717
|
+
* the recorded read-timestamp. Rejects the entire call if any key has been
|
|
718
|
+
* modified by another writer since the caller last read it.
|
|
719
|
+
*
|
|
720
|
+
* After a successful write, updates `lastReadAt` baselines so that a second
|
|
721
|
+
* `sync()` call on the same key does not spuriously fail. Keys that were
|
|
722
|
+
* deleted are removed from the tracker so they can be re-added later.
|
|
723
|
+
*/
|
|
724
|
+
sync(updates: MemoryUpdate[], ctx: MemoryContext): Promise<void>;
|
|
725
|
+
list(ctx: MemoryContext, opts?: ListOpts): Promise<MemoryEntryRef[]>;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Verify that `target` resolves to a path within (or equal to) `base`.
|
|
730
|
+
* Both paths are resolved to absolute before comparison.
|
|
731
|
+
*
|
|
732
|
+
* @throws BoundaryEscapeError if the resolved target escapes the base
|
|
733
|
+
*/
|
|
734
|
+
declare function assertWithinBase(base: string, target: string): void;
|
|
735
|
+
declare class BoundaryEscapeError extends Error {
|
|
736
|
+
readonly code: "path-boundary-escape";
|
|
737
|
+
readonly base: string;
|
|
738
|
+
readonly resolved: string;
|
|
739
|
+
constructor(base: string, resolved: string);
|
|
740
|
+
}
|
|
741
|
+
|
|
237
742
|
type PluginFactory<T, C = unknown> = (config: C) => T | null;
|
|
238
743
|
declare class PluginRegistry<T, C = unknown> {
|
|
239
744
|
private readonly factories;
|
|
@@ -275,11 +780,155 @@ declare class ChainedProvider implements LLMProvider {
|
|
|
275
780
|
private activeEntry;
|
|
276
781
|
}
|
|
277
782
|
|
|
783
|
+
declare class DefaultLLMProviderRegistry implements LLMProviderRegistry {
|
|
784
|
+
private readonly factories;
|
|
785
|
+
register(name: string, factory: LLMProviderFactory): void;
|
|
786
|
+
get(name: string): LLMProviderFactory | undefined;
|
|
787
|
+
list(): string[];
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
declare class DefaultMemoryProviderRegistry implements MemoryProviderRegistry {
|
|
791
|
+
private readonly factories;
|
|
792
|
+
register(name: string, factory: MemoryProviderFactory): void;
|
|
793
|
+
get(name: string): MemoryProviderFactory | undefined;
|
|
794
|
+
list(): string[];
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Bounded in-memory request dump store for tests. Not suitable for production
|
|
799
|
+
* — use JsonlRequestDumpStore (or a durable implementation) instead.
|
|
800
|
+
* Caps at `maxRecords` to prevent unbounded memory growth.
|
|
801
|
+
*/
|
|
802
|
+
declare class InMemoryRequestDumpStore implements RequestDumpStore {
|
|
803
|
+
private records;
|
|
804
|
+
private readonly maxRecords;
|
|
805
|
+
constructor(opts?: {
|
|
806
|
+
maxRecords?: number;
|
|
807
|
+
});
|
|
808
|
+
append(record: RequestDumpRecord): Promise<void>;
|
|
809
|
+
recent(opts: {
|
|
810
|
+
limit: number;
|
|
811
|
+
sessionId?: string;
|
|
812
|
+
since?: Date;
|
|
813
|
+
includeContent?: boolean;
|
|
814
|
+
}): Promise<RequestDumpRecord[]>;
|
|
815
|
+
close(): Promise<void>;
|
|
816
|
+
getAll(): RequestDumpRecord[];
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Strip ANSI escape sequences from untrusted output before rendering.
|
|
821
|
+
* Prevents terminal manipulation via LLM-generated or tool-fetched content.
|
|
822
|
+
*
|
|
823
|
+
* Covers:
|
|
824
|
+
* - CSI sequences (including private modes like ?25l, ?2004h): ESC[ ... <final>
|
|
825
|
+
* - OSC sequences terminated with BEL (\x07) or ST (ESC\): ESC] ... BEL|ST
|
|
826
|
+
* - Character set selection (G0/G1): ESC( <charset>
|
|
827
|
+
* - Other single-character escape sequences: ESC + one char
|
|
828
|
+
*/
|
|
829
|
+
declare function stripAnsiEscapes(input: string): string;
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Test seam — `safeFetch`'s injection points, mirrored on the wrapper so
|
|
833
|
+
* tests can stub DNS + fetch hermetically. Production wiring leaves
|
|
834
|
+
* these undefined; `safeFetch` defaults to `node:dns/promises#lookup`
|
|
835
|
+
* and `globalThis.fetch`.
|
|
836
|
+
*/
|
|
837
|
+
interface ScopedFetchTestSeam {
|
|
838
|
+
fetchImpl?: typeof fetch;
|
|
839
|
+
resolveHost?: (hostname: string) => Promise<string[]>;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Scoped network capability. Enforces two layers in order:
|
|
843
|
+
*
|
|
844
|
+
* 1. **Declared host allowlist** — the intersection of the tool's
|
|
845
|
+
* `capabilities.network.allowedHosts` with the personality's
|
|
846
|
+
* `safety.network.allow`, resolved at registration time.
|
|
847
|
+
* 2. **Non-overridable safety floor** — `safeFetch` runs scheme +
|
|
848
|
+
* cloud-metadata + private-network + per-redirect-hop revalidation
|
|
849
|
+
* regardless of declared hosts. A tool declaring `'*'` does NOT
|
|
850
|
+
* bypass the floor; a personality permitting `169.254.169.254` is
|
|
851
|
+
* still denied at the cloud-metadata layer.
|
|
852
|
+
*
|
|
853
|
+
* The two layers are not redundant: the allowlist is the policy
|
|
854
|
+
* surface tool authors and operators reason about; the floor catches
|
|
855
|
+
* the categories an allowlist can't (SSRF via redirect, DNS rebinding
|
|
856
|
+
* partial mitigation, file/data/javascript schemes).
|
|
857
|
+
*/
|
|
858
|
+
declare class ScopedFetchImpl implements ScopedFetch {
|
|
859
|
+
private readonly allowedHosts;
|
|
860
|
+
private readonly policy;
|
|
861
|
+
private readonly testSeam;
|
|
862
|
+
constructor(allowedHosts: Set<string>, policy: NetworkPolicy, testSeam?: ScopedFetchTestSeam);
|
|
863
|
+
fetch(url: string | URL, init?: RequestInit): Promise<Response>;
|
|
864
|
+
private isHostAllowed;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Scoped filesystem capability. Enforces two layers on every call:
|
|
869
|
+
*
|
|
870
|
+
* 1. **Non-overridable deny floor** — `defaultAlwaysDeny()` lists
|
|
871
|
+
* `.ssh`, `.aws/credentials`, `/etc/passwd`, `/root`, etc. A path
|
|
872
|
+
* that touches any of these denies even when the capability and
|
|
873
|
+
* personality both grant the parent (mirror of
|
|
874
|
+
* `safety-network`'s cloud-metadata block).
|
|
875
|
+
*
|
|
876
|
+
* 2. **Declared reach allowlist** — the intersection of the tool's
|
|
877
|
+
* `capabilities.fs_reach` with the personality's `fs_reach`,
|
|
878
|
+
* resolved at registration time. Paths outside the allow set are
|
|
879
|
+
* rejected with `PATH_NOT_REACHABLE`.
|
|
880
|
+
*
|
|
881
|
+
* The floor cannot be disabled by configuration. Tests that need to
|
|
882
|
+
* exercise a forbidden path override `$HOME` before constructing the
|
|
883
|
+
* wrapper.
|
|
884
|
+
*/
|
|
885
|
+
declare class ScopedFsImpl implements ScopedFs {
|
|
886
|
+
private readonly storage;
|
|
887
|
+
private readonly readPaths;
|
|
888
|
+
private readonly writePaths;
|
|
889
|
+
private readonly denyPaths;
|
|
890
|
+
constructor(storage: Storage, readPaths: Set<string>, writePaths: Set<string>);
|
|
891
|
+
read(path: string): Promise<string>;
|
|
892
|
+
readBytes(path: string): Promise<Uint8Array>;
|
|
893
|
+
write(path: string, content: string | Uint8Array): Promise<void>;
|
|
894
|
+
exists(path: string): Promise<boolean>;
|
|
895
|
+
list(path: string): Promise<string[]>;
|
|
896
|
+
mtime(path: string): Promise<number | null>;
|
|
897
|
+
mkdir(dir: string): Promise<void>;
|
|
898
|
+
listEntries(dir: string): Promise<ScopedFsEntry[]>;
|
|
899
|
+
private checkReach;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
declare class ScopedProcessImpl implements ScopedProcess {
|
|
903
|
+
private readonly allowedBinaries;
|
|
904
|
+
constructor(allowedBinaries: Set<string>);
|
|
905
|
+
spawn(binary: string, args: string[], opts?: SpawnOpts): Promise<ProcessResult>;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
type SecretsBackend = (ref: SecretRef) => Promise<string>;
|
|
909
|
+
declare class ScopedSecretsImpl implements ScopedSecretsResolver {
|
|
910
|
+
private readonly declaredRefs;
|
|
911
|
+
private readonly backend;
|
|
912
|
+
constructor(declaredRefs: Set<string>, backend: SecretsBackend);
|
|
913
|
+
get(ref: SecretRef): Promise<string>;
|
|
914
|
+
}
|
|
915
|
+
|
|
278
916
|
declare class DefaultToolRegistry implements ToolRegistry {
|
|
279
917
|
private readonly tools;
|
|
918
|
+
private readonly backends?;
|
|
919
|
+
constructor(backends?: CapabilityBackends);
|
|
280
920
|
register(tool: Tool, opts?: {
|
|
281
921
|
pluginId?: string;
|
|
282
922
|
}): void;
|
|
923
|
+
/**
|
|
924
|
+
* Validate every tool reachable for this personality (per
|
|
925
|
+
* `toolNamesForPersonality`) against the personality's policy. Only
|
|
926
|
+
* the tools the personality could actually call are checked — a
|
|
927
|
+
* personality that doesn't list `web_search` in its toolset does not
|
|
928
|
+
* fail because `web_search` declared `api.exa.ai` that's missing from
|
|
929
|
+
* `network.allow`.
|
|
930
|
+
*/
|
|
931
|
+
validateToolsForPersonality(personality: PersonalityConfig): CapabilityValidationError[];
|
|
283
932
|
registerAll(tools: Tool[]): void;
|
|
284
933
|
unregister(name: string): void;
|
|
285
934
|
get(name: string): Tool | undefined;
|
|
@@ -303,11 +952,35 @@ declare class DefaultToolRegistry implements ToolRegistry {
|
|
|
303
952
|
toolCallId: string;
|
|
304
953
|
name: string;
|
|
305
954
|
args: unknown;
|
|
306
|
-
}>, ctx: ToolContext, allowedTools?: string[], filterOpts?: ToolFilterOpts): Promise<Array<{
|
|
955
|
+
}>, ctx: ToolContext, allowedTools?: string[], filterOpts?: ToolFilterOpts, turnAttachments?: _ethosagent_types.Attachment[]): Promise<Array<{
|
|
307
956
|
toolCallId: string;
|
|
308
957
|
name: string;
|
|
309
958
|
result: ToolResult;
|
|
310
959
|
}>>;
|
|
311
960
|
}
|
|
312
961
|
|
|
313
|
-
|
|
962
|
+
interface ValidateUrlOptions {
|
|
963
|
+
/** Allow requests to localhost/127.0.0.1 (default: false).
|
|
964
|
+
* Useful for local LLM providers like Ollama. */
|
|
965
|
+
allowLocalhost?: boolean;
|
|
966
|
+
/** Additional hosts to allow even if they resolve to private IPs. */
|
|
967
|
+
trustedHosts?: string[];
|
|
968
|
+
}
|
|
969
|
+
declare class SsrfError extends Error {
|
|
970
|
+
constructor(url: string, reason: string);
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Synchronous SSRF validator. Checks:
|
|
974
|
+
* 1. URL is well-formed
|
|
975
|
+
* 2. Scheme is http or https
|
|
976
|
+
* 3. No embedded credentials
|
|
977
|
+
* 4. Hostname is not a cloud metadata endpoint
|
|
978
|
+
* 5. If hostname is a literal IP, it must not be in a private range
|
|
979
|
+
* 6. Hostname is not `localhost` or `.local` / `.internal`
|
|
980
|
+
*
|
|
981
|
+
* Does NOT perform DNS resolution — use `safeFetch` from `@ethosagent/safety-network`
|
|
982
|
+
* for runtime fetches where DNS rebinding is a concern.
|
|
983
|
+
*/
|
|
984
|
+
declare function validateUrl(urlStr: string, opts?: ValidateUrlOptions): URL;
|
|
985
|
+
|
|
986
|
+
export { type AgentEvent, AgentLoop, type AgentLoopConfig, type AgentLoopObservability, BoundaryEscapeError, type CapabilityBackends, type CapabilityScopeIds, type CapabilityValidationError, ChainedProvider, type ChainedProviderOptions, ClarifyBridge, ClarifyBusyError, ClarifyNoSurfaceError, type ClarifyPresenter, type ClarifyRequestInput, type ClarifyResolvedListener, ClarifyTimedOutNoDefaultError, DefaultContextEngineRegistry, type DefaultContextEngineRegistryOptions, DefaultHookRegistry, DefaultLLMProviderRegistry, DefaultMemoryProviderRegistry, DefaultPersonalityRegistry, DefaultToolRegistry, DropOldestEngine, EagerPrefetchPolicy, FileClarifyStore, InMemoryRequestDumpStore, InMemorySessionStore, type InMemoryToolContextOptions, KNOWN_AGENT_EVENT_TYPES, type KnownAgentEventType, LastWriteWinsPolicy, LazyOnDemandPolicy, NoopMemoryProvider, type PluginFactory, PluginRegistry, ReferencePreservingEngine, type RunOptions, ScopedFetchImpl, ScopedFsImpl, ScopedProcessImpl, ScopedSecretsImpl, type SecretsBackend, SemanticSummaryEngine, SsrfError, type SummarizerFn, type ValidateUrlOptions, assertWithinBase, buildAttachmentAnnotation, estimateMessageTokens, estimateMessagesTokens, estimateTokens, isKnownAgentEvent, makeTestToolContext, resolveCapabilities, stripAnsiEscapes, validateRegistration, validateUrl };
|