@tinyclaw/types 1.0.1-dev.1cd2fca
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/README.md +19 -0
- package/dist/index.d.ts +562 -0
- package/dist/index.js +79 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @tinyclaw/types
|
|
2
|
+
|
|
3
|
+
Shared TypeScript type definitions for [Tiny Claw](https://github.com/warengonzaga/tinyclaw) — your autonomous AI companion.
|
|
4
|
+
|
|
5
|
+
Provides all core interfaces and types (Message, ToolCall, LLMResponse, StreamEvent, Provider, Database, MemoryEngine, etc.) used across the monorepo.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @tinyclaw/types
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Part of Tiny Claw
|
|
14
|
+
|
|
15
|
+
This package is part of the [Tiny Claw](https://github.com/warengonzaga/tinyclaw) monorepo.
|
|
16
|
+
|
|
17
|
+
## License
|
|
18
|
+
|
|
19
|
+
GPL-3.0 — see [LICENSE](../../LICENSE) for details.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
export type QueryTier = 'simple' | 'moderate' | 'complex' | 'reasoning';
|
|
2
|
+
export interface Message {
|
|
3
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
4
|
+
content: string;
|
|
5
|
+
toolCalls?: ToolCall[];
|
|
6
|
+
toolCallId?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ToolCall {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
arguments: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
export interface LLMResponse {
|
|
14
|
+
type: 'text' | 'tool_calls';
|
|
15
|
+
content?: string;
|
|
16
|
+
toolCalls?: ToolCall[];
|
|
17
|
+
}
|
|
18
|
+
export interface StreamEvent {
|
|
19
|
+
type: 'text' | 'tool_start' | 'tool_result' | 'done' | 'error' | 'delegation_start' | 'delegation_complete' | 'background_start' | 'background_update';
|
|
20
|
+
content?: string;
|
|
21
|
+
tool?: string;
|
|
22
|
+
result?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
/** Delegation metadata (present on delegation_* events) */
|
|
25
|
+
delegation?: {
|
|
26
|
+
agentId?: string;
|
|
27
|
+
role?: string;
|
|
28
|
+
task?: string;
|
|
29
|
+
taskId?: string;
|
|
30
|
+
tier?: string;
|
|
31
|
+
isReuse?: boolean;
|
|
32
|
+
success?: boolean;
|
|
33
|
+
status?: string;
|
|
34
|
+
background?: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export type StreamCallback = (event: StreamEvent) => void;
|
|
38
|
+
export interface Provider {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
chat(messages: Message[], tools?: Tool[]): Promise<LLMResponse>;
|
|
42
|
+
isAvailable(): Promise<boolean>;
|
|
43
|
+
}
|
|
44
|
+
export interface Tool {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
parameters: Record<string, unknown>;
|
|
48
|
+
execute(args: Record<string, unknown>): Promise<string>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Authority tier determines what a user is allowed to do.
|
|
52
|
+
*
|
|
53
|
+
* - **owner**: Full control — config, secrets, heartware, delegation, model switching, tools.
|
|
54
|
+
* There is exactly one owner per Tiny Claw instance (the "assigned human").
|
|
55
|
+
* - **friend**: Chat only — Tiny Claw is friendly and remembers preferences,
|
|
56
|
+
* but refuses commands that modify its internals or take action on the owner's behalf.
|
|
57
|
+
*/
|
|
58
|
+
export type AuthorityTier = 'owner' | 'friend';
|
|
59
|
+
/**
|
|
60
|
+
* Owner authority configuration stored in config.
|
|
61
|
+
*
|
|
62
|
+
* Set during first-time claim flow: Tiny Claw generates a claim token on boot,
|
|
63
|
+
* the first person to enter it in the web UI becomes the owner.
|
|
64
|
+
*/
|
|
65
|
+
export interface OwnerAuthority {
|
|
66
|
+
/** The userId of the owner (e.g. 'web:owner', 'discord:123456'). */
|
|
67
|
+
ownerId: string;
|
|
68
|
+
/** SHA-256 hash of the persistent session token (never store raw tokens). */
|
|
69
|
+
sessionTokenHash: string;
|
|
70
|
+
/** Timestamp when ownership was claimed. */
|
|
71
|
+
claimedAt: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Sensitive tools that only the owner may invoke.
|
|
75
|
+
* Non-owner users receive a polite refusal when these are called.
|
|
76
|
+
*/
|
|
77
|
+
export declare const OWNER_ONLY_TOOLS: ReadonlySet<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Check whether a userId has owner authority.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isOwner(userId: string, ownerId: string | undefined): boolean;
|
|
82
|
+
export interface AgentContext {
|
|
83
|
+
db: Database;
|
|
84
|
+
provider: Provider;
|
|
85
|
+
learning: LearningEngine;
|
|
86
|
+
tools: Tool[];
|
|
87
|
+
heartwareContext?: string;
|
|
88
|
+
secrets?: SecretsManagerInterface;
|
|
89
|
+
configManager?: ConfigManagerInterface;
|
|
90
|
+
/** The model tag currently in use (e.g. 'kimi-k2.5:cloud'). */
|
|
91
|
+
modelName?: string;
|
|
92
|
+
/** Human-readable provider name (e.g. 'Ollama Cloud'). */
|
|
93
|
+
providerName?: string;
|
|
94
|
+
/** The userId of the instance owner. */
|
|
95
|
+
ownerId?: string;
|
|
96
|
+
/** Adaptive memory engine (v3) — episodic memory + FTS5 + temporal decay. */
|
|
97
|
+
memory?: MemoryEngine;
|
|
98
|
+
/** Runtime SHIELD.md enforcement engine. */
|
|
99
|
+
shield?: ShieldEngine;
|
|
100
|
+
/** Delegation v2 subsystems (lifecycle, templates, background runner). */
|
|
101
|
+
delegation?: {
|
|
102
|
+
lifecycle: unknown;
|
|
103
|
+
templates: unknown;
|
|
104
|
+
background: {
|
|
105
|
+
getUndelivered(userId: string): BackgroundTask[];
|
|
106
|
+
markDelivered(taskId: string): void;
|
|
107
|
+
cancelAll(): void;
|
|
108
|
+
cleanupStale(olderThanMs: number): number;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
/** Compaction engine — tiered compression of conversation history. */
|
|
112
|
+
compactor?: {
|
|
113
|
+
compactIfNeeded(userId: string, provider: Provider): Promise<unknown>;
|
|
114
|
+
getLatestSummary(userId: string): string | null;
|
|
115
|
+
estimateTokens(text: string): number;
|
|
116
|
+
};
|
|
117
|
+
/** Pre-built system prompt section about available software updates. */
|
|
118
|
+
updateContext?: string;
|
|
119
|
+
}
|
|
120
|
+
export interface Database {
|
|
121
|
+
saveMessage(userId: string, role: string, content: string): void;
|
|
122
|
+
getHistory(userId: string, limit?: number): Message[];
|
|
123
|
+
getMessageCount(userId: string): number;
|
|
124
|
+
/** Return message timestamps ordered ascending (oldest first). */
|
|
125
|
+
getMessageTimestamps(userId: string): number[];
|
|
126
|
+
deleteMessagesBefore(userId: string, beforeTimestamp: number): void;
|
|
127
|
+
deleteMessagesForUser(userId: string): void;
|
|
128
|
+
saveCompaction(userId: string, summary: string, replacedBefore: number): void;
|
|
129
|
+
getLatestCompaction(userId: string): CompactionRecord | null;
|
|
130
|
+
saveMemory(userId: string, key: string, value: string): void;
|
|
131
|
+
getMemory(userId: string): Record<string, string>;
|
|
132
|
+
saveSubAgent(record: SubAgentRecord): void;
|
|
133
|
+
getSubAgent(id: string): SubAgentRecord | null;
|
|
134
|
+
getActiveSubAgents(userId: string): SubAgentRecord[];
|
|
135
|
+
getAllSubAgents(userId: string, includeDeleted?: boolean): SubAgentRecord[];
|
|
136
|
+
updateSubAgent(id: string, updates: Partial<SubAgentRecord>): void;
|
|
137
|
+
deleteExpiredSubAgents(beforeTimestamp: number): number;
|
|
138
|
+
archiveStaleSuspended(inactiveBefore: number): number;
|
|
139
|
+
saveRoleTemplate(template: RoleTemplate): void;
|
|
140
|
+
getRoleTemplate(id: string): RoleTemplate | null;
|
|
141
|
+
getRoleTemplates(userId: string): RoleTemplate[];
|
|
142
|
+
updateRoleTemplate(id: string, updates: Partial<RoleTemplate>): void;
|
|
143
|
+
deleteRoleTemplate(id: string): void;
|
|
144
|
+
saveBackgroundTask(record: BackgroundTask): void;
|
|
145
|
+
updateBackgroundTask(id: string, status: string, result: string | null, completedAt: number | null): void;
|
|
146
|
+
getUndeliveredTasks(userId: string): BackgroundTask[];
|
|
147
|
+
getUserBackgroundTasks(userId: string): BackgroundTask[];
|
|
148
|
+
getBackgroundTask(id: string): BackgroundTask | null;
|
|
149
|
+
markTaskDelivered(id: string): void;
|
|
150
|
+
getStaleBackgroundTasks(olderThanMs: number): BackgroundTask[];
|
|
151
|
+
saveEpisodicEvent(record: EpisodicRecord): void;
|
|
152
|
+
getEpisodicEvent(id: string): EpisodicRecord | null;
|
|
153
|
+
getEpisodicEvents(userId: string, limit?: number): EpisodicRecord[];
|
|
154
|
+
updateEpisodicEvent(id: string, updates: Partial<EpisodicRecord>): void;
|
|
155
|
+
deleteEpisodicEvents(ids: string[]): void;
|
|
156
|
+
searchEpisodicFTS(query: string, userId: string, limit?: number): Array<{
|
|
157
|
+
id: string;
|
|
158
|
+
rank: number;
|
|
159
|
+
}>;
|
|
160
|
+
decayEpisodicImportance(userId: string, olderThanDays: number, decayFactor: number): number;
|
|
161
|
+
pruneEpisodicEvents(userId: string, maxImportance: number, maxAccessCount: number, olderThanMs: number): number;
|
|
162
|
+
saveTaskMetric(record: TaskMetricRecord): void;
|
|
163
|
+
getTaskMetrics(taskType: string, tier: string, limit?: number): TaskMetricRecord[];
|
|
164
|
+
saveBlackboardEntry(entry: BlackboardEntry): void;
|
|
165
|
+
getBlackboardEntry(id: string): BlackboardEntry | null;
|
|
166
|
+
getBlackboardProposals(problemId: string): BlackboardEntry[];
|
|
167
|
+
getActiveProblems(userId: string): BlackboardEntry[];
|
|
168
|
+
resolveBlackboardProblem(problemId: string, synthesis: string): void;
|
|
169
|
+
cleanupBlackboard(olderThanMs: number): number;
|
|
170
|
+
close(): void;
|
|
171
|
+
}
|
|
172
|
+
export interface SubAgentRecord {
|
|
173
|
+
id: string;
|
|
174
|
+
userId: string;
|
|
175
|
+
role: string;
|
|
176
|
+
systemPrompt: string;
|
|
177
|
+
toolsGranted: string[];
|
|
178
|
+
tierPreference: QueryTier | null;
|
|
179
|
+
status: 'active' | 'suspended' | 'soft_deleted';
|
|
180
|
+
performanceScore: number;
|
|
181
|
+
totalTasks: number;
|
|
182
|
+
successfulTasks: number;
|
|
183
|
+
templateId: string | null;
|
|
184
|
+
createdAt: number;
|
|
185
|
+
lastActiveAt: number;
|
|
186
|
+
deletedAt: number | null;
|
|
187
|
+
}
|
|
188
|
+
export interface RoleTemplate {
|
|
189
|
+
id: string;
|
|
190
|
+
userId: string;
|
|
191
|
+
name: string;
|
|
192
|
+
roleDescription: string;
|
|
193
|
+
defaultTools: string[];
|
|
194
|
+
defaultTier: QueryTier | null;
|
|
195
|
+
timesUsed: number;
|
|
196
|
+
avgPerformance: number;
|
|
197
|
+
tags: string[];
|
|
198
|
+
createdAt: number;
|
|
199
|
+
updatedAt: number;
|
|
200
|
+
}
|
|
201
|
+
export interface BackgroundTask {
|
|
202
|
+
id: string;
|
|
203
|
+
userId: string;
|
|
204
|
+
agentId: string;
|
|
205
|
+
taskDescription: string;
|
|
206
|
+
status: 'running' | 'completed' | 'failed' | 'delivered';
|
|
207
|
+
result: string | null;
|
|
208
|
+
startedAt: number;
|
|
209
|
+
completedAt: number | null;
|
|
210
|
+
deliveredAt: number | null;
|
|
211
|
+
}
|
|
212
|
+
export interface CompactionRecord {
|
|
213
|
+
id: number;
|
|
214
|
+
userId: string;
|
|
215
|
+
summary: string;
|
|
216
|
+
replacedBefore: number;
|
|
217
|
+
createdAt: number;
|
|
218
|
+
}
|
|
219
|
+
export type EpisodicEventType = 'task_completed' | 'preference_learned' | 'correction' | 'delegation_result' | 'fact_stored';
|
|
220
|
+
export interface EpisodicRecord {
|
|
221
|
+
id: string;
|
|
222
|
+
userId: string;
|
|
223
|
+
eventType: EpisodicEventType;
|
|
224
|
+
content: string;
|
|
225
|
+
outcome: string | null;
|
|
226
|
+
importance: number;
|
|
227
|
+
accessCount: number;
|
|
228
|
+
createdAt: number;
|
|
229
|
+
lastAccessedAt: number;
|
|
230
|
+
}
|
|
231
|
+
export interface MemorySearchResult {
|
|
232
|
+
id: string;
|
|
233
|
+
content: string;
|
|
234
|
+
relevanceScore: number;
|
|
235
|
+
source: 'episodic' | 'key_value';
|
|
236
|
+
}
|
|
237
|
+
export interface MemoryEngine {
|
|
238
|
+
/** Store an episodic event. */
|
|
239
|
+
recordEvent(userId: string, event: {
|
|
240
|
+
type: EpisodicEventType;
|
|
241
|
+
content: string;
|
|
242
|
+
outcome?: string;
|
|
243
|
+
importance?: number;
|
|
244
|
+
}): string;
|
|
245
|
+
/** Search memory using hybrid scoring: FTS5 BM25 + temporal decay + importance. */
|
|
246
|
+
search(userId: string, query: string, limit?: number): MemorySearchResult[];
|
|
247
|
+
/** Consolidate: merge duplicates, prune contradictions, decay old memories. */
|
|
248
|
+
consolidate(userId: string): {
|
|
249
|
+
merged: number;
|
|
250
|
+
pruned: number;
|
|
251
|
+
decayed: number;
|
|
252
|
+
};
|
|
253
|
+
/** Get context string for injection into agent system prompt. */
|
|
254
|
+
getContextForAgent(userId: string, query?: string): string;
|
|
255
|
+
/** Strengthen a memory (bump access_count + last_accessed_at). */
|
|
256
|
+
reinforce(memoryId: string): void;
|
|
257
|
+
/** Get a single episodic record by ID. */
|
|
258
|
+
getEvent(id: string): EpisodicRecord | null;
|
|
259
|
+
/** Get all episodic records for a user. */
|
|
260
|
+
getEvents(userId: string, limit?: number): EpisodicRecord[];
|
|
261
|
+
}
|
|
262
|
+
export interface TaskMetricRecord {
|
|
263
|
+
id: string;
|
|
264
|
+
userId: string;
|
|
265
|
+
taskType: string;
|
|
266
|
+
tier: string;
|
|
267
|
+
durationMs: number;
|
|
268
|
+
iterations: number;
|
|
269
|
+
success: boolean;
|
|
270
|
+
createdAt: number;
|
|
271
|
+
}
|
|
272
|
+
export interface BlackboardEntry {
|
|
273
|
+
id: string;
|
|
274
|
+
userId: string;
|
|
275
|
+
problemId: string;
|
|
276
|
+
problemText: string | null;
|
|
277
|
+
agentId: string | null;
|
|
278
|
+
agentRole: string | null;
|
|
279
|
+
proposal: string | null;
|
|
280
|
+
confidence: number;
|
|
281
|
+
synthesis: string | null;
|
|
282
|
+
status: 'open' | 'resolved';
|
|
283
|
+
createdAt: number;
|
|
284
|
+
}
|
|
285
|
+
export interface LearningEngine {
|
|
286
|
+
analyze(userMessage: string, assistantMessage: string, history: Message[]): void;
|
|
287
|
+
getContext(): LearnedContext;
|
|
288
|
+
injectIntoPrompt(basePrompt: string, context: LearnedContext): string;
|
|
289
|
+
}
|
|
290
|
+
export interface LearnedContext {
|
|
291
|
+
preferences: string;
|
|
292
|
+
patterns: string;
|
|
293
|
+
recentCorrections: string;
|
|
294
|
+
}
|
|
295
|
+
export interface PulseJob {
|
|
296
|
+
id: string;
|
|
297
|
+
schedule: string;
|
|
298
|
+
handler: () => Promise<void>;
|
|
299
|
+
lastRun?: number;
|
|
300
|
+
/** When true, the handler fires immediately on start (not just on interval). */
|
|
301
|
+
runOnStart?: boolean;
|
|
302
|
+
/** Internal flag — true while handler() is executing; prevents overlapping runs. */
|
|
303
|
+
isRunning?: boolean;
|
|
304
|
+
}
|
|
305
|
+
export interface TinyClawConfig {
|
|
306
|
+
dataDir?: string;
|
|
307
|
+
provider?: Provider;
|
|
308
|
+
tools?: Tool[];
|
|
309
|
+
secrets?: {
|
|
310
|
+
/** Explicit path to secrets storage directory (defaults to ~/.secrets-engine/) */
|
|
311
|
+
path?: string;
|
|
312
|
+
};
|
|
313
|
+
config?: {
|
|
314
|
+
/** Override the config storage directory (defaults to ~/.tinyclaw/data/) */
|
|
315
|
+
cwd?: string;
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Configuration for the ConfigManager factory
|
|
320
|
+
*/
|
|
321
|
+
export interface ConfigManagerConfig {
|
|
322
|
+
/** Override the config storage directory (defaults to ~/.tinyclaw/data/) */
|
|
323
|
+
readonly cwd?: string;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Contract for the ConfigManager wrapper.
|
|
327
|
+
* Mirrors config-engine's public API through a controlled interface.
|
|
328
|
+
*/
|
|
329
|
+
export interface ConfigManagerInterface {
|
|
330
|
+
/** Get a config value by dot-notation key */
|
|
331
|
+
get<V = unknown>(key: string, defaultValue?: V): V | undefined;
|
|
332
|
+
/** Check if a config key exists */
|
|
333
|
+
has(key: string): boolean;
|
|
334
|
+
/** Set a config value by dot-notation key, or set multiple values via object */
|
|
335
|
+
set(key: string, value: unknown): void;
|
|
336
|
+
set(object: Record<string, unknown>): void;
|
|
337
|
+
/** Delete a config key */
|
|
338
|
+
delete(key: string): void;
|
|
339
|
+
/** Reset specific keys to their defaults */
|
|
340
|
+
reset(...keys: string[]): void;
|
|
341
|
+
/** Clear all config and restore defaults */
|
|
342
|
+
clear(): void;
|
|
343
|
+
/** Get the full config snapshot */
|
|
344
|
+
readonly store: Record<string, unknown>;
|
|
345
|
+
/** Number of top-level config entries */
|
|
346
|
+
readonly size: number;
|
|
347
|
+
/** Absolute path to the config database file */
|
|
348
|
+
readonly path: string;
|
|
349
|
+
/** Watch a specific key for changes */
|
|
350
|
+
onDidChange<V = unknown>(key: string, callback: (newValue?: V, oldValue?: V) => void): () => void;
|
|
351
|
+
/** Watch the entire config for any change */
|
|
352
|
+
onDidAnyChange(callback: (newValue?: Record<string, unknown>, oldValue?: Record<string, unknown>) => void): () => void;
|
|
353
|
+
/** Close the underlying config engine */
|
|
354
|
+
close(): void;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Configuration for the SecretsManager
|
|
358
|
+
*/
|
|
359
|
+
export interface SecretsConfig {
|
|
360
|
+
/** Explicit path to the secrets storage directory */
|
|
361
|
+
readonly path?: string;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Contract for the SecretsManager wrapper
|
|
365
|
+
*/
|
|
366
|
+
export interface SecretsManagerInterface {
|
|
367
|
+
/** Store or overwrite a secret */
|
|
368
|
+
store(key: string, value: string): Promise<void>;
|
|
369
|
+
/** Check if a secret exists (no decryption) */
|
|
370
|
+
check(key: string): Promise<boolean>;
|
|
371
|
+
/** Retrieve a decrypted secret value, or null if missing */
|
|
372
|
+
retrieve(key: string): Promise<string | null>;
|
|
373
|
+
/** List secret key names matching an optional glob pattern */
|
|
374
|
+
list(pattern?: string): Promise<string[]>;
|
|
375
|
+
/** Convenience: resolve a provider API key by provider name */
|
|
376
|
+
resolveProviderKey(providerName: string): Promise<string | null>;
|
|
377
|
+
/** Close the underlying secrets engine */
|
|
378
|
+
close(): Promise<void>;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Well-known key prefixes for structured secret storage.
|
|
382
|
+
*
|
|
383
|
+
* Provider API keys follow: `provider.<name>.apiKey`
|
|
384
|
+
* Example: `provider.ollama.apiKey`, `provider.openai.apiKey`
|
|
385
|
+
*/
|
|
386
|
+
export declare const SECRET_KEY_PREFIXES: {
|
|
387
|
+
readonly provider: "provider";
|
|
388
|
+
readonly channel: "channel";
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* Build a provider API key following the naming convention
|
|
392
|
+
*/
|
|
393
|
+
export declare function buildProviderKeyName(providerName: string): string;
|
|
394
|
+
/**
|
|
395
|
+
* Build a channel token key following the naming convention
|
|
396
|
+
*/
|
|
397
|
+
export declare function buildChannelKeyName(channelName: string): string;
|
|
398
|
+
/** Common metadata shared by all plugin types. */
|
|
399
|
+
export interface PluginMeta {
|
|
400
|
+
/** npm package name, e.g. "@tinyclaw/plugin-channel-discord" */
|
|
401
|
+
readonly id: string;
|
|
402
|
+
/** Human-readable name, e.g. "Discord" */
|
|
403
|
+
readonly name: string;
|
|
404
|
+
/** Short description shown at startup */
|
|
405
|
+
readonly description: string;
|
|
406
|
+
/** Plugin type discriminant */
|
|
407
|
+
readonly type: 'channel' | 'provider' | 'tools';
|
|
408
|
+
/** Plugin semver */
|
|
409
|
+
readonly version: string;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* A channel plugin connects an external messaging platform to the agent loop.
|
|
413
|
+
*
|
|
414
|
+
* Lifecycle:
|
|
415
|
+
* 1. `getPairingTools()` — called during boot to merge pairing tools
|
|
416
|
+
* 2. `start(context)` — called after agentContext is built
|
|
417
|
+
* 3. The plugin drives messages into the agent via `context.enqueue`
|
|
418
|
+
* 4. `stop()` — called during graceful shutdown
|
|
419
|
+
*/
|
|
420
|
+
export interface ChannelPlugin extends PluginMeta {
|
|
421
|
+
readonly type: 'channel';
|
|
422
|
+
/** Boot the channel. */
|
|
423
|
+
start(context: PluginRuntimeContext): Promise<void>;
|
|
424
|
+
/** Tear down — disconnect from platform, flush any pending state. */
|
|
425
|
+
stop(): Promise<void>;
|
|
426
|
+
/**
|
|
427
|
+
* Return pairing tools that the agent can invoke to configure this channel.
|
|
428
|
+
* These tools are merged into AgentContext.tools before the agent loop starts.
|
|
429
|
+
*/
|
|
430
|
+
getPairingTools?(secrets: SecretsManagerInterface, configManager: ConfigManagerInterface): Tool[];
|
|
431
|
+
}
|
|
432
|
+
/** A provider plugin registers an additional LLM provider. */
|
|
433
|
+
export interface ProviderPlugin extends PluginMeta {
|
|
434
|
+
readonly type: 'provider';
|
|
435
|
+
/** Create and return an initialized Provider instance. */
|
|
436
|
+
createProvider(secrets: SecretsManagerInterface): Promise<Provider>;
|
|
437
|
+
/** Optional pairing tools for conversational setup (API key, model config). */
|
|
438
|
+
getPairingTools?(secrets: SecretsManagerInterface, configManager: ConfigManagerInterface): Tool[];
|
|
439
|
+
}
|
|
440
|
+
/** A tools plugin contributes additional agent tools. */
|
|
441
|
+
export interface ToolsPlugin extends PluginMeta {
|
|
442
|
+
readonly type: 'tools';
|
|
443
|
+
/** Return the tools this plugin contributes. */
|
|
444
|
+
createTools(context: AgentContext): Tool[];
|
|
445
|
+
}
|
|
446
|
+
/** Union type for all plugin variants. */
|
|
447
|
+
export type TinyClawPlugin = ChannelPlugin | ProviderPlugin | ToolsPlugin;
|
|
448
|
+
/**
|
|
449
|
+
* Runtime context injected into channel plugins when they start.
|
|
450
|
+
* Gives channels everything needed to route messages through the agent.
|
|
451
|
+
*/
|
|
452
|
+
export interface PluginRuntimeContext {
|
|
453
|
+
/** Push a message into the session queue and run the agent loop. */
|
|
454
|
+
enqueue(userId: string, message: string): Promise<string>;
|
|
455
|
+
/** The initialized AgentContext. */
|
|
456
|
+
agentContext: AgentContext;
|
|
457
|
+
/** Secrets manager for resolving tokens. */
|
|
458
|
+
secrets: SecretsManagerInterface;
|
|
459
|
+
/** Config manager for reading/writing channel config. */
|
|
460
|
+
configManager: ConfigManagerInterface;
|
|
461
|
+
}
|
|
462
|
+
/** The three enforcement actions defined by the SHIELD.md v0.1 spec. */
|
|
463
|
+
export type ShieldAction = 'block' | 'require_approval' | 'log';
|
|
464
|
+
/**
|
|
465
|
+
* Event scopes that the shield engine can evaluate.
|
|
466
|
+
* Maps 1:1 to the SHIELD.md specification's scope definitions.
|
|
467
|
+
*/
|
|
468
|
+
export type ShieldScope = 'prompt' | 'skill.install' | 'skill.execute' | 'tool.call' | 'network.egress' | 'secrets.read' | 'mcp';
|
|
469
|
+
/** Threat severity levels. */
|
|
470
|
+
export type ThreatSeverity = 'critical' | 'high' | 'medium' | 'low';
|
|
471
|
+
/**
|
|
472
|
+
* Threat categories from the SHIELD.md v0.1 spec.
|
|
473
|
+
*/
|
|
474
|
+
export type ThreatCategory = 'prompt' | 'tool' | 'mcp' | 'memory' | 'supply_chain' | 'vulnerability' | 'fraud' | 'policy_bypass' | 'anomaly' | 'skill' | 'other';
|
|
475
|
+
/**
|
|
476
|
+
* A parsed threat entry from SHIELD.md.
|
|
477
|
+
*/
|
|
478
|
+
export interface ThreatEntry {
|
|
479
|
+
id: string;
|
|
480
|
+
fingerprint: string;
|
|
481
|
+
category: ThreatCategory;
|
|
482
|
+
severity: ThreatSeverity;
|
|
483
|
+
confidence: number;
|
|
484
|
+
action: ShieldAction;
|
|
485
|
+
title: string;
|
|
486
|
+
description: string;
|
|
487
|
+
recommendationAgent: string;
|
|
488
|
+
expiresAt: string | null;
|
|
489
|
+
revoked: boolean;
|
|
490
|
+
revokedAt: string | null;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* An event to evaluate against the shield threat feed.
|
|
494
|
+
*/
|
|
495
|
+
export interface ShieldEvent {
|
|
496
|
+
scope: ShieldScope;
|
|
497
|
+
/** Tool name (for tool.call scope). */
|
|
498
|
+
toolName?: string;
|
|
499
|
+
/** Tool arguments (for tool.call scope). */
|
|
500
|
+
toolArgs?: Record<string, unknown>;
|
|
501
|
+
/** Target domain (for network.egress scope). */
|
|
502
|
+
domain?: string;
|
|
503
|
+
/** Secret key path (for secrets.read scope). */
|
|
504
|
+
secretPath?: string;
|
|
505
|
+
/** Skill/plugin name (for skill.install / skill.execute scope). */
|
|
506
|
+
skillName?: string;
|
|
507
|
+
/** Raw input text (for prompt scope). */
|
|
508
|
+
inputText?: string;
|
|
509
|
+
/** The user ID associated with this event. */
|
|
510
|
+
userId?: string;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* The decision output — maps 1:1 to the SHIELD.md DECISION block format.
|
|
514
|
+
*/
|
|
515
|
+
export interface ShieldDecision {
|
|
516
|
+
action: ShieldAction;
|
|
517
|
+
scope: ShieldScope;
|
|
518
|
+
threatId: string | null;
|
|
519
|
+
fingerprint: string | null;
|
|
520
|
+
matchedOn: string | null;
|
|
521
|
+
matchValue: string | null;
|
|
522
|
+
reason: string;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* A tool call pending human approval via conversational flow.
|
|
526
|
+
*/
|
|
527
|
+
export interface PendingApproval {
|
|
528
|
+
/** The tool call that was blocked. */
|
|
529
|
+
toolCall: ToolCall;
|
|
530
|
+
/** The shield decision that triggered the approval request. */
|
|
531
|
+
decision: ShieldDecision;
|
|
532
|
+
/** Timestamp when approval was requested. */
|
|
533
|
+
createdAt: number;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Runtime shield engine interface.
|
|
537
|
+
*
|
|
538
|
+
* Evaluates events against the parsed SHIELD.md threat feed and returns
|
|
539
|
+
* deterministic decisions following the v0.1 spec.
|
|
540
|
+
*/
|
|
541
|
+
export interface ShieldEngine {
|
|
542
|
+
/** Evaluate an event against active threats. */
|
|
543
|
+
evaluate(event: ShieldEvent): ShieldDecision;
|
|
544
|
+
/** Whether the shield has active threats loaded. */
|
|
545
|
+
isActive(): boolean;
|
|
546
|
+
/** Get all loaded threat entries (for debugging/audit). */
|
|
547
|
+
getThreats(): ThreatEntry[];
|
|
548
|
+
}
|
|
549
|
+
export interface Signal {
|
|
550
|
+
type: 'positive' | 'negative' | 'correction' | 'preference';
|
|
551
|
+
confidence: number;
|
|
552
|
+
context: string;
|
|
553
|
+
learned?: string;
|
|
554
|
+
timestamp: number;
|
|
555
|
+
}
|
|
556
|
+
export interface Pattern {
|
|
557
|
+
category: string;
|
|
558
|
+
preference: string;
|
|
559
|
+
confidence: number;
|
|
560
|
+
examples: string[];
|
|
561
|
+
lastUpdated: number;
|
|
562
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Core type definitions for Tiny Claw
|
|
2
|
+
/**
|
|
3
|
+
* Sensitive tools that only the owner may invoke.
|
|
4
|
+
* Non-owner users receive a polite refusal when these are called.
|
|
5
|
+
*/
|
|
6
|
+
export const OWNER_ONLY_TOOLS = new Set([
|
|
7
|
+
// Heartware modifications
|
|
8
|
+
'heartware_write',
|
|
9
|
+
'identity_update',
|
|
10
|
+
'soul_update',
|
|
11
|
+
'soul_info',
|
|
12
|
+
'soul_explain',
|
|
13
|
+
'preferences_set',
|
|
14
|
+
'bootstrap_complete',
|
|
15
|
+
// System control
|
|
16
|
+
'builtin_model_switch',
|
|
17
|
+
'primary_model_list',
|
|
18
|
+
'primary_model_set',
|
|
19
|
+
'primary_model_clear',
|
|
20
|
+
'tinyclaw_restart',
|
|
21
|
+
// Code execution
|
|
22
|
+
'execute_code',
|
|
23
|
+
// Delegation
|
|
24
|
+
'delegate_task',
|
|
25
|
+
'delegate_background',
|
|
26
|
+
'delegate_to_existing',
|
|
27
|
+
'manage_sub_agent',
|
|
28
|
+
'confirm_task',
|
|
29
|
+
'list_sub_agents',
|
|
30
|
+
// Shell execution
|
|
31
|
+
'run_shell',
|
|
32
|
+
'shell_approve',
|
|
33
|
+
'shell_allow',
|
|
34
|
+
// Config & secrets (pairing tools are dynamically added)
|
|
35
|
+
'config_get',
|
|
36
|
+
'config_set',
|
|
37
|
+
'config_reset',
|
|
38
|
+
'secrets_store',
|
|
39
|
+
'secrets_check',
|
|
40
|
+
'secrets_list',
|
|
41
|
+
// Friends chat management
|
|
42
|
+
'friends_chat_invite',
|
|
43
|
+
'friends_chat_reinvite',
|
|
44
|
+
'friends_chat_revoke',
|
|
45
|
+
'friends_chat_list',
|
|
46
|
+
// Discord channel management
|
|
47
|
+
'discord_pair',
|
|
48
|
+
'discord_unpair',
|
|
49
|
+
]);
|
|
50
|
+
/**
|
|
51
|
+
* Check whether a userId has owner authority.
|
|
52
|
+
*/
|
|
53
|
+
export function isOwner(userId, ownerId) {
|
|
54
|
+
if (!ownerId)
|
|
55
|
+
return false;
|
|
56
|
+
return userId === ownerId;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Well-known key prefixes for structured secret storage.
|
|
60
|
+
*
|
|
61
|
+
* Provider API keys follow: `provider.<name>.apiKey`
|
|
62
|
+
* Example: `provider.ollama.apiKey`, `provider.openai.apiKey`
|
|
63
|
+
*/
|
|
64
|
+
export const SECRET_KEY_PREFIXES = {
|
|
65
|
+
provider: 'provider',
|
|
66
|
+
channel: 'channel',
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Build a provider API key following the naming convention
|
|
70
|
+
*/
|
|
71
|
+
export function buildProviderKeyName(providerName) {
|
|
72
|
+
return `${SECRET_KEY_PREFIXES.provider}.${providerName}.apiKey`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build a channel token key following the naming convention
|
|
76
|
+
*/
|
|
77
|
+
export function buildChannelKeyName(channelName) {
|
|
78
|
+
return `${SECRET_KEY_PREFIXES.channel}.${channelName}.token`;
|
|
79
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tinyclaw/types",
|
|
3
|
+
"version": "1.0.1-dev.1cd2fca",
|
|
4
|
+
"description": "Shared TypeScript type definitions for Tiny Claw",
|
|
5
|
+
"license": "GPL-3.0",
|
|
6
|
+
"author": "Waren Gonzaga",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/warengonzaga/tinyclaw.git",
|
|
16
|
+
"directory": "packages/types"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/warengonzaga/tinyclaw/tree/main/packages/types#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/warengonzaga/tinyclaw/issues"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"tinyclaw",
|
|
24
|
+
"types",
|
|
25
|
+
"typescript"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json"
|
|
29
|
+
}
|
|
30
|
+
}
|