qlogicagent 2.0.0 → 2.2.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 (69) hide show
  1. package/README.md +8 -8
  2. package/dist/agent.js +8 -8
  3. package/dist/cli.js +250 -203
  4. package/dist/contracts.js +1 -1
  5. package/dist/index.js +249 -202
  6. package/dist/orchestration.js +6 -6
  7. package/dist/types/agent/types.d.ts +3 -1
  8. package/dist/types/cli/stdio-server.d.ts +27 -8
  9. package/dist/types/cli/tool-bootstrap.d.ts +8 -0
  10. package/dist/types/contracts/hooks.d.ts +3 -0
  11. package/dist/types/contracts/index.d.ts +0 -1
  12. package/dist/types/contracts/todo.d.ts +8 -21
  13. package/dist/types/llm/adapters/aliyun-oss-file-upload-adapter.d.ts +44 -0
  14. package/dist/types/llm/adapters/gemini-file-upload-adapter.d.ts +26 -0
  15. package/dist/types/llm/adapters/hub-oss-file-upload-adapter.d.ts +29 -0
  16. package/dist/types/llm/adapters/index.d.ts +10 -0
  17. package/dist/types/llm/adapters/openai-file-upload-adapter.d.ts +38 -0
  18. package/dist/types/llm/adapters/volcengine-file-upload-adapter.d.ts +24 -0
  19. package/dist/types/llm/file-upload-service.d.ts +68 -0
  20. package/dist/types/llm/transports/anthropic-messages.d.ts +4 -0
  21. package/dist/types/llm/transports/gemini-generatecontent.d.ts +4 -0
  22. package/dist/types/llm/transports/media-resolve.d.ts +50 -0
  23. package/dist/types/llm/transports/openai-chat.d.ts +4 -0
  24. package/dist/types/llm/transports/openai-responses.d.ts +3 -0
  25. package/dist/types/llm/transports/volcengine-responses.d.ts +4 -0
  26. package/dist/types/orchestration/tool-loop/tool-schema.d.ts +1 -0
  27. package/dist/types/protocol/methods.d.ts +70 -0
  28. package/dist/types/protocol/notifications.d.ts +42 -0
  29. package/dist/types/runtime/execution/dream-agent.d.ts +2 -0
  30. package/dist/types/runtime/execution/dream-category-context.d.ts +47 -0
  31. package/dist/types/runtime/execution/dream-category-context.test.d.ts +1 -0
  32. package/dist/types/runtime/execution/index.d.ts +1 -0
  33. package/dist/types/runtime/execution/memory-decay.d.ts +57 -0
  34. package/dist/types/runtime/execution/memory-decay.test.d.ts +1 -0
  35. package/dist/types/runtime/hooks/index.d.ts +1 -0
  36. package/dist/types/runtime/hooks/memory-hooks.d.ts +20 -0
  37. package/dist/types/runtime/hooks/skill-recall-hooks.d.ts +36 -0
  38. package/dist/types/runtime/infra/agent-paths.d.ts +20 -2
  39. package/dist/types/runtime/infra/disk-storage.d.ts +0 -16
  40. package/dist/types/runtime/infra/index.d.ts +4 -2
  41. package/dist/types/runtime/infra/media-persistence.d.ts +71 -0
  42. package/dist/types/runtime/infra/project-instructions-store.d.ts +30 -0
  43. package/dist/types/runtime/infra/project-plan-store.d.ts +27 -0
  44. package/dist/types/runtime/infra/project-store.d.ts +30 -0
  45. package/dist/types/runtime/session/session-persistence.d.ts +3 -1
  46. package/dist/types/skills/index.d.ts +7 -9
  47. package/dist/types/skills/memory/categories.d.ts +5 -0
  48. package/dist/types/skills/memory/find-relevant-memories.d.ts +70 -0
  49. package/dist/types/skills/memory/memdir.d.ts +85 -0
  50. package/dist/types/skills/memory/memory-tool.d.ts +16 -44
  51. package/dist/types/skills/memory/qmemory-adapter.d.ts +12 -0
  52. package/dist/types/skills/memory/recall-category-filter.d.ts +54 -0
  53. package/dist/types/skills/permissions/group-security-policy.d.ts +15 -0
  54. package/dist/types/skills/permissions/index.d.ts +1 -0
  55. package/dist/types/skills/plugins/plugin-loader.d.ts +5 -0
  56. package/dist/types/skills/portable-tool.d.ts +13 -2
  57. package/dist/types/skills/tools/plan-mode-tool.d.ts +1 -1
  58. package/dist/types/skills/tools/read-tool.d.ts +2 -2
  59. package/dist/types/skills/tools/skill-tool.d.ts +16 -3
  60. package/dist/types/skills/tools/task-tool.d.ts +64 -75
  61. package/package.json +1 -1
  62. package/dist/types/contracts/planner.d.ts +0 -35
  63. package/dist/types/orchestration/error-handling/failover-error.d.ts +0 -33
  64. package/dist/types/skills/memory/memory-store.d.ts +0 -86
  65. package/dist/types/skills/todo-tool.d.ts +0 -72
  66. package/dist/types/skills/tools/skill-invoke-tool.d.ts +0 -46
  67. package/dist/types/skills/tools/skill-list-tool.d.ts +0 -33
  68. package/dist/types/skills/tools/skill-manage-tool.d.ts +0 -73
  69. package/dist/types/skills/tools/skill-view-tool.d.ts +0 -37
