qlogicagent 2.6.0 → 2.7.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.
Files changed (49) hide show
  1. package/dist/agent.js +14 -12
  2. package/dist/cli.js +609 -282
  3. package/dist/index.js +608 -281
  4. package/dist/orchestration.js +15 -15
  5. package/dist/protocol.js +1 -1
  6. package/dist/types/agent/agent.d.ts +3 -0
  7. package/dist/types/agent/tool-loop.d.ts +2 -0
  8. package/dist/types/agent/tunable-defaults.d.ts +18 -1
  9. package/dist/types/agent/types.d.ts +9 -0
  10. package/dist/types/cli/stdio-server.d.ts +42 -6
  11. package/dist/types/cli/tool-bootstrap.d.ts +3 -5
  12. package/dist/types/llm/model-catalog.d.ts +29 -0
  13. package/dist/types/llm/retry.d.ts +1 -1
  14. package/dist/types/orchestration/dag-scheduler.d.ts +46 -0
  15. package/dist/types/orchestration/index.d.ts +1 -1
  16. package/dist/types/orchestration/product-planner.d.ts +146 -0
  17. package/dist/types/orchestration/skill-improvement.d.ts +39 -0
  18. package/dist/types/orchestration/solo-evaluator.d.ts +26 -6
  19. package/dist/types/orchestration/solo-persistence.d.ts +5 -0
  20. package/dist/types/protocol/methods.d.ts +36 -1
  21. package/dist/types/protocol/notifications.d.ts +1 -1
  22. package/dist/types/protocol/wire/acp-protocol.d.ts +7 -0
  23. package/dist/types/protocol/wire/agent-methods.d.ts +1 -1
  24. package/dist/types/protocol/wire/index.d.ts +1 -1
  25. package/dist/types/protocol/wire/memory-provider-lifecycle.d.ts +3 -1
  26. package/dist/types/protocol/wire/notification-payloads.d.ts +52 -3
  27. package/dist/types/runtime/execution/dream-agent.d.ts +32 -5
  28. package/dist/types/runtime/execution/memory-decay.d.ts +17 -5
  29. package/dist/types/runtime/hooks/memory-hooks.d.ts +9 -0
  30. package/dist/types/runtime/infra/acp-types.d.ts +88 -0
  31. package/dist/types/runtime/prompt/environment-context.d.ts +10 -0
  32. package/dist/types/runtime/prompt/index.d.ts +1 -1
  33. package/dist/types/skills/index.d.ts +8 -2
  34. package/dist/types/skills/memory/implicit-extraction.d.ts +58 -0
  35. package/dist/types/skills/memory/local-embedding.d.ts +176 -0
  36. package/dist/types/skills/memory/local-memory-provider.d.ts +197 -0
  37. package/dist/types/skills/memory/local-store.d.ts +254 -0
  38. package/dist/types/skills/memory/memdir.d.ts +6 -1
  39. package/dist/types/skills/memory/memory-provider-factory.d.ts +54 -0
  40. package/dist/types/skills/memory/memory-tool.d.ts +30 -2
  41. package/dist/types/skills/permissions/denial-audit-log.d.ts +52 -0
  42. package/dist/types/skills/permissions/hook-runner.d.ts +14 -4
  43. package/dist/types/skills/skill-system/skill-lifecycle.d.ts +81 -0
  44. package/dist/types/skills/skill-system/skill-validation.d.ts +29 -0
  45. package/dist/types/skills/tools/exec-tool.d.ts +1 -1
  46. package/dist/types/transport/acp-server.d.ts +5 -0
  47. package/package.json +18 -5
  48. package/dist/types/skills/memory/qmemory-adapter.d.ts +0 -55
  49. package/dist/types/skills/memory/qmemory-http-client.d.ts +0 -16
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Local Memory Provider — implements MemoryProvider using local SQLite store.
3
+ *
4
+ * This is the default provider for desktop use. Requires no external service.
5
+ * Uses FTS5 for keyword search and optionally embedding API for vector search.
6
+ *
7
+ * Falls back gracefully:
8
+ * - With embedding API configured: hybrid search (FTS + vector)
9
+ * - Without embedding: FTS-only search (still useful for exact/keyword matches)
10
+ */
11
+ import type { MemoryProvider, MemorySearchResult, MemorySearchOptions, MemoryIngestMessage, MemoryIngestOptions } from "../../protocol/wire/index.js";
12
+ import type { SqliteDatabase } from "./local-store.js";
13
+ import { type LocalEmbeddingConfig } from "./local-embedding.js";
14
+ /** A pre-extracted memory item ready to be stored (no LLM needed). */
15
+ export interface ExtractedMemoryItem {
16
+ text: string;
17
+ category?: string;
18
+ importance?: number;
19
+ speaker?: string;
20
+ event_date?: string;
21
+ tags?: string[];
22
+ }
23
+ export interface LocalMemoryProviderConfig {
24
+ /** Project root for project-level storage (falls back to user-level). */
25
+ projectRoot?: string;
26
+ /** Embedding configuration. If omitted, uses FTS-only search. */
27
+ embedding?: LocalEmbeddingConfig;
28
+ /** User ID prefix for multi-tenant isolation. */
29
+ userIdPrefix?: string;
30
+ /** Factory function to create the SQLite database instance. */
31
+ createDatabase?: (dbPath: string) => SqliteDatabase;
32
+ }
33
+ export declare class LocalMemoryProvider implements MemoryProvider {
34
+ readonly providerId = "qmemory-local";
35
+ private store;
36
+ private embedding;
37
+ private userIdPrefix;
38
+ private dbPath;
39
+ constructor(config: LocalMemoryProviderConfig);
40
+ private resolveUserId;
41
+ search(query: string, userId: string, options?: MemorySearchOptions): Promise<MemorySearchResult[]>;
42
+ ingest(messages: MemoryIngestMessage[], userId: string, options?: MemoryIngestOptions): Promise<void>;
43
+ addText(text: string, userId: string, options?: MemoryIngestOptions & {
44
+ category?: string;
45
+ importance?: number;
46
+ }): Promise<{
47
+ memoriesAdded: number;
48
+ }>;
49
+ remove(memoryId: string): Promise<boolean>;
50
+ /**
51
+ * Ingest pre-extracted memory items (no LLM needed).
52
+ * Compatible with qmemory-adapter's ingestExtracted interface.
53
+ */
54
+ ingestExtracted(items: ExtractedMemoryItem[], userId: string, options?: MemoryIngestOptions): Promise<{
55
+ memoriesAdded: number;
56
+ }>;
57
+ /**
58
+ * Trigger memory decay — multi-strategy (temporal + staleness + noise).
59
+ * Also enforces capacity limit and runs vacuum for space reclamation.
60
+ */
61
+ triggerDecay(userId: string, _maxAgeDays?: number): Promise<{
62
+ decayed: number;
63
+ }>;
64
+ /**
65
+ * Apply feedback to a memory (useful/irrelevant/outdated/wrong).
66
+ * Adjusts importance or archives/deletes based on signal.
67
+ */
68
+ feedback(memoryIds: string[], signal: "useful" | "irrelevant" | "outdated" | "wrong"): Promise<{
69
+ affected: number;
70
+ }>;
71
+ /**
72
+ * Get a user profile value.
73
+ */
74
+ getProfile(userId: string, key: string): string | null;
75
+ /**
76
+ * Set a user profile value (upsert).
77
+ */
78
+ setProfile(userId: string, key: string, value: string): void;
79
+ /**
80
+ * Get all profile entries for a user.
81
+ */
82
+ getAllProfiles(userId: string): Record<string, string>;
83
+ /**
84
+ * Delete a profile entry.
85
+ */
86
+ deleteProfile(userId: string, key: string): boolean;
87
+ /**
88
+ * Get memories within a time range, grouped by day.
89
+ * Powers "what happened last week" type queries.
90
+ */
91
+ getTemporalSlice(userId: string, startMs: number, endMs: number, options?: {
92
+ category?: string;
93
+ limit?: number;
94
+ }): {
95
+ date: string;
96
+ memories: Array<{
97
+ id: string;
98
+ text: string;
99
+ category: string;
100
+ importance: number;
101
+ }>;
102
+ }[];
103
+ /**
104
+ * Get activity summary over recent N days (daily counts + highlights).
105
+ */
106
+ getActivitySummary(userId: string, days?: number): {
107
+ dailyCounts: Array<{
108
+ date: string;
109
+ count: number;
110
+ }>;
111
+ highlights: Array<{
112
+ id: string;
113
+ text: string;
114
+ category: string;
115
+ importance: number;
116
+ date: string;
117
+ }>;
118
+ };
119
+ /**
120
+ * Find memories by event date (±tolerance). For temporal context retrieval.
121
+ */
122
+ findByEventDate(userId: string, targetDate: string, toleranceDays?: number): import("./local-store.js").MemorySearchHit[];
123
+ /**
124
+ * Find related memories (event continuity detection).
125
+ * Given a new memory, finds existing memories that are semantically related
126
+ * (cosine 0.6-0.82) and from the past 14 days. These represent continuations
127
+ * of an ongoing event/thread.
128
+ *
129
+ * Example: "周一面试了字节" → finds "上周投了字节的简历" → linked event chain.
130
+ */
131
+ findRelatedEvents(text: string, userId: string, options?: {
132
+ maxDaysBack?: number;
133
+ minSimilarity?: number;
134
+ maxSimilarity?: number;
135
+ limit?: number;
136
+ }): Promise<Array<{
137
+ id: string;
138
+ text: string;
139
+ score: number;
140
+ date: string;
141
+ }>>;
142
+ /**
143
+ * Synthesize a temporal narrative from memories in a time range.
144
+ * Returns a structured timeline suitable for prompt injection.
145
+ */
146
+ synthesizeTimeline(userId: string, startMs: number, endMs: number): string;
147
+ /**
148
+ * Rerank search results by applying recency boost, access frequency,
149
+ * and importance weighting. No LLM needed — pure scoring heuristics.
150
+ *
151
+ * This goes beyond basic search scoring by considering:
152
+ * - Temporal proximity (recent memories get boosted)
153
+ * - Access frequency (frequently recalled = more relevant)
154
+ * - Category alignment (if preferredCategories specified)
155
+ */
156
+ rerank(results: Array<{
157
+ id: string;
158
+ text: string;
159
+ score: number;
160
+ category?: string;
161
+ metadata?: Record<string, unknown>;
162
+ }>, options?: {
163
+ preferredCategories?: string[];
164
+ recencyBoostDays?: number;
165
+ }): Array<{
166
+ id: string;
167
+ text: string;
168
+ score: number;
169
+ category?: string;
170
+ metadata?: Record<string, unknown>;
171
+ }>;
172
+ /**
173
+ * Health check — always healthy for local store.
174
+ */
175
+ health(): Promise<{
176
+ status: string;
177
+ memoryCount: number;
178
+ dbPath: string;
179
+ }>;
180
+ /**
181
+ * Get memory count for a user.
182
+ */
183
+ count(userId: string): number;
184
+ /**
185
+ * Reset all memories for a user.
186
+ */
187
+ resetUser(userId: string): Promise<number>;
188
+ /**
189
+ * Close the database connection.
190
+ */
191
+ close(): void;
192
+ }
193
+ /**
194
+ * Create a local memory provider (convenience factory).
195
+ * Caller must provide the createDatabase factory to avoid hard dependency on better-sqlite3.
196
+ */
197
+ export declare function createLocalMemoryProvider(config: LocalMemoryProviderConfig): LocalMemoryProvider;
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Local Memory Store — SQLite-backed persistence for qmemory.
3
+ *
4
+ * Ported from Python qmemory's memory_store.py + db.py.
5
+ * Uses better-sqlite3 for synchronous, fast, single-file persistence.
6
+ *
7
+ * Storage location:
8
+ * <project>/.qlogicagent/memory/memories.db (project-level)
9
+ * ~/.qlogicagent/memory/memories.db (user-level fallback)
10
+ *
11
+ * Schema:
12
+ * - memories: core fact storage with optional embedding blob
13
+ * - memories_fts: FTS5 full-text index for keyword search
14
+ * - profiles: user profile KV (future)
15
+ */
16
+ export interface MemoryRecord {
17
+ id: string;
18
+ text: string;
19
+ userId: string;
20
+ category: string;
21
+ importance: number;
22
+ confidence: number;
23
+ source: string;
24
+ sessionId: string;
25
+ eventDate: string;
26
+ tags: string[];
27
+ embedding: Float32Array | null;
28
+ createdAt: number;
29
+ updatedAt: number;
30
+ accessCount: number;
31
+ lastAccessedAt: number;
32
+ isArchived: boolean;
33
+ }
34
+ export interface MemoryInsertInput {
35
+ text: string;
36
+ userId: string;
37
+ category?: string;
38
+ importance?: number;
39
+ source?: string;
40
+ sessionId?: string;
41
+ eventDate?: string;
42
+ tags?: string[];
43
+ embedding?: Float32Array;
44
+ }
45
+ export interface MemorySearchHit {
46
+ id: string;
47
+ text: string;
48
+ score: number;
49
+ category: string;
50
+ importance: number;
51
+ metadata: Record<string, unknown>;
52
+ }
53
+ export interface SqliteDatabase {
54
+ exec(sql: string): void;
55
+ prepare(sql: string): SqliteStatement;
56
+ pragma(pragma: string): unknown;
57
+ close(): void;
58
+ }
59
+ export interface SqliteStatement {
60
+ run(...params: unknown[]): {
61
+ changes: number;
62
+ lastInsertRowid: number | bigint;
63
+ };
64
+ get(...params: unknown[]): unknown;
65
+ all(...params: unknown[]): unknown[];
66
+ }
67
+ export declare class LocalMemoryStore {
68
+ private db;
69
+ constructor(db: SqliteDatabase);
70
+ private initSchema;
71
+ /**
72
+ * Insert a new memory record. Returns the generated ID.
73
+ */
74
+ insert(input: MemoryInsertInput): string;
75
+ /**
76
+ * Full-text search using FTS5. Returns ranked results.
77
+ */
78
+ searchFts(query: string, userId: string, limit?: number): MemorySearchHit[];
79
+ /**
80
+ * Vector similarity search using pre-computed embeddings.
81
+ * Performs brute-force cosine similarity (efficient for <100k records per user).
82
+ */
83
+ searchVector(queryEmbedding: Float32Array, userId: string, limit?: number, minScore?: number): MemorySearchHit[];
84
+ /**
85
+ * Hybrid search: FTS5 + vector similarity, de-duplicated and merged.
86
+ */
87
+ searchHybrid(query: string, queryEmbedding: Float32Array | null, userId: string, limit?: number): MemorySearchHit[];
88
+ /**
89
+ * Get all memories for a user (paginated).
90
+ */
91
+ listByUser(userId: string, page?: number, pageSize?: number, activeOnly?: boolean): MemoryRecord[];
92
+ /**
93
+ * Get a single memory by ID.
94
+ */
95
+ getById(id: string): MemoryRecord | null;
96
+ /**
97
+ * Update memory text and bump updatedAt.
98
+ */
99
+ updateText(id: string, text: string, embedding?: Float32Array): boolean;
100
+ /**
101
+ * Delete a memory by ID.
102
+ */
103
+ delete(id: string): boolean;
104
+ /**
105
+ * Archive a memory (soft-delete: set is_archived=1).
106
+ * Used by dedup gate when a similar but newer memory supersedes an older one.
107
+ */
108
+ archive(id: string): boolean;
109
+ /**
110
+ * Temporal expiry: archive event/plan memories whose event_date has passed
111
+ * beyond a grace period (e.g., "meeting tomorrow" 3 days after it happened).
112
+ */
113
+ decayTemporalExpiry(userId: string, graceDays?: number): number;
114
+ /**
115
+ * Staleness decay: reduce importance of memories not accessed in a long time.
116
+ * Memories accessed recently retain their importance; stale ones degrade.
117
+ */
118
+ decayStaleness(userId: string, staleDays?: number, decayFactor?: number): number;
119
+ /**
120
+ * Noise archival: archive low-importance memories that never got accessed.
121
+ * Memories written by the agent but never recalled are likely noise.
122
+ */
123
+ decayNoiseArchival(userId: string, minAgeDays?: number, maxImportance?: number): number;
124
+ /**
125
+ * Run all decay strategies. Returns total affected count.
126
+ */
127
+ runFullDecay(userId: string, options?: {
128
+ temporalGraceDays?: number;
129
+ staleDays?: number;
130
+ staleDecayFactor?: number;
131
+ noiseMinAgeDays?: number;
132
+ noiseMaxImportance?: number;
133
+ }): {
134
+ temporal: number;
135
+ stale: number;
136
+ noise: number;
137
+ total: number;
138
+ };
139
+ /**
140
+ * Apply feedback signal to a memory, adjusting importance accordingly.
141
+ *
142
+ * Signals:
143
+ * - "useful" → boost importance by +0.15 (capped at 1.0)
144
+ * - "irrelevant" → reduce importance by -0.2
145
+ * - "outdated" → archive immediately
146
+ * - "wrong" → delete immediately
147
+ */
148
+ applyFeedback(memoryId: string, signal: "useful" | "irrelevant" | "outdated" | "wrong"): boolean;
149
+ /**
150
+ * Get a profile value for a user.
151
+ */
152
+ getProfile(userId: string, key: string): string | null;
153
+ /**
154
+ * Set a profile value (upsert).
155
+ */
156
+ setProfile(userId: string, key: string, value: string): void;
157
+ /**
158
+ * Get all profile entries for a user.
159
+ */
160
+ getAllProfiles(userId: string): Record<string, string>;
161
+ /**
162
+ * Delete a profile entry.
163
+ */
164
+ deleteProfile(userId: string, key: string): boolean;
165
+ private profileTableCreated;
166
+ private ensureProfileTable;
167
+ /**
168
+ * Retrieve memories within a time range, grouped by day.
169
+ * Used for "what happened last week" type queries and dream synthesis.
170
+ */
171
+ getTemporalSlice(userId: string, startMs: number, endMs: number, options?: {
172
+ category?: string;
173
+ limit?: number;
174
+ }): Array<{
175
+ date: string;
176
+ memories: Array<{
177
+ id: string;
178
+ text: string;
179
+ category: string;
180
+ importance: number;
181
+ }>;
182
+ }>;
183
+ /**
184
+ * Get memory activity summary over recent N days.
185
+ * Returns daily counts and high-importance entries — used by temporal synthesis.
186
+ */
187
+ getActivitySummary(userId: string, days?: number): {
188
+ dailyCounts: Array<{
189
+ date: string;
190
+ count: number;
191
+ }>;
192
+ highlights: Array<{
193
+ id: string;
194
+ text: string;
195
+ category: string;
196
+ importance: number;
197
+ date: string;
198
+ }>;
199
+ };
200
+ /**
201
+ * Find memories related to a specific event date (±tolerance).
202
+ * Used for temporal context retrieval: "关于上周二的会议" → find memories around that date.
203
+ */
204
+ findByEventDate(userId: string, targetDate: string, toleranceDays?: number): MemorySearchHit[];
205
+ /**
206
+ * Record an access (for importance/relevance boosting).
207
+ */
208
+ recordAccess(id: string): void;
209
+ /**
210
+ * Get total memory count for a user.
211
+ */
212
+ count(userId: string, activeOnly?: boolean): number;
213
+ /**
214
+ * Delete all memories for a user.
215
+ */
216
+ resetUser(userId: string): number;
217
+ /**
218
+ * Run SQLite VACUUM to reclaim space after deletions/archival.
219
+ * Should be called periodically (e.g. after decay cycles).
220
+ */
221
+ vacuum(): void;
222
+ /**
223
+ * Get database size info for capacity monitoring.
224
+ */
225
+ getStorageStats(): {
226
+ pageCount: number;
227
+ pageSize: number;
228
+ totalBytes: number;
229
+ freePages: number;
230
+ };
231
+ /**
232
+ * Export archived memories as JSONL (for cold storage / backup).
233
+ * Deletes exported records from the database to reclaim space.
234
+ */
235
+ exportAndPurgeArchived(userId: string, maxExport?: number): Array<{
236
+ id: string;
237
+ text: string;
238
+ category: string;
239
+ importance: number;
240
+ createdAt: number;
241
+ archivedAt: number;
242
+ tags: string[];
243
+ }>;
244
+ /**
245
+ * Enforce capacity limit: if active memories exceed maxCount,
246
+ * archive the oldest lowest-importance ones.
247
+ */
248
+ enforceCapacityLimit(userId: string, maxCount?: number): number;
249
+ close(): void;
250
+ }
251
+ /**
252
+ * Resolve the database file path for local memory storage.
253
+ */
254
+ export declare function resolveMemoryDbPath(projectRoot?: string): string;
@@ -1,4 +1,4 @@
1
- /** Max chars for INDEX.md to inject into system prompt (CC uses 25KB, we use 12KB). */
1
+ /** Max bytes (UTF-8) for INDEX.md to inject into system prompt (CC uses 25KB, we use 12KB). */
2
2
  export declare const INDEX_MAX_CHARS = 12288;
