auggy 0.3.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/CHANGELOG.md +96 -0
- package/LICENSE +201 -0
- package/README.md +161 -0
- package/package.json +76 -0
- package/src/agent-card.ts +39 -0
- package/src/agent.ts +283 -0
- package/src/agentmail-client.ts +138 -0
- package/src/augments/bash/index.ts +463 -0
- package/src/augments/bash/skill/SKILL.md +156 -0
- package/src/augments/budgets/budget-store.ts +513 -0
- package/src/augments/budgets/index.ts +134 -0
- package/src/augments/budgets/preamble.ts +93 -0
- package/src/augments/budgets/types.ts +89 -0
- package/src/augments/file-memory/index.ts +71 -0
- package/src/augments/filesystem/index.ts +533 -0
- package/src/augments/filesystem/skill/SKILL.md +142 -0
- package/src/augments/filesystem/skill/references/mount-permissions.md +81 -0
- package/src/augments/layered-memory/extractor/buffer.ts +56 -0
- package/src/augments/layered-memory/extractor/frequency.ts +79 -0
- package/src/augments/layered-memory/extractor/inject-handler.ts +103 -0
- package/src/augments/layered-memory/extractor/parse.ts +75 -0
- package/src/augments/layered-memory/extractor/prompt.md +26 -0
- package/src/augments/layered-memory/index.ts +757 -0
- package/src/augments/layered-memory/skill/SKILL.md +153 -0
- package/src/augments/layered-memory/storage/migrations/README.md +16 -0
- package/src/augments/layered-memory/storage/migrations/supabase-add-fact-fields.sql +9 -0
- package/src/augments/layered-memory/storage/sqlite-store.ts +352 -0
- package/src/augments/layered-memory/storage/supabase-store.ts +263 -0
- package/src/augments/layered-memory/storage/types.ts +98 -0
- package/src/augments/link/index.ts +489 -0
- package/src/augments/link/translate.ts +261 -0
- package/src/augments/notify/adapters/agentmail.ts +70 -0
- package/src/augments/notify/adapters/telegram.ts +60 -0
- package/src/augments/notify/adapters/webhook.ts +55 -0
- package/src/augments/notify/index.ts +284 -0
- package/src/augments/notify/skill/SKILL.md +150 -0
- package/src/augments/org-context/index.ts +721 -0
- package/src/augments/org-context/skill/SKILL.md +96 -0
- package/src/augments/skills/index.ts +103 -0
- package/src/augments/supabase-memory/index.ts +151 -0
- package/src/augments/telegram-transport/index.ts +312 -0
- package/src/augments/telegram-transport/polling.ts +55 -0
- package/src/augments/telegram-transport/webhook.ts +56 -0
- package/src/augments/turn-control/index.ts +61 -0
- package/src/augments/turn-control/skill/SKILL.md +155 -0
- package/src/augments/visitor-auth/email-validation.ts +66 -0
- package/src/augments/visitor-auth/index.ts +779 -0
- package/src/augments/visitor-auth/rate-limiter.ts +90 -0
- package/src/augments/visitor-auth/skill/SKILL.md +55 -0
- package/src/augments/visitor-auth/storage/sqlite-store.ts +398 -0
- package/src/augments/visitor-auth/storage/types.ts +164 -0
- package/src/augments/visitor-auth/types.ts +123 -0
- package/src/augments/visitor-auth/verify-page.ts +179 -0
- package/src/augments/web-fetch/index.ts +331 -0
- package/src/augments/web-fetch/skill/SKILL.md +100 -0
- package/src/cli/agent-index.ts +289 -0
- package/src/cli/augment-catalog.ts +320 -0
- package/src/cli/augment-resolver.ts +597 -0
- package/src/cli/commands/add-skill.ts +194 -0
- package/src/cli/commands/add.ts +87 -0
- package/src/cli/commands/chat.ts +207 -0
- package/src/cli/commands/create.ts +462 -0
- package/src/cli/commands/dev.ts +139 -0
- package/src/cli/commands/eval.ts +180 -0
- package/src/cli/commands/ls.ts +66 -0
- package/src/cli/commands/remove.ts +95 -0
- package/src/cli/commands/restart.ts +40 -0
- package/src/cli/commands/start.ts +123 -0
- package/src/cli/commands/status.ts +104 -0
- package/src/cli/commands/stop.ts +84 -0
- package/src/cli/commands/visitors-revoke.ts +155 -0
- package/src/cli/commands/visitors.ts +101 -0
- package/src/cli/config-parser.ts +1034 -0
- package/src/cli/engine-resolver.ts +68 -0
- package/src/cli/index.ts +178 -0
- package/src/cli/model-picker.ts +89 -0
- package/src/cli/pid-registry.ts +146 -0
- package/src/cli/plist-generator.ts +117 -0
- package/src/cli/resolve-config.ts +56 -0
- package/src/cli/scaffold-skills.ts +158 -0
- package/src/cli/scaffold.ts +291 -0
- package/src/cli/skill-frontmatter.ts +51 -0
- package/src/cli/skill-validator.ts +151 -0
- package/src/cli/types.ts +228 -0
- package/src/cli/yaml-helpers.ts +66 -0
- package/src/engines/_shared/cost.ts +55 -0
- package/src/engines/_shared/schema-normalize.ts +75 -0
- package/src/engines/anthropic/pricing.ts +117 -0
- package/src/engines/anthropic.ts +483 -0
- package/src/engines/openai/pricing.ts +67 -0
- package/src/engines/openai.ts +446 -0
- package/src/engines/openrouter/pricing.ts +83 -0
- package/src/engines/openrouter.ts +185 -0
- package/src/helpers.ts +24 -0
- package/src/http.ts +387 -0
- package/src/index.ts +165 -0
- package/src/kernel/capability-table.ts +172 -0
- package/src/kernel/context-allocator.ts +161 -0
- package/src/kernel/history-manager.ts +198 -0
- package/src/kernel/lifecycle-manager.ts +106 -0
- package/src/kernel/output-validator.ts +35 -0
- package/src/kernel/preamble.ts +23 -0
- package/src/kernel/route-collector.ts +97 -0
- package/src/kernel/timeout.ts +21 -0
- package/src/kernel/tool-selector.ts +47 -0
- package/src/kernel/trace-emitter.ts +66 -0
- package/src/kernel/transport-queue.ts +147 -0
- package/src/kernel/turn-loop.ts +1148 -0
- package/src/memory/context-synthesis.ts +83 -0
- package/src/memory/memory-bus.ts +61 -0
- package/src/memory/registry.ts +80 -0
- package/src/memory/tools.ts +320 -0
- package/src/memory/types.ts +8 -0
- package/src/parts.ts +30 -0
- package/src/scaffold-templates/identity.md +31 -0
- package/src/telegram-client.ts +145 -0
- package/src/tokenizer.ts +14 -0
- package/src/transports/ag-ui-events.ts +253 -0
- package/src/transports/visitor-token.ts +82 -0
- package/src/transports/web-transport.ts +948 -0
- package/src/types.ts +1009 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,1009 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { CostResult } from "./engines/_shared/cost";
|
|
3
|
+
export type { CostResult } from "./engines/_shared/cost";
|
|
4
|
+
|
|
5
|
+
// === Context Types (spec §3) ===
|
|
6
|
+
|
|
7
|
+
export type ContextPlacement = "system" | "preamble" | "assistant-preamble";
|
|
8
|
+
export type ContextProvenance = "identity" | "memory" | "retrieval" | "augment";
|
|
9
|
+
export type ContextPriority = "required" | "high" | "normal" | "low" | "evictable";
|
|
10
|
+
export type EvictionPolicy = "never" | "summarize" | "drop";
|
|
11
|
+
export type ContextOrigin = "operator" | "system" | "agent" | "peer-derived";
|
|
12
|
+
|
|
13
|
+
export interface ContextBlock {
|
|
14
|
+
source: string;
|
|
15
|
+
content: string;
|
|
16
|
+
placement: ContextPlacement;
|
|
17
|
+
provenance: ContextProvenance;
|
|
18
|
+
priority: ContextPriority;
|
|
19
|
+
eviction: EvictionPolicy;
|
|
20
|
+
origin: ContextOrigin;
|
|
21
|
+
ttl?: "turn" | "session" | "persistent";
|
|
22
|
+
visibility?: "public" | "pipeline-only";
|
|
23
|
+
tokenCount?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// === A2A-compatible content types (spec §3, A2A-shaped) ===
|
|
27
|
+
|
|
28
|
+
export type Part =
|
|
29
|
+
| { kind: "text"; text: string }
|
|
30
|
+
| { kind: "file"; uri: string; mimeType?: string; name?: string }
|
|
31
|
+
| { kind: "data"; data: Record<string, unknown> };
|
|
32
|
+
|
|
33
|
+
// === Task lifecycle (A2A-shaped, v1 uses "completed" | "failed" | "canceled") ===
|
|
34
|
+
|
|
35
|
+
export type TaskState =
|
|
36
|
+
| "working"
|
|
37
|
+
| "input-required"
|
|
38
|
+
| "auth-required"
|
|
39
|
+
| "completed"
|
|
40
|
+
| "failed"
|
|
41
|
+
| "canceled"
|
|
42
|
+
| "rejected";
|
|
43
|
+
|
|
44
|
+
// === Memory Provider Contract ===
|
|
45
|
+
|
|
46
|
+
export interface MemoryDefaults {
|
|
47
|
+
mutable: boolean;
|
|
48
|
+
origin: ContextOrigin;
|
|
49
|
+
priority: ContextPriority;
|
|
50
|
+
placement: ContextPlacement;
|
|
51
|
+
eviction: EvictionPolicy;
|
|
52
|
+
ttl?: "turn" | "session" | "persistent";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Provenance origin of a memory entry. Canonical here; storage types alias
|
|
57
|
+
* via MemoryOrigin so the runtime contract and the storage column type
|
|
58
|
+
* stay in lockstep.
|
|
59
|
+
*
|
|
60
|
+
* - "operator" — written by the operator (config-mounted entries, identity)
|
|
61
|
+
* - "peer-derived" — explicit `memory_write` calls from the model on behalf
|
|
62
|
+
* of a peer's request ("save this for me")
|
|
63
|
+
* - "agent-derived" — written by background extraction (auto-save, ADR-018
|
|
64
|
+
* Phase 2; populated by PR β). Paraphrases, not verbatim.
|
|
65
|
+
* - "agent" — direct agent-side writes (rare; reserved for system-internal
|
|
66
|
+
* writes that shouldn't carry "peer-derived" trust)
|
|
67
|
+
*/
|
|
68
|
+
export type MemoryOrigin = "operator" | "peer-derived" | "agent-derived" | "agent";
|
|
69
|
+
|
|
70
|
+
export interface MemoryEntry {
|
|
71
|
+
label: string;
|
|
72
|
+
content: string;
|
|
73
|
+
metadata?: Record<string, unknown>;
|
|
74
|
+
// Provenance — providers that don't track this omit these fields
|
|
75
|
+
peerId?: string;
|
|
76
|
+
trustLevel?: TrustLevel;
|
|
77
|
+
createdAt?: number;
|
|
78
|
+
supersededBy?: string;
|
|
79
|
+
retentionClass?: "operational" | "lesson";
|
|
80
|
+
isVerbatim?: boolean;
|
|
81
|
+
origin?: MemoryOrigin;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface MemoryQueryOpts {
|
|
85
|
+
peerId?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface MemoryWriteOpts {
|
|
89
|
+
peerId?: string;
|
|
90
|
+
trustLevel?: TrustLevel;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface StaticMemoryProvider {
|
|
94
|
+
owns: { kind: "static"; labels: string[] };
|
|
95
|
+
defaults: MemoryDefaults;
|
|
96
|
+
read: (label: string) => Promise<MemoryEntry | null>;
|
|
97
|
+
write?: (label: string, content: string) => Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface NamespaceMemoryProvider {
|
|
101
|
+
owns: { kind: "namespace"; prefix: string };
|
|
102
|
+
defaults: MemoryDefaults;
|
|
103
|
+
search: (query: string, opts?: MemoryQueryOpts) => Promise<MemoryEntry[]>;
|
|
104
|
+
write?: (label: string, content: string, opts?: MemoryWriteOpts) => Promise<void>;
|
|
105
|
+
read?: (label: string) => Promise<MemoryEntry | null>;
|
|
106
|
+
list?: () => Promise<string[]>;
|
|
107
|
+
forget?: (peerId: string) => Promise<number>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type MemoryProviderSpec = StaticMemoryProvider | NamespaceMemoryProvider;
|
|
111
|
+
|
|
112
|
+
// === Tool Types (spec §3) ===
|
|
113
|
+
|
|
114
|
+
export type ToolCategory = "memory" | "search" | "communication" | "meta" | (string & {});
|
|
115
|
+
|
|
116
|
+
export interface ToolExecuteContext {
|
|
117
|
+
turnId: string;
|
|
118
|
+
peer: PeerIdentity | null;
|
|
119
|
+
threadId: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
|
+
export interface Tool<TInput = any> {
|
|
124
|
+
name: string;
|
|
125
|
+
description: string;
|
|
126
|
+
category: ToolCategory;
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
128
|
+
input: z.ZodType<TInput, any, any>;
|
|
129
|
+
inputJsonSchema?: Record<string, unknown>;
|
|
130
|
+
execute: (input: TInput, context?: ToolExecuteContext) => Promise<string | ToolResult>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Structured tool return shape. Augments may return either a plain string
|
|
135
|
+
* (back-compat with all existing tools) OR a ToolResult that lets the tool
|
|
136
|
+
* influence turn lifecycle.
|
|
137
|
+
*
|
|
138
|
+
* The narrowed `terminate.status` union is a type-level guarantee that
|
|
139
|
+
* augments cannot spoof kernel-controlled states (failed/canceled/rejected/
|
|
140
|
+
* auth-required). Those remain owned by the kernel.
|
|
141
|
+
*/
|
|
142
|
+
export interface ToolResult {
|
|
143
|
+
/** What the model sees as the tool's output. Replaces the plain-string return. */
|
|
144
|
+
content: string;
|
|
145
|
+
/** Optional turn-termination directive. */
|
|
146
|
+
terminate?: {
|
|
147
|
+
status: Extract<TaskState, "input-required" | "completed">;
|
|
148
|
+
message?: string;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// === Peer Identity (spec §4) ===
|
|
153
|
+
|
|
154
|
+
export type PeerKind = "human" | "agent" | "system" | "anonymous";
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Trust level for an inbound peer. Determines what they CAN do
|
|
158
|
+
* (capability gating).
|
|
159
|
+
*
|
|
160
|
+
* creator — the deployer of this specific agent. Bypasses budgets.
|
|
161
|
+
* agent — a machine the creator has admitted (shared-secret).
|
|
162
|
+
* public — everyone else (anonymous or recognized via visitor token).
|
|
163
|
+
*
|
|
164
|
+
* v0 ships these three. "person" (verified human, post-OAuth/SSO) is
|
|
165
|
+
* the post-v0 fourth level — reserved in design, not enabled in code.
|
|
166
|
+
*/
|
|
167
|
+
export type TrustLevel = "creator" | "agent" | "public";
|
|
168
|
+
|
|
169
|
+
export interface PeerIdentity {
|
|
170
|
+
id: string;
|
|
171
|
+
kind: PeerKind;
|
|
172
|
+
trustLevel: TrustLevel;
|
|
173
|
+
/**
|
|
174
|
+
* Substate within the `public` trust level. Set by the transport at
|
|
175
|
+
* identity resolution. Differentiates first-contact anonymous visitors
|
|
176
|
+
* from those holding a valid agent-issued visitor token.
|
|
177
|
+
*
|
|
178
|
+
* - "anonymous": no token, ephemeral peer.id (anon-<threadId>).
|
|
179
|
+
* Memory writes attach to ephemeral identity.
|
|
180
|
+
* - "recognized": HMAC-verified visitor token, durable peer.id (vis_*).
|
|
181
|
+
* Memory writes attach to durable identity.
|
|
182
|
+
*
|
|
183
|
+
* Present iff trustLevel === "public". Other trust levels MUST omit it.
|
|
184
|
+
*/
|
|
185
|
+
publicSubstate?: "anonymous" | "recognized";
|
|
186
|
+
sourceAugment: string;
|
|
187
|
+
displayName?: string;
|
|
188
|
+
orgId?: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// === Turn Types (spec §4) ===
|
|
192
|
+
|
|
193
|
+
export type TurnTriggerType = "message" | "scheduled" | "event" | "continuation" | "internal";
|
|
194
|
+
|
|
195
|
+
export interface InboundMessage {
|
|
196
|
+
parts: Part[];
|
|
197
|
+
sourceAugment: string;
|
|
198
|
+
peer: PeerIdentity | null;
|
|
199
|
+
timestamp: number;
|
|
200
|
+
contextId?: string;
|
|
201
|
+
taskId?: string;
|
|
202
|
+
metadata?: Record<string, unknown>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface TurnTrigger {
|
|
206
|
+
type: TurnTriggerType;
|
|
207
|
+
turnId: string;
|
|
208
|
+
threadId?: string;
|
|
209
|
+
contextId?: string;
|
|
210
|
+
taskId?: string;
|
|
211
|
+
timestamp: number;
|
|
212
|
+
source?: string;
|
|
213
|
+
peer?: PeerIdentity | null;
|
|
214
|
+
payload: InboundMessage | Record<string, unknown>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface TurnState {
|
|
218
|
+
turnId: string;
|
|
219
|
+
threadId: string;
|
|
220
|
+
trigger: TurnTrigger;
|
|
221
|
+
peer: PeerIdentity | null;
|
|
222
|
+
toolCallsSoFar: number;
|
|
223
|
+
turnStartedAt: number;
|
|
224
|
+
metadata: Record<string, unknown>;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface OutboundMessage {
|
|
228
|
+
parts: Part[];
|
|
229
|
+
targetAugment?: string;
|
|
230
|
+
targetPeer?: string;
|
|
231
|
+
contextId?: string;
|
|
232
|
+
taskId?: string;
|
|
233
|
+
metadata?: Record<string, unknown>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface ToolCallRecord {
|
|
237
|
+
name: string;
|
|
238
|
+
input: unknown;
|
|
239
|
+
output: string;
|
|
240
|
+
durationMs: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface TurnTrace {
|
|
244
|
+
turnId: string;
|
|
245
|
+
threadId: string;
|
|
246
|
+
timestamp: number;
|
|
247
|
+
duration: number;
|
|
248
|
+
trigger: {
|
|
249
|
+
type: string;
|
|
250
|
+
sourceAugment?: string;
|
|
251
|
+
peerKind?: string;
|
|
252
|
+
trustLevel?: string;
|
|
253
|
+
};
|
|
254
|
+
contextAssembly: {
|
|
255
|
+
augmentBlocks: {
|
|
256
|
+
source: string;
|
|
257
|
+
tokens: number;
|
|
258
|
+
included: boolean;
|
|
259
|
+
evicted: boolean;
|
|
260
|
+
}[];
|
|
261
|
+
preambleTokens: number;
|
|
262
|
+
toolSchemaTokens: number;
|
|
263
|
+
historyTokens: number;
|
|
264
|
+
totalTokens: number;
|
|
265
|
+
budgetUsed: number;
|
|
266
|
+
};
|
|
267
|
+
toolSelection: {
|
|
268
|
+
totalTools: number;
|
|
269
|
+
phase1Used: boolean;
|
|
270
|
+
selectedCategories?: string[];
|
|
271
|
+
mountedTools: string[];
|
|
272
|
+
withheldTools: string[];
|
|
273
|
+
};
|
|
274
|
+
inferenceSteps: {
|
|
275
|
+
model: string;
|
|
276
|
+
inputTokens: number;
|
|
277
|
+
outputTokens: number;
|
|
278
|
+
durationMs: number;
|
|
279
|
+
toolCalls: {
|
|
280
|
+
name: string;
|
|
281
|
+
augment: string;
|
|
282
|
+
durationMs: number;
|
|
283
|
+
approved: boolean;
|
|
284
|
+
}[];
|
|
285
|
+
cost: CostResult;
|
|
286
|
+
}[];
|
|
287
|
+
capabilityChecks: {
|
|
288
|
+
tool: string;
|
|
289
|
+
result: "allowed" | "needs-approval" | "denied";
|
|
290
|
+
}[];
|
|
291
|
+
approvals?: {
|
|
292
|
+
tool: string;
|
|
293
|
+
outcome: "approved" | "denied" | "timeout";
|
|
294
|
+
waitMs: number;
|
|
295
|
+
}[];
|
|
296
|
+
outputValidation?: {
|
|
297
|
+
flagged: boolean;
|
|
298
|
+
reasons: string[];
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface TurnResult {
|
|
303
|
+
turnId: string;
|
|
304
|
+
success: boolean;
|
|
305
|
+
status: TaskState;
|
|
306
|
+
response?: OutboundMessage;
|
|
307
|
+
responses?: OutboundMessage[];
|
|
308
|
+
errorResponse?: string;
|
|
309
|
+
toolCalls: ToolCallRecord[];
|
|
310
|
+
trace: TurnTrace;
|
|
311
|
+
error?: { message: string; source: string };
|
|
312
|
+
/**
|
|
313
|
+
* When status is "rejected", this names the class of rejection so
|
|
314
|
+
* the transport can map to the right HTTP status:
|
|
315
|
+
* - "cap-denied" → HTTP 429 (over budget cap)
|
|
316
|
+
* - "admission-state-failed" → HTTP 5xx (confirm-phase failure)
|
|
317
|
+
* - "engine-error" → HTTP 5xx (engine call threw)
|
|
318
|
+
* - other strings → HTTP 5xx fallback
|
|
319
|
+
*
|
|
320
|
+
* Optional for backward compatibility — older callers and existing
|
|
321
|
+
* rejection sites may not yet set this.
|
|
322
|
+
*/
|
|
323
|
+
errorClass?: string;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// === Transcript + Scheduler (ADR-027) ===
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Snapshot of a completed turn, captured by the kernel and exposed via
|
|
330
|
+
* SchedulerContext.getCompletedTranscript() for background-work augments.
|
|
331
|
+
*
|
|
332
|
+
* Returned by history-manager's kernel-internal getTranscript(turnId).
|
|
333
|
+
* Returns null when the turn was already compacted before retrieval.
|
|
334
|
+
*/
|
|
335
|
+
export interface Transcript {
|
|
336
|
+
turnId: string;
|
|
337
|
+
threadId: string;
|
|
338
|
+
peer: PeerIdentity | null;
|
|
339
|
+
parts: Part[];
|
|
340
|
+
toolCalls: ToolCallRecord[];
|
|
341
|
+
startedAt: number;
|
|
342
|
+
endedAt: number;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Context handed to `Augment.scheduleAfterTurn` (ADR-027). Exposes the
|
|
347
|
+
* narrow surface needed for post-turn background work:
|
|
348
|
+
*
|
|
349
|
+
* - inject(trigger): admit a follow-up turn through the normal turn
|
|
350
|
+
* loop. The follow-up gets its own turnId, runs admission/budgets,
|
|
351
|
+
* fires lifecycle hooks, and surfaces in cost accounting like any
|
|
352
|
+
* other turn.
|
|
353
|
+
* - getCompletedTranscript(): retrieve the just-completed turn's
|
|
354
|
+
* transcript snapshot. Closure-bound to the just-completed turnId;
|
|
355
|
+
* no turnId argument by design (per ADR-027 Decision 3 — arbitrary
|
|
356
|
+
* turnId reads stay kernel-internal at v1.0). Returns null when the
|
|
357
|
+
* turn was already compacted before the hook ran.
|
|
358
|
+
*/
|
|
359
|
+
export interface SchedulerContext {
|
|
360
|
+
inject(trigger: TurnTrigger): Promise<TurnResult>;
|
|
361
|
+
getCompletedTranscript(): Promise<Transcript | null>;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Context handed to `Augment.handleInternalTurn` (ADR-027 Decision 5).
|
|
366
|
+
* Exposes the kernel-resolved threadId + peer for the internal turn so
|
|
367
|
+
* the handler can propagate them when writing to memory or recording
|
|
368
|
+
* side-effects.
|
|
369
|
+
*/
|
|
370
|
+
export interface InternalTurnContext {
|
|
371
|
+
threadId: string;
|
|
372
|
+
peer: PeerIdentity | null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// === Kernel Events (internal — emitted by turn loop, consumed by transports) ===
|
|
376
|
+
|
|
377
|
+
export type KernelEvent =
|
|
378
|
+
| {
|
|
379
|
+
kind: "run_started";
|
|
380
|
+
turnId: string;
|
|
381
|
+
threadId: string;
|
|
382
|
+
contextId?: string;
|
|
383
|
+
taskId?: string;
|
|
384
|
+
}
|
|
385
|
+
| {
|
|
386
|
+
kind: "tool_call_started";
|
|
387
|
+
turnId: string;
|
|
388
|
+
toolCallId: string;
|
|
389
|
+
toolName: string;
|
|
390
|
+
augmentName: string;
|
|
391
|
+
}
|
|
392
|
+
| {
|
|
393
|
+
kind: "tool_call_args";
|
|
394
|
+
turnId: string;
|
|
395
|
+
toolCallId: string;
|
|
396
|
+
args: Record<string, unknown>;
|
|
397
|
+
}
|
|
398
|
+
| {
|
|
399
|
+
kind: "tool_call_result";
|
|
400
|
+
turnId: string;
|
|
401
|
+
toolCallId: string;
|
|
402
|
+
output: string;
|
|
403
|
+
isError: boolean;
|
|
404
|
+
}
|
|
405
|
+
| {
|
|
406
|
+
kind: "text_message";
|
|
407
|
+
turnId: string;
|
|
408
|
+
messageId: string;
|
|
409
|
+
role: "assistant";
|
|
410
|
+
text: string;
|
|
411
|
+
}
|
|
412
|
+
| {
|
|
413
|
+
kind: "text_message_start";
|
|
414
|
+
turnId: string;
|
|
415
|
+
messageId: string;
|
|
416
|
+
role: "assistant";
|
|
417
|
+
}
|
|
418
|
+
| {
|
|
419
|
+
kind: "text_message_delta";
|
|
420
|
+
turnId: string;
|
|
421
|
+
messageId: string;
|
|
422
|
+
delta: string;
|
|
423
|
+
}
|
|
424
|
+
| {
|
|
425
|
+
kind: "text_message_end";
|
|
426
|
+
turnId: string;
|
|
427
|
+
messageId: string;
|
|
428
|
+
}
|
|
429
|
+
| {
|
|
430
|
+
kind: "run_finished";
|
|
431
|
+
turnId: string;
|
|
432
|
+
status: TaskState;
|
|
433
|
+
/**
|
|
434
|
+
* Optional human-visible message that explains the terminal status.
|
|
435
|
+
* Today this is populated only when a tool's `ToolResult.terminate`
|
|
436
|
+
* carries a `message` (e.g. the prompt from `request_input`). The
|
|
437
|
+
* AG-UI translator forwards it as `RUN_FINISHED.result.message`.
|
|
438
|
+
*/
|
|
439
|
+
message?: string;
|
|
440
|
+
}
|
|
441
|
+
| {
|
|
442
|
+
kind: "run_error";
|
|
443
|
+
turnId: string;
|
|
444
|
+
message: string;
|
|
445
|
+
source: string;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
export type KernelEventHandler = (event: KernelEvent) => void;
|
|
449
|
+
|
|
450
|
+
// === Message / History (spec §4) ===
|
|
451
|
+
|
|
452
|
+
export type MessageRole = "user" | "assistant" | "tool_use" | "tool_result";
|
|
453
|
+
|
|
454
|
+
export interface Message {
|
|
455
|
+
id: string;
|
|
456
|
+
role: MessageRole;
|
|
457
|
+
peerId?: string;
|
|
458
|
+
toolCallId?: string;
|
|
459
|
+
content: string;
|
|
460
|
+
timestamp: number;
|
|
461
|
+
tokenCount: number;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// === Model Interface (spec §12) ===
|
|
465
|
+
|
|
466
|
+
export interface ToolDefinition {
|
|
467
|
+
name: string;
|
|
468
|
+
description: string;
|
|
469
|
+
inputSchema: Record<string, unknown>;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export interface AssembledPrompt {
|
|
473
|
+
systemBlocks: string[];
|
|
474
|
+
contextBlocks: string[];
|
|
475
|
+
assistantPreamble?: string[];
|
|
476
|
+
messages: Message[];
|
|
477
|
+
tools: ToolDefinition[];
|
|
478
|
+
toolChoice?: "auto" | "any" | { name: string };
|
|
479
|
+
totalTokens: number;
|
|
480
|
+
evictions: { source: string; priority: ContextPriority; reason: string }[];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export interface ModelResponse {
|
|
484
|
+
content: string;
|
|
485
|
+
toolCalls?: { name: string; arguments: Record<string, unknown> }[];
|
|
486
|
+
inputTokens: number;
|
|
487
|
+
outputTokens: number;
|
|
488
|
+
cacheCreationTokens?: number; // Anthropic-specific: tokens written to prompt cache
|
|
489
|
+
cacheReadTokens?: number; // Anthropic-specific: tokens read from prompt cache
|
|
490
|
+
finishReason: "end_turn" | "tool_use" | "max_tokens";
|
|
491
|
+
costUsd?: number; // populated by adapter when pricing is known; undefined otherwise
|
|
492
|
+
unpricedReason?: string; // set when costUsd is absent, describes why pricing was unavailable
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export type ModelDelta = { kind: "text_delta"; text: string };
|
|
496
|
+
|
|
497
|
+
export interface ModelClient {
|
|
498
|
+
complete(
|
|
499
|
+
prompt: AssembledPrompt,
|
|
500
|
+
opts?: { onDelta?: (delta: ModelDelta) => void },
|
|
501
|
+
): Promise<ModelResponse>;
|
|
502
|
+
countTokens(text: string): number;
|
|
503
|
+
maxContextTokens: number;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// === Storage (spec §5.5) ===
|
|
507
|
+
|
|
508
|
+
export interface Storage {
|
|
509
|
+
get(key: string): Promise<string | null>;
|
|
510
|
+
put(key: string, value: string): Promise<void>;
|
|
511
|
+
delete(key: string): Promise<void>;
|
|
512
|
+
list(prefix: string): Promise<string[]>;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// === Agent Card (A2A-shaped, used for discovery) ===
|
|
516
|
+
|
|
517
|
+
export interface AgentCardProvider {
|
|
518
|
+
name: string;
|
|
519
|
+
version?: string;
|
|
520
|
+
contact?: string;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export interface AgentCardCapabilities {
|
|
524
|
+
streaming: boolean;
|
|
525
|
+
pushNotifications: boolean;
|
|
526
|
+
memory: boolean;
|
|
527
|
+
transport: boolean;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export interface AgentCardSkill {
|
|
531
|
+
name: string;
|
|
532
|
+
description: string;
|
|
533
|
+
category: string;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export interface AgentCard {
|
|
537
|
+
provider: AgentCardProvider;
|
|
538
|
+
purpose?: string;
|
|
539
|
+
capabilities: AgentCardCapabilities;
|
|
540
|
+
skills: AgentCardSkill[];
|
|
541
|
+
interfaces: string[];
|
|
542
|
+
extensions: Record<string, unknown>;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// === Transport (spec §3) ===
|
|
546
|
+
|
|
547
|
+
export interface TransportKernel {
|
|
548
|
+
handleInbound(
|
|
549
|
+
trigger: TurnTrigger,
|
|
550
|
+
options?: { onEvent?: KernelEventHandler },
|
|
551
|
+
): Promise<TurnResult>;
|
|
552
|
+
onOutbound(callback: (peer: PeerIdentity, message: OutboundMessage) => Promise<void>): void;
|
|
553
|
+
getAgentCard(): AgentCard;
|
|
554
|
+
/**
|
|
555
|
+
* Cross-augment HTTP routes collected at `agent.start()` after
|
|
556
|
+
* `lifecycle.boot()`. Returns a frozen array — transports MUST NOT mutate.
|
|
557
|
+
* Transports that don't speak HTTP simply ignore this method.
|
|
558
|
+
*/
|
|
559
|
+
getAugmentRoutes(): readonly AugmentHttpRoute[];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export interface TransportSpec {
|
|
563
|
+
/**
|
|
564
|
+
* Called once at agent boot. The kernel handle is captured for handleInbound
|
|
565
|
+
* dispatch; the augmentName is the operator-chosen runtime name (e.g. "telegram"),
|
|
566
|
+
* which the transport SHOULD use as trigger.source so kernel-emitted outbound
|
|
567
|
+
* messages route back through the agent's outboundHandlers map (keyed by aug.name).
|
|
568
|
+
*/
|
|
569
|
+
register(kernel: TransportKernel, augmentName: string): Promise<void>;
|
|
570
|
+
identify(raw: unknown): PeerIdentity | null;
|
|
571
|
+
concurrency?: number;
|
|
572
|
+
maxQueueDepth?: number;
|
|
573
|
+
rateLimitPerPeer?: { maxPerMinute: number };
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// === Augment HTTP routes (PR γ.1) ===
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* HTTP methods supported by augment-registered routes.
|
|
580
|
+
*
|
|
581
|
+
* v1 limits to GET + POST. PUT/DELETE/PATCH deferred — no current consumer
|
|
582
|
+
* needs them, and a smaller surface reduces audit cost. Add on demand.
|
|
583
|
+
*/
|
|
584
|
+
export type HttpMethod = "GET" | "POST";
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Authentication mode for an augment-registered HTTP route.
|
|
588
|
+
*
|
|
589
|
+
* - `"bearer"` — the route inherits webTransport's bearer-token check (same
|
|
590
|
+
* token that gates `/agent/run`). Recommended default for any route that
|
|
591
|
+
* represents creator-driven action.
|
|
592
|
+
* - `"none"` — the route accepts any caller. Opt-in only; required for
|
|
593
|
+
* public callbacks like email magic-link clicks (PR γ.2 visitorAuth) where
|
|
594
|
+
* the visitor can't supply a bearer token. Boot logs a warning per
|
|
595
|
+
* `auth: "none"` route so operators can't miss them.
|
|
596
|
+
*/
|
|
597
|
+
export type AugmentHttpRouteAuth = "bearer" | "none";
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* One HTTP route registered by an augment. Routes are collected at
|
|
601
|
+
* `agent.start()` AFTER `lifecycle.boot()` succeeds (so `onBoot`-populated
|
|
602
|
+
* route lists are visible) and BEFORE any transport binds a port. Path
|
|
603
|
+
* collisions (vs built-in paths or across augments) throw at `agent.start()`,
|
|
604
|
+
* never silently override.
|
|
605
|
+
*/
|
|
606
|
+
export interface AugmentHttpRoute {
|
|
607
|
+
method: HttpMethod;
|
|
608
|
+
/**
|
|
609
|
+
* Exact-match path. v1 does not support patterns or parameters.
|
|
610
|
+
* Must start with `/`. Reserved paths (cannot be registered):
|
|
611
|
+
* - "/"
|
|
612
|
+
* - "/agent/run"
|
|
613
|
+
* - "/health"
|
|
614
|
+
* - "/.well-known/agent-card.json"
|
|
615
|
+
* Convention: scope under `/<augment-name>/...` to make collisions unlikely.
|
|
616
|
+
*/
|
|
617
|
+
path: string;
|
|
618
|
+
/** Auth mode is required — no implicit default; forces deliberate choice. */
|
|
619
|
+
auth: AugmentHttpRouteAuth;
|
|
620
|
+
/**
|
|
621
|
+
* Optional per-route handler timeout in milliseconds. Default 30_000.
|
|
622
|
+
* Times out → 504. Independent from Bun.serve's connection idleTimeout.
|
|
623
|
+
*/
|
|
624
|
+
timeoutMs?: number;
|
|
625
|
+
/**
|
|
626
|
+
* Optional max body bytes the dispatcher will accept. Default 1_048_576 (1 MB).
|
|
627
|
+
* Over cap → 413 before the handler runs. Enforced by counting actual bytes
|
|
628
|
+
* read from req.body (not trusting content-length, which is bypassable via
|
|
629
|
+
* chunked encoding or omission).
|
|
630
|
+
*/
|
|
631
|
+
maxBodyBytes?: number;
|
|
632
|
+
/**
|
|
633
|
+
* Optional sliding-window rate limit per route (NOT per peer — auth-none
|
|
634
|
+
* routes have no peer). Returns 429 with `Retry-After` when triggered.
|
|
635
|
+
*/
|
|
636
|
+
rateLimit?: {
|
|
637
|
+
maxPerMinute: number;
|
|
638
|
+
};
|
|
639
|
+
/**
|
|
640
|
+
* The handler. Receives the raw Request and an options bag carrying an
|
|
641
|
+
* AbortSignal that fires on timeout. Handlers SHOULD listen for the
|
|
642
|
+
* signal and short-circuit side-effecting work to avoid duplicate effects
|
|
643
|
+
* after a 504. Errors thrown are caught by the dispatcher and surfaced
|
|
644
|
+
* as 500 with an opaque body; the actual error is logged with the route
|
|
645
|
+
* path for triage.
|
|
646
|
+
*/
|
|
647
|
+
handler: (req: Request, opts: { signal: AbortSignal }) => Promise<Response>;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// === Turn Gate (2PC admission) ===
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Pre-dispatch admission gate. Augments declaring `turnGate` participate
|
|
654
|
+
* in two-phase commit (2PC) admission: the augment opens a transaction,
|
|
655
|
+
* stages writes inside it, returns a ticket the kernel uses to confirm
|
|
656
|
+
* (commit) or rollback (discard).
|
|
657
|
+
*
|
|
658
|
+
* The kernel pairs every prepare with exactly one of confirm or rollback.
|
|
659
|
+
* Storage transactions enforce atomicity; the augment cannot leak partial
|
|
660
|
+
* state because the writes only escape into the live state when the
|
|
661
|
+
* kernel signals confirm.
|
|
662
|
+
*
|
|
663
|
+
* v0 NOTE: This contract is FIRST-PARTY ONLY. The kernel cannot
|
|
664
|
+
* mechanically prevent third-party augments from violating the
|
|
665
|
+
* prepare-then-confirm contract (e.g. by writing outside the transaction).
|
|
666
|
+
* v0 ships with the budgets augment as the sole turn-gate; third-party
|
|
667
|
+
* turn-gate augments are out of scope until the contract has more
|
|
668
|
+
* real-world miles.
|
|
669
|
+
*/
|
|
670
|
+
export interface TurnGateProvider {
|
|
671
|
+
/**
|
|
672
|
+
* Stage admission writes inside an open transaction. Returns a ticket
|
|
673
|
+
* the kernel uses to confirm or rollback. The augment evaluates caps
|
|
674
|
+
* using whatever reads it needs, stages reservation rows / rate-limit
|
|
675
|
+
* ticks / etc inside the transaction, and returns either:
|
|
676
|
+
* - { decision: { allow: false, reason }, confirm, rollback }
|
|
677
|
+
* where confirm is a no-op and rollback closes the read transaction.
|
|
678
|
+
* - { decision: { allow: true }, confirm, rollback }
|
|
679
|
+
* where confirm commits the staged writes and rollback discards them.
|
|
680
|
+
*
|
|
681
|
+
* The kernel pairs every prepare with exactly one of confirm/rollback.
|
|
682
|
+
*/
|
|
683
|
+
prepare(args: {
|
|
684
|
+
turnId: string;
|
|
685
|
+
peer: PeerIdentity | null;
|
|
686
|
+
threadId: string;
|
|
687
|
+
trigger: TurnTrigger;
|
|
688
|
+
}): Promise<TurnGateTicket>;
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Post-response cost commit. Receives the cost result; the augment
|
|
692
|
+
* uses this to debit USD totals or mark reservations completed.
|
|
693
|
+
* The CostResult discriminated union forces unpriced-aware handling.
|
|
694
|
+
*
|
|
695
|
+
* Optional. Errors here are logged but do not fail the turn — the
|
|
696
|
+
* response already exists.
|
|
697
|
+
*/
|
|
698
|
+
commit?(args: {
|
|
699
|
+
turnId: string;
|
|
700
|
+
peer: PeerIdentity | null;
|
|
701
|
+
threadId: string;
|
|
702
|
+
cost: CostResult;
|
|
703
|
+
}): Promise<void>;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export interface TurnGateTicket {
|
|
707
|
+
decision: { allow: true } | { allow: false; reason: string };
|
|
708
|
+
/** Commit the staged writes. Idempotent — calling twice is a no-op. */
|
|
709
|
+
confirm(): Promise<void>;
|
|
710
|
+
/** Discard the staged writes. Idempotent — calling twice is a no-op. */
|
|
711
|
+
rollback(): Promise<void>;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// === Augment (spec §3) ===
|
|
715
|
+
|
|
716
|
+
export type AugmentCapability = "transport" | "context" | "tools" | "lifecycle";
|
|
717
|
+
|
|
718
|
+
export interface AugmentConstraints {
|
|
719
|
+
maxToolCallsPerTurn?: number;
|
|
720
|
+
requiresHumanApproval?: string[];
|
|
721
|
+
approvalPolicy?: "block-and-queue" | "skip" | "fail";
|
|
722
|
+
neverExpose?: string[];
|
|
723
|
+
contextTimeoutMs?: number;
|
|
724
|
+
toolTimeoutMs?: number;
|
|
725
|
+
/**
|
|
726
|
+
* Per-trust-level structural constraints. Applied additively on top of the
|
|
727
|
+
* top-level `neverExpose` / `requiresHumanApproval` fields. Top-level rules
|
|
728
|
+
* apply to every peer; per-level rules apply only to the specific level.
|
|
729
|
+
*
|
|
730
|
+
* Example: hide `fs_remove` from public peers but keep it visible to
|
|
731
|
+
* agent and creator:
|
|
732
|
+
* perTrustLevel: { public: { neverExpose: ["fs_remove"] } }
|
|
733
|
+
*
|
|
734
|
+
* Null peer (internal/scheduled triggers) is treated as "creator" trust.
|
|
735
|
+
*/
|
|
736
|
+
perTrustLevel?: Partial<
|
|
737
|
+
Record<
|
|
738
|
+
TrustLevel,
|
|
739
|
+
{
|
|
740
|
+
neverExpose?: string[];
|
|
741
|
+
requiresHumanApproval?: string[];
|
|
742
|
+
}
|
|
743
|
+
>
|
|
744
|
+
>;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
export interface Augment {
|
|
748
|
+
name: string;
|
|
749
|
+
version?: string;
|
|
750
|
+
required?: boolean;
|
|
751
|
+
capabilities?: AugmentCapability[];
|
|
752
|
+
context?: (turn: TurnState, priorContext?: ContextBlock[]) => Promise<ContextBlock[] | string>;
|
|
753
|
+
receivesPriorContext?: boolean;
|
|
754
|
+
tools?: Tool[];
|
|
755
|
+
transport?: TransportSpec;
|
|
756
|
+
/**
|
|
757
|
+
* HTTP routes the augment serves on any HTTP-capable transport (today: webTransport).
|
|
758
|
+
* Collected at `agent.start()` after `onBoot` runs; immutable thereafter.
|
|
759
|
+
* See `AugmentHttpRoute` for the contract.
|
|
760
|
+
*/
|
|
761
|
+
httpRoutes?: AugmentHttpRoute[];
|
|
762
|
+
memory?: MemoryProviderSpec;
|
|
763
|
+
constraints?: AugmentConstraints;
|
|
764
|
+
onBoot?: () => Promise<void>;
|
|
765
|
+
onShutdown?: () => Promise<void>;
|
|
766
|
+
onTurnStart?: (turn: TurnState) => Promise<void>;
|
|
767
|
+
onTurnEnd?: (turn: TurnResult) => Promise<void>;
|
|
768
|
+
onIdle?: () => Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* ADR-027: post-turn background-work hook. Fires after `onTurnEnd` for
|
|
771
|
+
* the just-completed user-facing turn. Receives a `SchedulerContext`
|
|
772
|
+
* with `inject` (admit a follow-up turn through the normal turn loop)
|
|
773
|
+
* and `getCompletedTranscript` (retrieve the just-completed turn's
|
|
774
|
+
* transcript snapshot).
|
|
775
|
+
*
|
|
776
|
+
* Errors thrown from this hook are caught and logged; they NEVER block
|
|
777
|
+
* the user-facing turn or affect the response delivered to the peer.
|
|
778
|
+
* Background work is best-effort by design.
|
|
779
|
+
*
|
|
780
|
+
* Multiple augments registering the hook execute sequentially in
|
|
781
|
+
* declaration order (ADR-027 Decision 2).
|
|
782
|
+
*/
|
|
783
|
+
scheduleAfterTurn?: (result: TurnResult, ctx: SchedulerContext) => Promise<void>;
|
|
784
|
+
/**
|
|
785
|
+
* ADR-027 Decision 5: internal-trigger handler dispatch. When the
|
|
786
|
+
* kernel admits a turn whose `trigger.type === "internal"`, the
|
|
787
|
+
* turn-loop walks the augment list in declaration order and calls
|
|
788
|
+
* each augment's `handleInternalTurn` (if present) with the trigger.
|
|
789
|
+
* Augments that do not recognize the trigger MUST return null —
|
|
790
|
+
* dispatch then continues to the next augment. The first augment to
|
|
791
|
+
* return a non-null TurnResult owns the turn; the standard
|
|
792
|
+
* model-engine + tool-execution path is bypassed and the returned
|
|
793
|
+
* result is the turn's outcome.
|
|
794
|
+
*
|
|
795
|
+
* Augments use trigger.source as the authoritative routing key
|
|
796
|
+
* (e.g. `"layered-memory.autoSave"`). Augments emitting and consuming
|
|
797
|
+
* triggers SHOULD use a dotted prefix matching their augment name to
|
|
798
|
+
* avoid cross-augment collisions.
|
|
799
|
+
*
|
|
800
|
+
* The handler runs WITHIN the admitted turn — turn-gate prepare /
|
|
801
|
+
* confirm, onTurnStart, onTurnEnd, scheduleAfterTurn, and history
|
|
802
|
+
* recording all fire as for any standard turn. The handler is
|
|
803
|
+
* responsible for any LLM call its work needs; cost flows through
|
|
804
|
+
* `runCostCommit` via the standard trace pipeline (push priced
|
|
805
|
+
* inference steps onto `TurnResult.trace.inferenceSteps[]`).
|
|
806
|
+
*
|
|
807
|
+
* Augment authors MUST guard against re-entry — a handler should
|
|
808
|
+
* never synthesize a trigger that re-routes back to itself during
|
|
809
|
+
* the same execution.
|
|
810
|
+
*
|
|
811
|
+
* **Throw contract — load-bearing for budget accuracy.** Handlers
|
|
812
|
+
* MUST NOT throw with side effects. Failure modes (engine error,
|
|
813
|
+
* malformed response, transient network failure) MUST be caught
|
|
814
|
+
* inside the handler and returned as a failed TurnResult that still
|
|
815
|
+
* carries any priced inference steps in `trace.inferenceSteps[]`.
|
|
816
|
+
*
|
|
817
|
+
* If a handler throws after incurring LLM spend, the kernel's
|
|
818
|
+
* catch-block will commit a turn with no recorded cost — budgets
|
|
819
|
+
* sees zero spend for a turn that actually burned money. The kernel
|
|
820
|
+
* logs a structured warning (`[kernel] handleInternalTurn for
|
|
821
|
+
* augment "X" threw; cost may be undercounted ...`) so a misbehaving
|
|
822
|
+
* handler is operator-visible, but the cap-accuracy invariant
|
|
823
|
+
* depends on handlers honoring this contract.
|
|
824
|
+
*/
|
|
825
|
+
handleInternalTurn?: (
|
|
826
|
+
trigger: TurnTrigger,
|
|
827
|
+
ctx: InternalTurnContext,
|
|
828
|
+
) => Promise<TurnResult | null>;
|
|
829
|
+
/**
|
|
830
|
+
* Pre-dispatch admission gate. Kernel calls prepare/confirm/rollback
|
|
831
|
+
* before executing the turn. See TurnGateProvider for the 2PC contract.
|
|
832
|
+
*
|
|
833
|
+
* v0 NOTE: First-party only. The budgets augment is the sole shipped
|
|
834
|
+
* implementation. Third-party turn-gate augments are out of scope
|
|
835
|
+
* until the contract has more real-world miles.
|
|
836
|
+
*/
|
|
837
|
+
turnGate?: TurnGateProvider;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// === Agent Config (spec §8) ===
|
|
841
|
+
|
|
842
|
+
export type CompactionStrategy = "summarize" | "truncate" | "sliding-window";
|
|
843
|
+
|
|
844
|
+
export interface AgentConfig {
|
|
845
|
+
name: string;
|
|
846
|
+
purpose?: string;
|
|
847
|
+
model: string;
|
|
848
|
+
augments: Augment[];
|
|
849
|
+
operators?: string[];
|
|
850
|
+
contextBudget?: {
|
|
851
|
+
historyPercent?: number;
|
|
852
|
+
toolSchemaPercent?: number;
|
|
853
|
+
};
|
|
854
|
+
compactionStrategy?: CompactionStrategy;
|
|
855
|
+
/** Max inference loop iterations per turn. Default 10. */
|
|
856
|
+
maxInferenceLoops?: number;
|
|
857
|
+
/** Tool-choice policy sent to the model. "auto" (default) lets the model
|
|
858
|
+
* decide; "any" forces a tool call; { name } forces a specific tool. */
|
|
859
|
+
toolChoice?: "auto" | "any" | { name: string };
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
export interface AgentHealth {
|
|
863
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
864
|
+
agent: string;
|
|
865
|
+
uptime: number;
|
|
866
|
+
augments: Record<string, { status: "ok" | "degraded" | "failed"; error?: string }>;
|
|
867
|
+
model: { reachable: boolean };
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export interface AgentHandle {
|
|
871
|
+
start(): Promise<void>;
|
|
872
|
+
stop(): Promise<void>;
|
|
873
|
+
ready(): Promise<void>;
|
|
874
|
+
health(): AgentHealth;
|
|
875
|
+
card(): AgentCard;
|
|
876
|
+
inject(trigger: TurnTrigger): Promise<TurnResult>;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// === Notify augment ===
|
|
880
|
+
|
|
881
|
+
export type NotifyAdapterKind = "webhook" | "telegram" | "agentmail";
|
|
882
|
+
|
|
883
|
+
export interface WebhookNotifyDestination {
|
|
884
|
+
name: string;
|
|
885
|
+
transport: "webhook";
|
|
886
|
+
url: string;
|
|
887
|
+
headers?: Record<string, string>;
|
|
888
|
+
/** Optional per-destination rate limit. Falls back to the augment-level global cap when absent. */
|
|
889
|
+
rateLimit?: {
|
|
890
|
+
maxPerHour?: number;
|
|
891
|
+
cooldownMs?: number;
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
export interface TelegramNotifyDestination {
|
|
896
|
+
name: string;
|
|
897
|
+
transport: "telegram";
|
|
898
|
+
botToken: string;
|
|
899
|
+
chatId: number | string;
|
|
900
|
+
parseMode?: "Markdown" | "HTML" | "MarkdownV2";
|
|
901
|
+
/** Optional per-destination rate limit. Falls back to the augment-level global cap when absent. */
|
|
902
|
+
rateLimit?: {
|
|
903
|
+
maxPerHour?: number;
|
|
904
|
+
cooldownMs?: number;
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
export interface AgentMailNotifyDestination {
|
|
909
|
+
name: string;
|
|
910
|
+
transport: "agentmail";
|
|
911
|
+
/** AgentMail API key (Bearer token, prefix `am_`). Resolve via env interpolation in agent.yaml. */
|
|
912
|
+
apiKey: string;
|
|
913
|
+
/** AgentMail inbox ID this notification is sent FROM. */
|
|
914
|
+
inboxId: string;
|
|
915
|
+
/** Recipient email address(es). String or array; adapter normalizes to array. */
|
|
916
|
+
to: string | string[];
|
|
917
|
+
/** Optional subject prefix prepended to the notify summary. e.g. "[Auggy] ". */
|
|
918
|
+
subjectPrefix?: string;
|
|
919
|
+
/** Optional labels applied to the sent message in AgentMail. */
|
|
920
|
+
labels?: string[];
|
|
921
|
+
/** Override the AgentMail API base URL (testing/sandbox). Default: https://api.agentmail.to/v0 */
|
|
922
|
+
apiBaseUrl?: string;
|
|
923
|
+
/** Optional per-destination rate limit. Falls back to the augment-level global cap when absent. */
|
|
924
|
+
rateLimit?: {
|
|
925
|
+
maxPerHour?: number;
|
|
926
|
+
cooldownMs?: number;
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
export type NotifyDestination =
|
|
931
|
+
| WebhookNotifyDestination
|
|
932
|
+
| TelegramNotifyDestination
|
|
933
|
+
| AgentMailNotifyDestination;
|
|
934
|
+
|
|
935
|
+
export interface NotifyRateLimitOptions {
|
|
936
|
+
enabled?: boolean;
|
|
937
|
+
cooldownMs?: number;
|
|
938
|
+
globalMaxPerHour?: number;
|
|
939
|
+
dedupWindowMs?: number;
|
|
940
|
+
dedupThreshold?: number;
|
|
941
|
+
perPeerCooldownMs?: number;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
export interface NotifyAugmentOptions {
|
|
945
|
+
destinations: NotifyDestination[];
|
|
946
|
+
rateLimit?: NotifyRateLimitOptions;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
export interface NotifyPayload {
|
|
950
|
+
summary: string;
|
|
951
|
+
reason?: string;
|
|
952
|
+
visitor?: string;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
export interface NotifyDeliveryResult {
|
|
956
|
+
status: "sent" | "failed";
|
|
957
|
+
detail?: string;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
export interface NotifyAdapter {
|
|
961
|
+
deliver(destination: NotifyDestination, payload: NotifyPayload): Promise<NotifyDeliveryResult>;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// ---------------------------------------------------------------------------
|
|
965
|
+
// Telegram transport
|
|
966
|
+
// ---------------------------------------------------------------------------
|
|
967
|
+
|
|
968
|
+
export type TelegramInboundMode = "polling" | "webhook";
|
|
969
|
+
|
|
970
|
+
export interface TelegramPollingOptions {
|
|
971
|
+
timeoutSec?: number;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
export interface TelegramWebhookOptions {
|
|
975
|
+
publicUrl: string;
|
|
976
|
+
port?: number;
|
|
977
|
+
secretToken: string;
|
|
978
|
+
allowedUpdates?: string[];
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
export interface TelegramAdmittedAgent {
|
|
982
|
+
id: string;
|
|
983
|
+
telegramUserId: number;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
export type TelegramAnonymousIdentityMode = "ephemeral" | "durable";
|
|
987
|
+
|
|
988
|
+
export interface TelegramAuthOptions {
|
|
989
|
+
creatorUserIds?: number[];
|
|
990
|
+
admittedAgents?: TelegramAdmittedAgent[];
|
|
991
|
+
recognizedUserIds?: number[];
|
|
992
|
+
/**
|
|
993
|
+
* peer.id durability for anonymous Telegram peers. Default "ephemeral"
|
|
994
|
+
* matches web's anonymous-ephemeral semantics — peer.id is `tg_anon_<threadId>`,
|
|
995
|
+
* memory dies with thread. "durable" uses `tg_user_<userId>` for cross-session
|
|
996
|
+
* recall; operators opt into this consciously.
|
|
997
|
+
*/
|
|
998
|
+
anonymousIdentityMode?: TelegramAnonymousIdentityMode;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
export interface TelegramTransportOptions {
|
|
1002
|
+
botToken: string;
|
|
1003
|
+
inbound: {
|
|
1004
|
+
mode: TelegramInboundMode;
|
|
1005
|
+
polling?: TelegramPollingOptions;
|
|
1006
|
+
webhook?: TelegramWebhookOptions;
|
|
1007
|
+
};
|
|
1008
|
+
auth: TelegramAuthOptions;
|
|
1009
|
+
}
|