@@ -0,0 +1,68 @@
1
+ /**
2
+ * FileUploadService — Unified file upload abstraction for all LLM providers.
3
+ *
4
+ * Replaces the base64 approach in media-resolve.ts. When a local URL is
5
+ * encountered, this service uploads the file to the current provider's
6
+ * File API and returns a public URL or file_id.
7
+ *
8
+ * Supported providers:
9
+ * - OpenAI-compatible (OpenAI, Kimi, Minimax, Qwen, GLM) — POST /v1/files
10
+ * - Volcengine — POST /v3/files
11
+ * - Google Gemini — Resumable upload protocol
12
+ *
13
+ * Architecture:
14
+ * Transport layer calls resolveLocalMedia() before sending messages.
15
+ * resolveLocalMedia() fetches local content and uploads to provider,
16
+ * returning a public URL the LLM can access.
17
+ */
18
+ export interface FileUploadResult {
19
+ /** Public URL accessible by the LLM provider. */
20
+ url: string;
21
+ /** Provider-specific file identifier (for reference/deletion). */
22
+ fileId: string;
23
+ /** Original filename. */
24
+ filename: string;
25
+ /** File size in bytes. */
26
+ bytes: number;
27
+ /** MIME type of the uploaded file. */
28
+ mimeType: string;
29
+ /** Provider that stored the file. */
30
+ provider: string;
31
+ }
32
+ /**
33
+ * Provider-specific upload adapter.
34
+ * Each transport implements this to upload files to its own File API.
35
+ */
36
+ export interface FileUploadAdapter {
37
+ /**
38
+ * Upload a file buffer and return a publicly accessible URL.
39
+ * @param buffer - File content
40
+ * @param filename - Original filename (used for MIME detection)
41
+ * @param mimeType - MIME type of the file
42
+ * @param apiKey - Provider API key
43
+ * @param signal - Abort signal
44
+ */
45
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
46
+ }
47
+ /** Guess MIME type from filename extension. */
48
+ export declare function guessMimeType(filename: string): string;
49
+ /** Check if a URL points to a local/private address that cloud APIs cannot reach. */
50
+ export declare function isLocalUrl(url: string): boolean;
51
+ /**
52
+ * Resolve a local URL by uploading its content to the provider's File API.
53
+ * Public URLs are returned as-is (the LLM API can fetch them directly).
54
+ *
55
+ * @param url - The URL to resolve (may be local or public)
56
+ * @param adapter - Provider-specific upload adapter
57
+ * @param apiKey - API key for the upload
58
+ * @param signal - Optional abort signal
59
+ * @returns Public URL accessible by the LLM
60
+ */
61
+ export declare function resolveLocalMedia(url: string, adapter: FileUploadAdapter, apiKey: string, signal?: AbortSignal): Promise<string>;
62
+ /**
63
+ * Batch-resolve multiple URLs concurrently. Returns array in same order.
64
+ * Local URLs are uploaded; public URLs pass through unchanged.
65
+ * Supports concurrent uploads (up to `concurrency` limit, default 3).
66
+ * Failures throw (caller should handle).
67
+ */
68
+ export declare function resolveLocalMediaBatch(urls: string[], adapter: FileUploadAdapter, apiKey: string, signal?: AbortSignal, concurrency?: number): Promise<string[]>;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
15
15
  import type { ProviderQuirks } from "../provider-def.js";