3
3
  /** Max lines for INDEX.md injection. */
4
4
  export declare const INDEX_MAX_LINES = 200;
@@ -49,6 +49,11 @@ export declare class Memdir {
49
49
  };
50
50
  /** Append a line/entry to INDEX.md. */
51
51
  addToIndex(content: string): Promise<MemdirResult>;
52
+ /**
53
+ * Auto-compact INDEX.md by removing oldest non-structural entries to make room.
54
+ * Returns the compacted content with the new entry appended, or null if impossible.
55
+ */
56
+ private autoCompactIndex;
52
57
  /** Replace text in INDEX.md (str_replace semantics). */
53
58
  replaceInIndex(oldText: string, newText: string): Promise<MemdirResult>;
54
59
  /** Remove text from INDEX.md. */
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Memory Provider Factory — creates local SQLite memory provider.
3
+ *
4
+ * No remote/cloud memory service exists. Memory is always local.
5
+ * This factory is the single integration point for stdio-server.ts.
6
+ */
7
+ import type { LocalEmbeddingConfig } from "./local-embedding.js";
8
+ import type { LocalMemoryProvider } from "./local-memory-provider.js";
9
+ export interface MemoryProviderFactoryConfig {
10
+ /** Project root for local storage path. */
11
+ projectRoot?: string;
12
+ /** User ID prefix. */
13
+ userIdPrefix?: string;
14
+ /** Embedding config for local provider. */
15
+ embedding?: LocalEmbeddingConfig;
16
+ }
17
+ export interface MemoryProviderFactoryResult {
18
+ provider: LocalMemoryProvider | null;
19
+ mode: "local" | "none";
20
+ error?: string;
21
+ }
22
+ /**
23
+ * Create the local SQLite memory provider.
24
+ * Returns null (mode "none") only if better-sqlite3 is not available.
25
+ */
26
+ export declare function createMemoryProvider(config: MemoryProviderFactoryConfig): MemoryProviderFactoryResult;
27
+ /**
28
+ * Build MemoryProviderFactoryConfig from environment variables.
29
+ * Used by stdio-server to auto-configure memory.
30
+ *
31
+ * Environment variables:
32
+ * QMEMORY_EMBEDDING_STRATEGY — "auto" | "api" | "onnx" | "none" (default: "none")
33
+ * - "auto": detect LLM provider → use their embedding API directly
34
+ * QMEMORY_EMBEDDING_BASE_URL — required when strategy=api
35
+ * QMEMORY_EMBEDDING_API_KEY — required when strategy=api
36
+ * QMEMORY_EMBEDDING_MODEL — model name (default: "text-embedding-3-small")
37
+ * QMEMORY_ONNX_MODEL_ID — model for ONNX (default: "Xenova/bge-small-zh-v1.5")
38
+ * QMEMORY_USER_PREFIX — user ID prefix for multi-tenant
39
+ *
40
+ * Auto-cascade (strategy=auto):
41
+ * Layer 0: LLM provider's embedding API (detected from LLM_PROVIDER + *_API_KEY)
42
+ * Layer 1: Self-hosted TEI bge-m3 (QMEMORY_TEI_URL / QMEMORY_TEI_FALLBACK_URL)
43
+ * Layer 2: ONNX local (@xenova/transformers)
44
+ * Layer 3: FTS5 pure text (NullEmbeddingProvider)
45
+ *
46
+ * @param projectRoot — Project root for local storage path
47
+ * @param embeddingOverride — TurnConfig.embeddingModel override (takes priority over env vars)
48
+ */
49
+ export declare function resolveMemoryConfigFromEnv(projectRoot?: string, embeddingOverride?: {
50
+ provider?: string;
51
+ model?: string;
52
+ apiKey?: string;
53
+ baseUrl?: string;
54
+ }): MemoryProviderFactoryConfig;
@@ -1,8 +1,9 @@
1
1
  import type { MemoryProvider, MemorySearchResult } from "../../protocol/wire/index.js";