16
+ import type { FileUploadAdapter } from "../file-upload-service.js";
16
17
  export interface AnthropicTransportConfig {
17
18
  baseUrl: string;
18
19
  /** anthropic-version header (default "2023-06-01") */
@@ -29,6 +30,8 @@ export interface AnthropicTransportConfig {
29
30
  omitZeroTemperature?: boolean;
30
31
  /** Provider-specific quirks for conditional logic (CC/altcode parity) */
31
32
  quirks?: ProviderQuirks;
33
+ /** File upload adapter (Hub OSS relay for Anthropic). */
34
+ fileUploadAdapter?: FileUploadAdapter;
32
35
  }
33
36
  export declare class AnthropicMessagesTransport implements LLMTransport {
34
37
  private baseUrl;
@@ -39,6 +42,7 @@ export declare class AnthropicMessagesTransport implements LLMTransport {
39
42
  private maxRetries;
40
43
  private omitZeroTemperature;
41
44
  private quirks;
45
+ private fileUploadAdapter?;
42
46
  constructor(config: AnthropicTransportConfig);
43
47
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
44
48
  /**
@@ -21,6 +21,7 @@
21
21
  */
22
22
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
23
23
  import type { ProviderQuirks } from "../provider-def.js";
24
+ import type { FileUploadAdapter } from "../file-upload-service.js";
24
25
  export interface GeminiGenerateContentTransportConfig {
25
26
  /** Base URL, e.g. "https://generativelanguage.googleapis.com/v1beta" */
26
27
  baseUrl: string;
@@ -28,11 +29,14 @@ export interface GeminiGenerateContentTransportConfig {
28
29
  timeoutMs?: number;
29
30
  /** Provider-specific quirks */
30
31
  quirks?: ProviderQuirks;
32
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
33
+ fileUploadAdapter?: FileUploadAdapter;
31
34
  }
32
35
  export declare class GeminiGenerateContentTransport implements LLMTransport {
33
36
  private baseUrl;
34
37
  private timeoutMs;
35
38
  private quirks;
39
+ private fileUploadAdapter?;
36
40
  constructor(config: GeminiGenerateContentTransportConfig);
37
41
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
38
42
  private buildRequestBody;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Media URL Resolution — resolves local/private URLs for cloud LLM APIs.
3
+ *
4
+ * Cloud LLM APIs (OpenAI, Anthropic, DeepSeek, etc.) cannot fetch content
5
+ * from localhost or private networks.
6
+ *
7
+ * **Primary approach (upload-based):**
8
+ * Local URLs are fetched → uploaded to provider's File API or Aliyun OSS → public URL returned.
9
+ * This is the ONLY approach for images, video, and documents.
10
+ *
11
+ * **Audio exception (base64):**
12
+ * OpenAI's input_audio.data API field mandates base64 encoding.
13
+ * resolveMediaUrl() is retained ONLY for this case.
14
+ *
15
+ * URL-first design: the gateway stores media as HTTP URLs; this layer handles
16
+ * the last-mile transformation before sending to provider APIs.
17
+ */
18
+ import type { FileUploadAdapter } from "../file-upload-service.js";
19
+ /** Check if a URL points to a local/private address that cloud APIs cannot reach. */
20
+ export declare function isLocalUrl(url: string): boolean;
21
+ export interface MediaResolveContext {
22
+ /** Provider-specific upload adapter. */
23
+ uploadAdapter: FileUploadAdapter;
24
+ /** API key for the upload. */
25
+ apiKey: string;
26
+ /** Abort signal. */
27
+ signal?: AbortSignal;
28
+ }
29
+ /**
30
+ * Resolve a local URL by uploading to the provider's File API.
31
+ * This is the **preferred** method for all media types.
32
+ *
33
+ * Public URLs pass through unchanged.
34
+ * Local URLs are uploaded → public URL or file_id returned.
35
+ */
36
+ export declare function resolveMediaUrlViaUpload(url: string, ctx: MediaResolveContext): Promise<string>;
37
+ /**
38
+ * Batch-resolve URLs via upload. Best-effort: failures return original URL.
39
+ */
40
+ export declare function resolveMediaUrlsViaUpload(urls: string[], ctx: MediaResolveContext): Promise<string[]>;
41
+ /**
42
+ * Resolve local audio URL to base64 data URL.
43
+ *
44
+ * ONLY for audio — OpenAI's input_audio.data API field mandates base64 encoding.
45
+ * There is no upload alternative for audio in the OpenAI API.
46
+ *
47
+ * For images/video/documents: ALWAYS use resolveMediaUrlViaUpload() instead.
48
+ * base64 is forbidden for non-audio media per project architecture rules.
49
+ */
50
+ export declare function resolveMediaUrl(url: string, fallbackMime?: string): Promise<string>;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import type { LLMChunk, LLMRequest, LLMTransport, FIMRequest, FIMChunk } from "../transport.js";
15
15
  import type { ProviderQuirks } from "../provider-def.js";
16
+ import type { FileUploadAdapter } from "../file-upload-service.js";
16
17
  export interface OpenAIChatTransportConfig {
17
18
  baseUrl: string;
18
19
  /** Additional headers (e.g. for specific providers) */
@@ -25,6 +26,8 @@ export interface OpenAIChatTransportConfig {
25
26
  omitZeroTemperature?: boolean;
26
27
  /** Provider-specific quirks (CC/altcode parity) */
27
28
  quirks?: ProviderQuirks;
29
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
30
+ fileUploadAdapter?: FileUploadAdapter;
28
31
  }
29
32
  export declare class OpenAIChatTransport implements LLMTransport {
30
33
  private baseUrl;
@@ -33,6 +36,7 @@ export declare class OpenAIChatTransport implements LLMTransport {
33
36
  private supportsStreamOptions;
34
37
  private omitZeroTemperature;
35
38
  private quirks;
39
+ private fileUploadAdapter?;
36
40
  private cumulativeReasoningLen;
37
41
  private cumulativeContentLen;
38
42
  constructor(config: OpenAIChatTransportConfig);
@@ -25,17 +25,20 @@
25
25
  */
26
26
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
27
27
  import type { ProviderQuirks } from "../provider-def.js";
28
+ import type { FileUploadAdapter } from "../file-upload-service.js";
28
29
  export interface OpenAIResponsesTransportConfig {
29
30
  baseUrl: string;
30
31
  extraHeaders?: Record<string, string>;
31
32
  timeoutMs?: number;
32
33
  quirks?: ProviderQuirks;
34
+ fileUploadAdapter?: FileUploadAdapter;
33
35
  }
34
36
  export declare class OpenAIResponsesTransport implements LLMTransport {
35
37
  private baseUrl;
36
38
  private extraHeaders;
37
39
  private timeoutMs;
38
40
  private quirks;
41
+ private fileUploadAdapter?;
39
42
  constructor(config: OpenAIResponsesTransportConfig);
40
43
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
41
44
  private buildRequestBody;
@@ -18,17 +18,21 @@
18
18
  */
19
19
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
20
20
  import type { ProviderQuirks } from "../provider-def.js";
21
+ import type { FileUploadAdapter } from "../file-upload-service.js";
21
22
  export interface VolcengineResponsesTransportConfig {
22
23
  baseUrl: string;
23
24
  extraHeaders?: Record<string, string>;
24
25
  timeoutMs?: number;
25
26
  quirks?: ProviderQuirks;
27
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
28
+ fileUploadAdapter?: FileUploadAdapter;
26
29
  }
27
30
  export declare class VolcengineResponsesTransport implements LLMTransport {
28
31
  private baseUrl;
29
32
  private extraHeaders;
30
33
  private timeoutMs;
31
34
  private quirks;
35
+ private fileUploadAdapter?;
32
36
  constructor(config: VolcengineResponsesTransportConfig);
33
37
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
34
38
  /**
@@ -38,5 +38,6 @@ export declare function buildToolResultMessage(callId: string, result: {
38
38
  payload?: unknown;
39
39
  error?: string;
40
40
  toolReferences?: string[];
41
+ imageUrls?: string[];
41
42
  }): Record<string, unknown>;
42
43
  export declare function cleanToolSchemaForGemini(schema: Record<string, unknown>): unknown;
@@ -302,6 +302,56 @@ export interface TasksCancelResult {
302
302
  ok: boolean;
303
303
  message: string;
304
304
  }
305
+ export type ProjectType = "default" | "personal" | "group";
306
+ export type ProjectStatus = "active" | "archived";
307
+ export interface ProjectInfo {
308
+ id: string;
309
+ name: string;
310
+ workspaceDir: string;
311
+ type: ProjectType;
312
+ status: ProjectStatus;
313
+ groupId?: string;
314
+ createdAt: string;
315
+ updatedAt: string;
316
+ }
317
+ export interface ProjectCreateParams {
318
+ name: string;
319
+ workspaceDir: string;
320
+ type?: ProjectType;
321
+ groupId?: string;
322
+ }
323
+ export interface ProjectCreateResult {
324
+ ok: boolean;
325
+ project: ProjectInfo;
326
+ }
327
+ export interface ProjectListParams {
328
+ }
329
+ export interface ProjectListResult {
330
+ projects: ProjectInfo[];
331
+ }
332
+ export interface ProjectDeleteParams {
333
+ projectId: string;
334
+ }
335
+ export interface ProjectDeleteResult {
336
+ ok: boolean;
337
+ switchedTo?: ProjectInfo;
338
+ }
339
+ export interface SessionSwitchProjectParams {
340
+ projectId?: string;
341
+ projectName?: string;
342
+ workspaceDir?: string;
343
+ }
344
+ export interface SessionSwitchProjectResult {
345
+ ok: boolean;
346
+ project: ProjectInfo;
347
+ }
348
+ export interface SessionGetStateParams {
349
+ }
350
+ export interface SessionGetStateResult {
351
+ sessionId: string;
352
+ activeProject: ProjectInfo | null;
353
+ projects: ProjectInfo[];
354
+ }
305
355
  export interface RpcMethodMap {
306
356
  "initialize": {
307
357
  params: InitializeParams;
@@ -484,6 +534,26 @@ export interface RpcMethodMap {
484
534
  params: undefined;
485
535
  result: ProductSummary[];
486
536
  };
537
+ "project.create": {
538
+ params: ProjectCreateParams;
539
+ result: ProjectCreateResult;
540
+ };
541
+ "project.list": {
542
+ params: ProjectListParams;
543
+ result: ProjectListResult;
544
+ };
545
+ "project.delete": {
546
+ params: ProjectDeleteParams;
547
+ result: ProjectDeleteResult;
548
+ };
549
+ "session.switchProject": {
550
+ params: SessionSwitchProjectParams;
551
+ result: SessionSwitchProjectResult;
552
+ };
553
+ "session.getState": {
554
+ params: SessionGetStateParams;
555
+ result: SessionGetStateResult;
556
+ };
487
557
  }
488
558
  /** All known RPC method names. */
489
559
  export type RpcMethod = keyof RpcMethodMap;
@@ -192,6 +192,16 @@ export interface TurnMediaProgressNotification {
192
192
  /** Provider id. */
193
193
  provider?: string;
194
194
  }
195
+ /** Media files auto-downloaded to local storage (~/.qlogicagent/media/). */
196
+ export interface TurnMediaPersistedNotification {
197
+ turnId: string;
198
+ files: Array<{
199
+ remoteUrl: string;
200
+ localPath: string;
201
+ bytes: number;
202
+ mimeType: string;
203
+ }>;
204
+ }
195
205
  /** Full todo list updated — enables DeerFlow-style todo panel sync. */
196
206
  export interface TurnTodosUpdatedNotification {
197
207
  turnId?: string;
@@ -279,6 +289,15 @@ export interface MemoryUpdatedNotification {
279
289
  /** Human-readable summary of what changed. */
280
290
  summary?: string;
281
291
  }
292
+ /** Emitted when importance decay runs after a Dream consolidation. */
293
+ export interface MemoryDecayCompletedNotification {
294
+ /** Number of memories whose importance was reduced. */
295
+ decayed: number;
296
+ /** Number of memories archived (below threshold). */
297
+ archived: number;
298
+ /** Duration in ms. */
299
+ durationMs: number;
300
+ }
282
301
  /** Session metadata changed (title, model, etc.). */
283
302
  export interface SessionInfoNotification {
284
303
  sessionId: string;
@@ -407,6 +426,24 @@ export interface ProductCompletedNotification {
407
426
  productId: string;
408
427
  summary: string;
409
428
  }
429
+ /** A project was created. */
430
+ export interface ProjectCreatedNotification {
431
+ id: string;
432
+ name: string;
433
+ workspaceDir: string;
434
+ type: string;
435
+ groupId?: string;
436
+ }
437
+ /** Active project was switched. */
438
+ export interface ProjectSwitchedNotification {
439
+ id: string;
440
+ name: string;
441
+ workspaceDir: string;
442
+ }
443
+ /** A project was deleted. */
444
+ export interface ProjectDeletedNotification {
445
+ id: string;
446
+ }
410
447
  export interface NotificationMethodMap {
411
448
  "turn.start": TurnStartNotification;
412
449
  "turn.delta": TurnDeltaNotification;
@@ -425,6 +462,7 @@ export interface NotificationMethodMap {
425
462
  "turn.annotations": TurnAnnotationsNotification;
426
463
  "turn.media_result": TurnMediaResultNotification;
427
464
  "turn.media_progress": TurnMediaProgressNotification;
465
+ "turn.media_persisted": TurnMediaPersistedNotification;
428
466
  "turn.todos_updated": TurnTodosUpdatedNotification;
429
467
  "task.updated": TaskUpdatedNotification;
430
468
  "turn.exec_progress": TurnExecProgressNotification;
@@ -435,6 +473,7 @@ export interface NotificationMethodMap {
435
473
  "turn.skill_instruction": TurnSkillInstructionNotification;
436
474
  "turn.ask_user": TurnAskUserNotification;
437
475
  "memory.updated": MemoryUpdatedNotification;
476
+ "memory.decay.completed": MemoryDecayCompletedNotification;
438
477
  "session.info": SessionInfoNotification;
439
478
  "permission.rule_updated": PermissionRuleUpdatedNotification;
440
479
  "team.updated": TeamUpdatedNotification;
@@ -453,6 +492,9 @@ export interface NotificationMethodMap {
453
492
  "product.checkpointed": ProductCheckpointedNotification;
454
493
  "product.budgetWarning": ProductBudgetWarningNotification;
455
494
  "product.completed": ProductCompletedNotification;
495
+ "project.created": ProjectCreatedNotification;
496
+ "project.switched": ProjectSwitchedNotification;
497
+ "project.deleted": ProjectDeletedNotification;
456
498
  }
457
499
  /** All known notification method names. */
458
500
  export type NotificationMethod = keyof NotificationMethodMap;
@@ -72,9 +72,11 @@ export declare function canUseDreamTool(memoryRoot: string, restriction: DreamTo
72
72
  * Build the 4-phase memory consolidation prompt.
73
73
  *
74
74
  * Adapted from CC's consolidationPrompt.ts with our project context.
75
+ * P5: Enhanced with category-aware merge rules from write gate taxonomy.
75
76
  */
76
77
  export declare function buildConsolidationPrompt(memoryRoot: string, transcriptDir: string, sessionIds: string[], opts?: {
77
78
  hasQMemory?: boolean;
79
+ categoryContext?: string;
78
80
  }): string;
79
81
  /**
80
82
  * Check whether dream consolidation should run.
@@ -0,0 +1,47 @@
1
+ import type { QMemoryCategory } from "../../skills/memory/categories.js";
2
+ /** A memory file with its inferred category and metadata. */
3
+ export interface CategorizedMemoryFile {
4
+ filename: string;
5
+ category: QMemoryCategory | "uncategorized";
6
+ /** First line description. */
7
+ description: string;
8
+ /** File size bytes. */
9
+ sizeBytes: number;
10
+ /** Count of entries/bullets in the file. */
11
+ entryCount: number;
12
+ }
13
+ /** Category statistics for the dream prompt. */
14
+ export interface CategoryManifest {
15
+ /** Per-category file groups. */
16
+ categories: Record<string, CategorizedMemoryFile[]>;
17
+ /** Total files scanned. */
18
+ totalFiles: number;
19
+ /** Files that couldn't be classified. */
20
+ uncategorizedCount: number;
21
+ }
22
+ /**
23
+ * Scan MEMDIR and classify all topic files by category.
24
+ *
25
+ * @param memoryRoot - The MEMDIR root directory
26
+ * @returns Category manifest with grouped files
27
+ */
28
+ export declare function scanCategoryManifest(memoryRoot: string): Promise<CategoryManifest>;
29
+ /**
30
+ * Category-specific merge/conflict rules for the dream prompt.
31
+ *
32
+ * These rules tell the dream agent how to handle each category:
33
+ * - facts: supersede (newer replaces older when same topic)
34
+ * - lessons: accumulate (append new insights, don't delete old)
35
+ * - preferences: overwrite (latest preference wins)
36
+ * - patterns: merge (consolidate duplicates into one authoritative entry)
37
+ * - decisions: update (add "update" section if decision changed)
38
+ */
39
+ export declare const CATEGORY_MERGE_RULES: Record<QMemoryCategory | "uncategorized", string>;
40
+ /**
41
+ * Format the category manifest and merge rules as an injection block
42
+ * for the dream consolidation prompt.
43
+ *
44
+ * This replaces the blind "grep transcripts" approach with structured
45
+ * guidance about what exists and how to handle each category.
46
+ */
47
+ export declare function formatCategoryContextBlock(manifest: CategoryManifest): string;
@@ -3,4 +3,5 @@ export { createContentReplacementState, enforceToolResultBudget, maybePersistLar
3
3
  export { resolveToolEligibility, type ToolEligibilityContext, type ToolEligibilityResult } from "./tool-eligibility.js";
4
4
  export { runForkedAgent, type ForkedAgentParams, type CanUseToolFn } from "./forked-agent.js";
5
5
  export { runDream, type DreamRunDeps } from "./dream-agent.js";
6
+ export { runDecayCycle, shouldTriggerDecay, markDecayComplete, type DecayCycleDeps, type DecayCycleResult, type DecayConfig } from "./memory-decay.js";
6
7
  export { createProgressTracker, updateProgressFromUsage, recordToolUse, getProgressUpdate, type AgentProgress, } from "./progress-tracker.js";
@@ -0,0 +1,57 @@
1
+ import type { DecayOptions, DecayResult } from "../../skills/memory/qmemory-adapter.js";
2
+ export interface DecayConfig {
3
+ /** Minimum hours between decay cycles. Default: 24. */
4
+ minIntervalHours: number;
5
+ /** Enable temporal expiry (event/plan memories past grace period). Default: true. */
6
+ temporalExpiry: boolean;
7
+ /** Enable staleness decay (reduce importance of unaccessed memories). Default: true. */
8
+ stalenessDecay: boolean;
9
+ /** Enable noise archival (archive memories below threshold). Default: true. */
10
+ noiseArchival: boolean;
11
+ }
12
+ export declare const DEFAULT_DECAY_CONFIG: DecayConfig;
13
+ /**
14
+ * Check whether enough time has elapsed since last decay.
15
+ * Returns true if decay should run.
16
+ */
17
+ export declare function shouldTriggerDecay(memoryRoot: string, config?: Partial<DecayConfig>): Promise<boolean>;
18
+ /**
19
+ * Mark decay as having just run (persist timestamp).
20
+ */
21
+ export declare function markDecayComplete(memoryRoot: string): Promise<void>;
22
+ export interface DecayCycleDeps {
23
+ /** QMemory adapter with triggerDecay method. */
24
+ adapter: {
25
+ triggerDecay(userId: string, options?: DecayOptions): Promise<DecayResult>;
26
+ };
27
+ /** User ID for QMemory operations. */
28
+ userId: string;
29
+ /** Memory root directory (for gate marker). */
30
+ memoryRoot: string;
31
+ /** Decay configuration overrides. */
32
+ config?: Partial<DecayConfig>;
33
+ /** Logger. */
34
+ log?: {
35
+ info(msg: string): void;
36
+ debug?(msg: string): void;
37
+ };
38
+ }
39
+ export interface DecayCycleResult {
40
+ /** Whether decay actually ran (false = skipped by gate). */
41
+ ran: boolean;
42
+ /** Number of memories whose importance was reduced. */
43
+ decayed: number;
44
+ /** Number of memories archived (below threshold). */
45
+ archived: number;
46
+ /** Duration in ms. */
47
+ durationMs: number;
48
+ }
49
+ /**
50
+ * Run a full decay cycle with gate check.
51
+ *
52
+ * Lifecycle:
53
+ * 1. Check time gate (24h default)
54
+ * 2. Call QMemory /v1/admin/decay
55
+ * 3. Mark completion timestamp
56
+ */
57
+ export declare function runDecayCycle(deps: DecayCycleDeps): Promise<DecayCycleResult>;
@@ -1,3 +1,4 @@
1
1
  export { createHookRegistry, type RuntimeLogger } from "./hook-registry.js";
2
2
  export { registerMemoryHooks, createMemoryPrefetchState, type MemoryHooksDeps, type MemoryPrefetchState, MEMORY_PREFETCH_CONFIG, } from "./memory-hooks.js";
3
3
  export { registerContextCompressionHook, compressMessages } from "./context-compression.js";
4
+ export { registerSkillRecallHooks, detectRetrospectiveTrigger, invalidateSkillRecallCache, type SkillRecallHooksDeps, SKILL_RECALL_CONFIG, } from "./skill-recall-hooks.js";
@@ -1,5 +1,6 @@
1
1
  import type { HookRegistry } from "../../contracts/hooks.js";
2
2
  import type { MemoryProvider } from "qlogicagent-runtime-contracts";
3
+ import type { Memdir } from "../../skills/memory/memdir.js";
3
4
  export declare const MEMORY_PREFETCH_CONFIG: {
4
5
  /** Max bytes of memory content to inject per session (CC: 60KB) */
5
6
  readonly MAX_SESSION_BYTES: number;
@@ -47,3 +48,22 @@ export declare function createMemoryPrefetchState(): MemoryPrefetchState;
47
48
  export declare function registerMemoryHooks(hooks: HookRegistry, deps: MemoryHooksDeps,
48
49
  /** Shared state — pass the same object across hook re-registrations in a session. */
49
50
  prefetchState?: MemoryPrefetchState): () => void;
51
+ export interface MemdirRecallHookDeps {
52
+ /** MEMDIR instance (lazy: may be null at registration time). */
53
+ getMemdir: () => Memdir | null;
54
+ /** Logger. */
55
+ log: {
56
+ debug(msg: string): void;
57
+ warn(msg: string): void;
58
+ };
59
+ }
60
+ /**
61
+ * Register the MEMDIR cross-file recall hook on `memory.before_recall`.
62
+ *
63
+ * - Priority 40 (before QMemory at 50)
64
+ * - Scans topic files, selects top-5 relevant
65
+ * - Injects content into recalledMemories (merged with QMemory results)
66
+ * - Respects session byte budget from shared MemoryPrefetchState
67
+ * - Dedup via surfacedPaths (shared with QMemory hook)
68
+ */
69
+ export declare function registerMemdirRecallHook(hooks: HookRegistry, deps: MemdirRecallHookDeps, prefetchState?: MemoryPrefetchState): () => void;
@@ -0,0 +1,36 @@
1
+ import type { HookRegistry } from "../../contracts/hooks.js";
2
+ export declare const SKILL_RECALL_CONFIG: {
3
+ /** Max number of cross-project skills to inject per turn. */
4
+ readonly MAX_RECALLED_SKILLS: 3;
5
+ /** Max chars of skill content to include in recall context. */
6
+ readonly MAX_SKILL_CONTENT_CHARS: 800;
7
+ /** Cache TTL for known project skill index (ms). */
8
+ readonly CACHE_TTL_MS: number;
9
+ };
10
+ /**
11
+ * Detect whether user message contains retrospective/cross-reference semantics.
12
+ * Returns extracted keywords for skill matching if triggered, or null.
13
+ */
14
+ export declare function detectRetrospectiveTrigger(message: string): string[] | null;
15
+ export interface SkillRecallHooksDeps {
16
+ /** Current project cwd (to exclude from cross-project search). */
17
+ currentCwd?: string;
18
+ /** Logger. */
19
+ log: {
20
+ debug(msg: string): void;
21
+ warn(msg: string): void;
22
+ };
23
+ }
24
+ /**
25
+ * Register the cross-project skill recall hook on `memory.before_recall`.
26
+ * Runs at lower priority (60) than QMemory prefetch (50) so it supplements,
27
+ * not replaces, the standard memory recall.
28
+ *
29
+ * When triggered, injects cross-project skill metadata into recalledMemories.
30
+ */
31
+ export declare function registerSkillRecallHooks(hooks: HookRegistry, deps: SkillRecallHooksDeps): () => void;
32
+ /**
33
+ * Invalidate the cross-project skill index cache.
34
+ * Call when skills are created/deleted/promoted to refresh.
35
+ */
36
+ export declare function invalidateSkillRecallCache(): void;
@@ -39,6 +39,8 @@ export declare function getUserWorkflowsDir(): string;
39
39
  export declare function getUserInstructionsPath(): string;
40
40
  /** `~/.qlogicagent/rules/` */
41
41
  export declare function getUserRulesDir(): string;
42
+ /** `~/.qlogicagent/media/` — auto-downloaded media files (images, videos, audio). */
43
+ export declare function getUserMediaDir(): string;
42
44
  /** `<cwd>/.qlogicagent/` */
43
45
  export declare function getProjectAgentDir(cwd?: string): string;
44
46
  /** `<cwd>/.qlogicagent/workflows/` */
@@ -51,6 +53,10 @@ export declare function getProjectSkillsDir(cwd?: string): string;
51
53
  export declare function getProjectSettingsPath(cwd?: string): string;
52
54
  /** `<cwd>/.qlogicagent/INSTRUCTIONS.md` */
53
55
  export declare function getProjectInstructionsPath(cwd?: string): string;
56
+ /** `<cwd>/.qlogicagent/instructions/` — project-scoped instruction files (CRUD via RPC) */
57
+ export declare function getProjectInstructionsDir(cwd?: string): string;
58
+ /** `<cwd>/.qlogicagent/plans/` — project-scoped plan files */
59
+ export declare function getProjectPlansDir(cwd?: string): string;
54
60
  /** `<cwd>/.qlogicagent/rules/` */
55
61
  export declare function getProjectRulesDir(cwd?: string): string;
56
62
  /** `<cwd>/.qlogicagent/sessions/` */
@@ -59,7 +65,19 @@ export declare function getProjectSessionsRoot(cwd: string): string;
59
65
  export declare function getProjectSessionDir(cwd: string, sessionId: string): string;
60
66
  /** `<cwd>/.qlogicagent/checkpoints/` or `<cwd>/.qlogicagent/checkpoints/{sessionId}` */
61
67
  export declare function getProjectCheckpointsDir(cwd: string, sessionId?: string): string;
62
- /** `<cwd>/.qlogicagent/memory.json` */
63
- export declare function getProjectMemoryPath(cwd: string): string;
64
68
  /** `<gitRoot>/.qlogicagent/hooks/` */
65
69
  export declare function getGitRootHooksDir(gitRoot: string): string;
70
+ /**
71
+ * Discover all known project directories from session history.
72
+ * Scans `~/.qlogicagent/sessions/` metadata to extract unique `cwd` paths.
73
+ * Used for cross-project skill recall (read-only, never writes to foreign projects).
74
+ *
75
+ * @param excludeCwd - Current project cwd to exclude from results
76
+ * @returns Array of absolute paths to project roots that have been worked on
77
+ */
78
+ export declare function getKnownProjectDirs(excludeCwd?: string): string[];
79
+ /**
80
+ * Get skill directories from all known projects (excluding current).
81
+ * Returns paths to `<project>/.qlogicagent/skills/` for recall-only access.
82
+ */
83
+ export declare function getAllProjectSkillDirs(excludeCwd?: string): string[];