2
+ import type { LocalMemoryProvider } from "./local-memory-provider.js";
2
3
  import type { Memdir } from "./memdir.js";
3
4
  export declare const MEMORY_TOOL_NAME: "memory";
4
5
  export declare const MEMORY_TOOL_LABEL = "Memory";
5
- export declare const MEMORY_TOOL_ACTIONS: readonly ["add", "replace", "remove", "create_file", "write_file", "read_file", "delete_file", "list_files", "search"];
6
+ export declare const MEMORY_TOOL_ACTIONS: readonly ["add", "replace", "remove", "create_file", "write_file", "read_file", "delete_file", "list_files", "search", "remember", "temporal", "feedback"];
6
7
  export type MemoryToolAction = (typeof MEMORY_TOOL_ACTIONS)[number];
7
8
  export declare const MEMORY_TOOL_SCHEMA: {
8
9
  readonly type: "object";
@@ -30,7 +31,28 @@ export declare const MEMORY_TOOL_SCHEMA: {
30
31
  };
31
32
  readonly query: {
32
33
  readonly type: "string";
33
- readonly description: "For 'search': natural language query to find relevant memories.";
34
+ readonly description: "For 'search'/'temporal': natural language query to find relevant memories.";
35
+ };
36
+ readonly days: {
37
+ readonly type: "number";
38
+ readonly description: "For 'temporal': look back N days from today (default: 7).";
39
+ };
40
+ readonly memory_ids: {
41
+ readonly type: "array";
42
+ readonly items: {
43
+ readonly type: "string";
44
+ };
45
+ readonly description: "For 'feedback': IDs of memories to give feedback on.";
46
+ };
47
+ readonly signal: {
48
+ readonly type: "string";
49
+ readonly enum: readonly ["useful", "irrelevant", "outdated", "wrong"];
50
+ readonly description: "For 'feedback': the feedback signal to apply.";
51
+ };
52
+ readonly category: {
53
+ readonly type: "string";
54
+ readonly enum: readonly ["preference", "personal_fact", "lesson", "pattern", "decision", "context"];
55
+ readonly description: "For 'remember': categorize the memory (helps with future recall precision).";
34
56
  };
35
57
  };
36
58
  readonly required: readonly ["action"];
@@ -44,6 +66,10 @@ export interface MemoryToolParams {
44
66
  new_text?: string;
45
67
  file?: string;
46
68
  query?: string;
69
+ days?: number;
70
+ memory_ids?: string[];
71
+ signal?: "useful" | "irrelevant" | "outdated" | "wrong";
72
+ category?: string;
47
73
  }
48
74
  export interface MemoryToolResult {
49
75
  ok: boolean;
@@ -54,6 +80,8 @@ export interface MemoryToolResult {
54
80
  export interface MemoryToolExecutorDeps {
55
81
  memdir: Memdir;
56
82
  provider?: MemoryProvider;
83
+ /** LocalMemoryProvider for temporal/feedback (typed narrow for advanced ops). */
84
+ localProvider?: LocalMemoryProvider;
57
85
  userId: string;
58
86
  }
59
87
  export declare function executeMemoryTool(params: MemoryToolParams, deps: MemoryToolExecutorDeps): Promise<MemoryToolResult>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Denial Audit Log — Persistent structured record of all permission denials.
3
+ *
4
+ * Writes denial events to a JSONL file for post-session analysis,
5
+ * compliance auditing, and permission calibration improvement.
6
+ *
7
+ * Storage layout:
8
+ * <project>/.qlogicagent/audit/denials.jsonl (project-level)
9
+ * ~/.qlogicagent/audit/denials.jsonl (user-level fallback)
10
+ *
11
+ * Each line is a self-contained JSON record with full context.
12
+ * File is append-only; rotation handled externally if needed.
13
+ */
14
+ export interface DenialAuditEntry {
15
+ /** ISO 8601 timestamp */
16
+ timestamp: string;
17
+ /** Session identifier */
18
+ sessionId: string;
19
+ /** Turn identifier (if available) */
20
+ turnId: string;
21
+ /** Tool that was denied */
22
+ toolName: string;
23
+ /** Human-readable reason for denial */
24
+ reason: string;
25
+ /** Source of the denial decision */
26
+ source: "classifier" | "rule-engine" | "user" | "timeout" | "safety" | "static-deny";
27
+ /** Permission role at time of denial */
28
+ permissionRole: string;
29
+ /** Tool call ID */
30
+ callId: string;
31
+ /** Tool arguments (sanitized — no secrets) */
32
+ toolArgs?: Record<string, unknown>;
33
+ /** Cumulative denial count at this point */
34
+ cumulativeDenials: number;
35
+ /** Consecutive denial count at this point */
36
+ consecutiveDenials: number;
37
+ }
38
+ export declare class DenialAuditLogger {
39
+ private filePath;
40
+ private writeQueue;
41
+ constructor(projectRoot?: string);
42
+ /**
43
+ * Append a denial event to the audit log.
44
+ * Non-blocking; errors are swallowed to avoid disrupting agent flow.
45
+ */
46
+ record(entry: DenialAuditEntry): void;
47
+ /** Get the audit log file path (for external tools/export). */
48
+ getFilePath(): string;
49
+ private doWrite;
50
+ }
51
+ /** Remove potential secrets from tool args before logging. */
52
+ export declare function sanitizeToolArgs(args: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
@@ -4,6 +4,7 @@ import { PermissionRuleEngine } from "./rule-engine.js";
4
4
  import type { PermissionUpdate, ApprovalRequest, ApprovalResponse } from "./types.js";
5
5
  import { type ClassifierLLMCall } from "./permission-classifier.js";
6
6
  import type { PermissionRole } from "../../orchestration/subagent/task-types.js";
7
+ import { DenialAuditLogger } from "./denial-audit-log.js";
7
8
  export interface PermissionCheckerDeps {
8
9
  ruleEngine: PermissionRuleEngine;
9
10
  hookRegistry: HookRegistry;
@@ -35,6 +36,12 @@ export interface PermissionCheckerDeps {
35
36
  * - worker: classifier-only path, no approval dialog fallback
36
37
  */
37
38
  permissionRole?: PermissionRole;
39
+ /** Denial audit logger for persistent audit trail. */
40
+ auditLogger?: DenialAuditLogger;
41
+ /** Current session ID (for audit context). */
42
+ sessionId?: string;
43
+ /** Getter for current turn ID (changes per turn). */
44
+ getTurnId?: () => string;
38
45
  }
39
46
  export declare class PermissionChecker {
40
47
  private readonly ruleEngine;
@@ -46,12 +53,15 @@ export declare class PermissionChecker {
46
53
  private readonly getRecentMessages;
47
54
  private readonly permissionRole;
48
55
  private readonly pendingApprovals;
56
+ private readonly auditLogger;
57
+ private readonly sessionId;
58
+ private readonly getTurnId;
49
59
  private unregisterHook;
50
- /** Tool meta cache 鈥?populated from ToolDefinition[] at agent creation */
60
+ /** Tool meta cache populated from ToolDefinition[] at agent creation */
51
61
  private toolMetaCache;
52
- /** Classifier result cache 鈥?avoids redundant LLM calls (CC permissionCache parity) */
62
+ /** Classifier result cache avoids redundant LLM calls (CC permissionCache parity) */
53
63
  private classifierCache;
54
- /** Denial tracking state 鈥?CC denialTracking.ts parity */
64
+ /** Denial tracking state CC denialTracking.ts parity */
55
65
  private denialTracking;
56
66
  constructor(deps: PermissionCheckerDeps);
57
67
  /**
@@ -68,7 +78,7 @@ export declare class PermissionChecker {
68
78
  */
69
79
  setToolMeta(tools: ToolDefinition[]): void;
70
80
  get ruleEngineRef(): PermissionRuleEngine;
71
- /** Fire permission.denied hook + onDenied callback */
81
+ /** Fire permission.denied hook + onDenied callback + audit log */
72
82
  private fireDenied;
73
83
  private handleResult;
74
84
  /**