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
@@ -66,8 +66,10 @@ export interface TurnEndNotification {
66
66
  /** Turn failed. */
67
67
  export interface TurnErrorNotification {
68
68
  turnId: string;
69
- error: string;
70
- code?: string;
69
+ error: {
70
+ message: string;
71
+ code?: string;
72
+ };
71
73
  }
72
74
  /** Agent self-recovered from an error. */
73
75
  export interface TurnRecoveryNotification {
@@ -256,6 +258,15 @@ export interface TurnSkillInstructionNotification {
256
258
  turnId: string;
257
259
  instruction: unknown;
258
260
  }
261
+ /** Agent detected a repeating pattern that should be acquired as a skill from hub. */
262
+ export interface TurnSkillAcquisitionNeededNotification {
263
+ turnId: string;
264
+ pattern: {
265
+ suggestedName: string;
266
+ description: string;
267
+ tools: string[];
268
+ };
269
+ }
259
270
  /** Agent asks the user a clarifying question mid-turn. */
260
271
  export interface TurnAskUserNotification {
261
272
  askId?: string;
@@ -341,7 +352,7 @@ export interface AgentsErrorNotification {
341
352
  export interface SoloProgressNotification {
342
353
  soloId: string;
343
354
  agentId: string;
344
- state: "pending" | "running" | "completed" | "failed";
355
+ state: "pending" | "running" | "completed" | "failed" | "idle";
345
356
  progress?: string;
346
357
  }
347
358
  /** Solo evaluation completed. */
@@ -434,6 +445,40 @@ export interface ProductTaskOutputDeltaNotification {
434
445
  taskId: string;
435
446
  text: string;
436
447
  }
448
+ /** Leader agent produced a structured plan — client should present to user. */
449
+ export interface ProductPlanReadyNotification {
450
+ productId: string;
451
+ plan: {
452
+ name: string;
453
+ modules: Array<{
454
+ name: string;
455
+ description: string;
456
+ suggestedAgentId?: string;
457
+ }>;
458
+ instances: Array<{
459
+ name: string;
460
+ agentId: string;
461
+ role: string;
462
+ }>;
463
+ tasks: Array<{
464
+ taskId: string;
465
+ assignee: string;
466
+ prompt: string;
467
+ dependsOn?: string[];
468
+ }>;
469
+ reasoning: string;
470
+ };
471
+ }
472
+ /** Planning failed. */
473
+ export interface ProductPlanFailedNotification {
474
+ productId: string;
475
+ error: string;
476
+ }
477
+ /** Streaming text output from leader during planning. */
478
+ export interface ProductPlanningDeltaNotification {
479
+ productId: string;
480
+ text: string;
481
+ }
437
482
  /** Plan interrupted. */
438
483
  export interface PlanInterruptedNotification {
439
484
  planId: string;
@@ -543,6 +588,7 @@ export interface NotificationMethodMap {
543
588
  "turn.artifact": TurnArtifactNotification;
544
589
  "tool.approval.request": ToolApprovalRequestNotification;
545
590
  "turn.skill_instruction": TurnSkillInstructionNotification;
591
+ "turn.skill_acquisition_needed": TurnSkillAcquisitionNeededNotification;
546
592
  "turn.ask_user": TurnAskUserNotification;
547
593
  "memory.updated": MemoryUpdatedNotification;
548
594
  "memory.decay.completed": MemoryDecayCompletedNotification;
@@ -569,6 +615,9 @@ export interface NotificationMethodMap {
569
615
  "product.dagTopology": ProductDagTopologyNotification;
570
616
  "product.budgetUpdate": ProductBudgetUpdateNotification;
571
617
  "product.taskOutput": ProductTaskOutputDeltaNotification;
618
+ "product.planReady": ProductPlanReadyNotification;
619
+ "product.planFailed": ProductPlanFailedNotification;
620
+ "product.planningDelta": ProductPlanningDeltaNotification;
572
621
  "plan.interrupted": PlanInterruptedNotification;
573
622
  "project.created": ProjectCreatedNotification;
574
623
  "project.switched": ProjectSwitchedNotification;
@@ -18,6 +18,8 @@ export interface DreamTriggerConfig {
18
18
  minHours: number;
19
19
  /** Minimum sessions since last consolidation. Default: 5. */
20
20
  minSessions: number;
21
+ /** Minimum turns in current session as alternative gate. Default: 20. */
22
+ minTurnsInSession: number;
21
23
  /** Scan throttle interval (ms). Default: 600_000 (10 min). */
22
24
  scanIntervalMs: number;
23
25
  /** Force run, ignoring gates. */
@@ -32,6 +34,8 @@ export interface DreamContext {
32
34
  currentSessionId: string;
33
35
  /** Callback to list session IDs touched since a timestamp. */
34
36
  listSessionsSince: (sinceMs: number) => Promise<string[]>;
37
+ /** Turn count in current session (for single-session users). */
38
+ currentSessionTurnCount?: number;
35
39
  }
36
40
  export interface DreamToolRestriction {
37
41
  toolName: string;
@@ -77,6 +81,8 @@ export declare function canUseDreamTool(memoryRoot: string, restriction: DreamTo
77
81
  export declare function buildConsolidationPrompt(memoryRoot: string, transcriptDir: string, sessionIds: string[], opts?: {
78
82
  hasQMemory?: boolean;
79
83
  categoryContext?: string;
84
+ temporalContext?: string;
85
+ profileContext?: string;
80
86
  }): string;
81
87
  /**
82
88
  * Check whether dream consolidation should run.
@@ -160,11 +166,11 @@ export interface DreamRunDeps {
160
166
  /** Parent abort signal */
161
167
  parentSignal?: AbortSignal;
162
168
  /**
163
- * QMemory adapter — when provided, Dream Agent acts as the "hippocampus":
169
+ * Memory provider — when provided, Dream Agent acts as the "hippocampus":
164
170
  * reads existing long-term memories, writes classified session insights,
165
171
  * and submits feedback on outdated/contradicted memories.
166
172
  */
167
- qmemoryAdapter?: {
173
+ memoryProvider?: {
168
174
  search(query: string, userId: string, options?: {
169
175
  limit?: number;
170
176
  }): Promise<Array<{
@@ -178,10 +184,31 @@ export interface DreamRunDeps {
178
184
  }): Promise<{
179
185
  memoriesAdded: number;
180
186
  }>;
181
- feedback?(memoryIds: string[], signal: string, sessionId?: string): Promise<void>;
187
+ feedback?(memoryIds: string[], signal: "useful" | "irrelevant" | "outdated" | "wrong"): Promise<{
188
+ affected: number;
189
+ }>;
190
+ /** Recent activity summary for temporal context injection into Dream. */
191
+ getActivitySummary?(userId: string, days?: number): {
192
+ dailyCounts: Array<{
193
+ date: string;
194
+ count: number;
195
+ }>;
196
+ highlights: Array<{
197
+ text: string;
198
+ category: string;
199
+ importance: number;
200
+ date: string;
201
+ }>;
202
+ };
203
+ /** Synthesize a timeline narrative for a time range. */
204
+ synthesizeTimeline?(userId: string, startMs: number, endMs: number): string;
205
+ /** Get/set user profile entries. */
206
+ getProfile?(userId: string, key: string): string | null;
207
+ setProfile?(userId: string, key: string, value: string): void;
208
+ getAllProfiles?(userId: string): Record<string, string>;
182
209
  };
183
- /** User ID for QMemory operations. */
184
- qmemoryUserId?: string;
210
+ /** User ID for memory operations. */
211
+ memoryUserId?: string;
185
212
  }
186
213
  /**
187
214
  * Run a complete dream consolidation using an isolated forked agent.
@@ -1,4 +1,14 @@
1
- import type { DecayOptions, DecayResult } from "../../skills/memory/qmemory-adapter.js";
1
+ /** Options for triggering a decay cycle. */
2
+ export interface DecayOptions {
3
+ temporalExpiry?: boolean;
4
+ stalenessDecay?: boolean;
5
+ noiseArchival?: boolean;
6
+ }
7
+ /** Result of a decay cycle. */
8
+ export interface DecayResult {
9
+ decayed: number;
10
+ archived: number;
11
+ }
2
12
  export interface DecayConfig {
3
13
  /** Minimum hours between decay cycles. Default: 24. */
4
14
  minIntervalHours: number;
@@ -20,11 +30,13 @@ export declare function shouldTriggerDecay(memoryRoot: string, config?: Partial<
20
30
  */
21
31
  export declare function markDecayComplete(memoryRoot: string): Promise<void>;
22
32
  export interface DecayCycleDeps {
23
- /** QMemory adapter with triggerDecay method. */
33
+ /** Memory provider with triggerDecay method. */
24
34
  adapter: {
25
- triggerDecay(userId: string, options?: DecayOptions): Promise<DecayResult>;
35
+ triggerDecay(userId: string, maxAgeDays?: number): Promise<{
36
+ decayed: number;
37
+ }>;
26
38
  };
27
- /** User ID for QMemory operations. */
39
+ /** User ID for memory operations. */
28
40
  userId: string;
29
41
  /** Memory root directory (for gate marker). */
30
42
  memoryRoot: string;
@@ -51,7 +63,7 @@ export interface DecayCycleResult {
51
63
  *
52
64
  * Lifecycle:
53
65
  * 1. Check time gate (24h default)
54
- * 2. Call QMemory /v1/admin/decay
66
+ * 2. Call local memory provider decay
55
67
  * 3. Mark completion timestamp
56
68
  */
57
69
  export declare function runDecayCycle(deps: DecayCycleDeps): Promise<DecayCycleResult>;
@@ -1,5 +1,6 @@
1
1
  import type { HookRegistry } from "../../contracts/hooks.js";
2
2
  import type { MemoryProvider } from "../../protocol/wire/index.js";
3
+ import type { LocalMemoryProvider } from "../../skills/memory/local-memory-provider.js";
3
4
  import type { Memdir } from "../../skills/memory/memdir.js";
4
5
  export declare const MEMORY_PREFETCH_CONFIG: {
5
6
  readonly MAX_SESSION_BYTES: number;
@@ -9,6 +10,8 @@ export declare const MEMORY_PREFETCH_CONFIG: {
9
10
  export interface MemoryHooksDeps {
10
11
  /** QMemory adapter (MemoryProvider with search/health). */
11
12
  memoryProvider?: MemoryProvider;
13
+ /** Local memory provider for direct writes (auto-extract). */
14
+ localMemoryProvider?: LocalMemoryProvider;
12
15
  /** User ID for memory lookups. */
13
16
  userId: string;
14
17
  /** Logger. */
@@ -16,6 +19,12 @@ export interface MemoryHooksDeps {
16
19
  debug(msg: string): void;
17
20
  warn(msg: string): void;
18
21
  };
22
+ /** Access to recent messages (for auto-extract). Set externally per turn. */
23
+ getLastUserMessage?: () => string | undefined;
24
+ /** Access to last assistant response (for implicit extraction). Set externally per turn. */
25
+ getLastAssistantMessage?: () => string | undefined;
26
+ /** Background LLM for implicit extraction. If provided, enables Layer 2. */
27
+ llmExtract?: (prompt: string) => Promise<string | null>;
19
28
  }
20
29
  /** Session-scoped state for dedup and byte budget (CC parity). */
21
30
  export interface MemoryPrefetchState {
@@ -158,6 +158,15 @@ export interface SoloStartParams {
158
158
  task: string;
159
159
  agents: string[];
160
160
  cwd: string;
161
+ /** Optional shared config injected into all agents (memory seed, rules, etc). */
162
+ sharedConfig?: {
163
+ /** Initial memory entries to seed into each agent's context. */
164
+ memory?: string[];
165
+ /** Rules/instructions to inject as system prompt prefix. */
166
+ rules?: string[];
167
+ /** Model override for all agents. */
168
+ model?: string;
169
+ };
161
170
  }
162
171
  /** solo.status / solo.cancel / solo.select RPC params. */
163
172
  export interface SoloIdParams {
@@ -168,6 +177,22 @@ export interface SoloSelectParams {
168
177
  soloId: string;
169
178
  winnerId: string;
170
179
  }
180
+ /** solo.message RPC params — send follow-up to individual agent. */
181
+ export interface SoloMessageParams {
182
+ soloId: string;
183
+ agentId: string;
184
+ content: string;
185
+ /** For duplicate agentIds, specify which instance (0-based index). */
186
+ agentIndex?: number;
187
+ }
188
+ /** solo.evaluate RPC params — user-triggered evaluation with chosen evaluator. */
189
+ export interface SoloEvaluateParams {
190
+ soloId: string;
191
+ /** Which agent in the solo session should perform the evaluation comparison. */
192
+ evaluatorAgentId: string;
193
+ /** For duplicate agentIds, specify which instance (0-based index). */
194
+ evaluatorIndex?: number;
195
+ }
171
196
  export type ProductInstanceState = "idle" | "running" | "completed" | "failed" | "paused";
172
197
  /** Product budget configuration & runtime counters. */
173
198
  export interface ProductBudget {
@@ -187,6 +212,69 @@ export interface ProductCreateParams {
187
212
  maxDuration?: number;
188
213
  };
189
214
  }
215
+ /**
216
+ * product.plan RPC params — starts an interactive planning session.
217
+ * The leader agent decomposes the goal into modules and proposes a DAG.
218
+ */
219
+ export interface ProductPlanParams {
220
+ /** High-level project goal (e.g. "build a multiplayer MMO game"). */
221
+ goal: string;
222
+ /** Working directory for the project. */
223
+ cwd: string;
224
+ /** Which agent acts as the team leader (must be ACP-compatible). */
225
+ leaderAgentId: string;
226
+ /** Optional: project name. Leader can suggest one if omitted. */
227
+ name?: string;
228
+ /** Optional: budget constraints communicated to leader during planning. */
229
+ budget?: {
230
+ maxTotalTokens?: number;
231
+ maxDuration?: number;
232
+ };
233
+ }
234
+ /** The structured plan produced by the leader agent. */
235
+ export interface ProductPlan {
236
+ /** Product/project name. */
237
+ name: string;
238
+ /** Modules the project is decomposed into. */
239
+ modules: Array<{
240
+ name: string;
241
+ description: string;
242
+ /** Suggested agent for this module (leader's recommendation). */
243
+ suggestedAgentId?: string;
244
+ }>;
245
+ /** Proposed team members (leader may suggest agents for each module). */
246
+ instances: ProductInstanceDef[];
247
+ /** Proposed task DAG. */
248
+ tasks: ProductTaskDef[];
249
+ /** Leader's explanation of the decomposition strategy. */
250
+ reasoning: string;
251
+ }
252
+ /**
253
+ * product.confirm RPC params — user confirms (optionally modified) plan.
254
+ * This starts the actual DAG execution with the leader managing progress.
255
+ */
256
+ export interface ProductConfirmParams {
257
+ /** The planning session product ID (returned by product.plan). */
258
+ productId: string;
259
+ /** Final instances (user may have reassigned agents). */
260
+ instances: ProductInstanceDef[];
261
+ /** Final task DAG (user may have modified). */
262
+ tasks: ProductTaskDef[];
263
+ /** Budget for execution phase. */
264
+ budget?: {
265
+ maxTotalTokens?: number;
266
+ maxDuration?: number;
267
+ };
268
+ }
269
+ /**
270
+ * product.message RPC params — user sends a message to the leader during any phase.
271
+ * Supports: multi-turn planning dialogue, and user intervention during execution.
272
+ */
273
+ export interface ProductMessageParams {
274
+ productId: string;
275
+ /** User's message content. */
276
+ content: string;
277
+ }
190
278
  /** product.resume / product.pause / product.checkpoint / product.status RPC params. */
191
279
  export interface ProductIdParams {
192
280
  productId: string;
@@ -35,3 +35,13 @@ export declare function createTaskGuidanceSection(domain?: TaskDomain): SystemPr
35
35
  * Tells the LLM when to use specialized tools vs. primitives.
36
36
  */
37
37
  export declare function createToolGuidanceSection(): SystemPromptSection;
38
+ /**
39
+ * Create a system prompt section that instructs the model on response language.
40
+ * CC parity: only injected when language is explicitly set; when absent,
41
+ * the model follows the user's message language naturally.
42
+ *
43
+ * Key rule: always respond in the SAME language as the user's current message.
44
+ * This prevents confusion when system prompt contains mixed-language content
45
+ * (e.g., Chinese INDEX.md + English tool guidance).
46
+ */
47
+ export declare function createLanguageSection(language?: string): SystemPromptSection;
@@ -1,4 +1,4 @@
1
1
  export { assembleSystemPrompt, clearSystemPromptSections, systemPromptSection, type SystemPromptSection, } from "./system-prompt-sections.js";
2
2
  export { getInstructions, buildInstructionsPrompt, resetInstructionCache, } from "./instruction-loader.js";
3
- export { createEnvironmentContextSection, createTaskGuidanceSection, createToolGuidanceSection } from "./environment-context.js";
3
+ export { createEnvironmentContextSection, createTaskGuidanceSection, createToolGuidanceSection, createLanguageSection } from "./environment-context.js";
4
4
  export { detectTaskDomain, resolveTaskDomain, loadProjectTaskDomain, persistTaskDomain, shouldPersistDomain, type TaskDomain, type DomainResolutionContext } from "./task-domain.js";
@@ -4,8 +4,10 @@ export { MEMORY_TOOL_NAME, MEMORY_TOOL_ACTIONS, MEMORY_TOOL_SCHEMA, MEMORY_TOOL_
4
4
  export type { MemoryToolAction, MemoryToolParams, MemoryToolResult, MemoryToolExecutorDeps, } from "./memory/memory-tool.js";
5
5
  export { Memdir, getMemdirPath, getIndexPath } from "./memory/memdir.js";
6
6
  export type { MemdirFileInfo, MemdirResult } from "./memory/memdir.js";
7
- export { createQMemoryAdapter } from "./memory/qmemory-adapter.js";
8
- export type { QMemoryAdapterConfig, QMemoryHealthStatus, ExtractedMemoryItem, DecayOptions, DecayResult } from "./memory/qmemory-adapter.js";
7
+ export { createMemoryProvider, resolveMemoryConfigFromEnv } from "./memory/memory-provider-factory.js";
8
+ export type { MemoryProviderFactoryConfig, MemoryProviderFactoryResult } from "./memory/memory-provider-factory.js";
9
+ export { LocalMemoryProvider } from "./memory/local-memory-provider.js";
10
+ export type { LocalMemoryProviderConfig, ExtractedMemoryItem } from "./memory/local-memory-provider.js";
9
11
  export { THINK_TOOL_NAME, THINK_TOOL_SCHEMA, createThinkTool } from "./think-tool.js";
10
12
  export type { ThinkToolParams } from "./think-tool.js";
11
13
  export { READ_TOOL_NAME, READ_TOOL_SCHEMA, createReadTool } from "./tools/read-tool.js";
@@ -95,6 +97,10 @@ export { scanSource, scanSkillDirectory, hasCriticalFindings, isScannable, } fro
95
97
  export type { SkillGuardDeps } from "./skill-system/skill-guard.js";
96
98
  export { installSkill, uninstallSkill, createEmptyLockfile, } from "./skill-system/skill-source.js";
97
99
  export type { TrustLevel, ScanVerdict, SkillSourceDescriptor, SkillFetchResult, SkillFetchDeps, SkillStorageDeps, SkillLockEntry, SkillLockfile, SkillInstallResult, } from "./skill-system/skill-source.js";
100
+ export { loadLifecycleStore, saveLifecycleStore, ensureRecord, recordInvocation, recordView, recordPatch, removeRecord, pinSkill, unpinSkill, runCurator, executeCuratorCycle, archiveSkillOnDisk, unarchiveSkillOnDisk, getSkillsByState, getLifecycleRecord, } from "./skill-system/skill-lifecycle.js";
101
+ export type { SkillLifecycleState, SkillLifecycleRecord, SkillLifecycleStore, CuratorResult, } from "./skill-system/skill-lifecycle.js";
102
+ export { validateSkillContent, generateSkillContent, autoFixFrontmatter, } from "./skill-system/skill-validation.js";
103
+ export type { FrontmatterValidationResult } from "./skill-system/skill-validation.js";
98
104
  export { McpStdioClient } from "./mcp/mcp-stdio-client.js";
99
105
  export { McpManager, parseMcpConfig } from "./mcp/mcp-manager.js";
100
106
  export type { McpServerEntry, McpManagerConfig } from "./mcp/mcp-manager.js";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Implicit Memory Extraction — CC extractMemories lightweight port.
3
+ *
4
+ * Architecture:
5
+ * Layer 1: Zero-cost signal detection (regex) — decides if turn has extractable content
6
+ * Layer 2: Lightweight LLM pass (async, non-blocking) — extracts structured facts
7
+ *
8
+ * This runs AFTER turn.end, so the user already has their response.
9
+ * Layer 2 only fires for ~10-20% of turns (those with detectable signals).
10
+ *
11
+ * Reference: claude-code src/services/extractMemories/extractMemories.ts
12
+ */
13
+ import type { LocalMemoryProvider } from "./local-memory-provider.js";
14
+ export interface ExtractedFact {
15
+ text: string;
16
+ category: "personal_fact" | "preference" | "event" | "lesson" | "pattern" | "decision";
17
+ importance: number;
18
+ eventDate?: string;
19
+ }
20
+ export interface ImplicitExtractionDeps {
21
+ /** Local memory provider for writing extracted facts. */
22
+ localProvider: LocalMemoryProvider;
23
+ /** User ID. */
24
+ userId: string;
25
+ /** Logger. */
26
+ log: {
27
+ debug(msg: string): void;
28
+ warn(msg: string): void;
29
+ };
30
+ /**
31
+ * LLM invocation function (uses background/cheap model).
32
+ * Returns structured JSON string or null if unavailable.
33
+ */
34
+ llmExtract?: (prompt: string) => Promise<string | null>;
35
+ }
36
+ export interface TurnPair {
37
+ userMessage: string;
38
+ assistantMessage: string;
39
+ }
40
+ /**
41
+ * Layer 1: Detect if a user message contains signals worth extracting.
42
+ * Zero LLM cost — pure regex scanning.
43
+ *
44
+ * @returns true if the message likely contains extractable personal facts/events
45
+ */
46
+ export declare function hasExtractionSignal(userMessage: string): boolean;
47
+ /**
48
+ * Layer 2: Use a lightweight LLM to extract structured facts from a turn pair.
49
+ * Only called when Layer 1 signals are detected.
50
+ */
51
+ export declare function extractFactsViaLlm(turn: TurnPair, llmExtract: (prompt: string) => Promise<string | null>, today: string): Promise<ExtractedFact[]>;
52
+ /**
53
+ * Run the full implicit extraction pipeline for a completed turn.
54
+ * This is async and non-blocking — call it after turn.end.
55
+ *
56
+ * @returns Number of facts extracted and stored
57
+ */
58
+ export declare function runImplicitExtraction(turn: TurnPair, deps: ImplicitExtractionDeps): Promise<number>;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Local Embedding — Pluggable embedding interface for local memory.
3
+ *
4
+ * Provides a unified interface for text → vector embedding.
5
+ * Strategies:
6
+ * 1. "api" — calls an external embedding API (OpenAI-compatible)
7
+ * 2. "onnx" — @xenova/transformers for fully offline embedding
8
+ * 3. "none" — no embeddings, FTS-only search (zero-dep fallback)
9
+ */
10
+ export interface EmbeddingProvider {
11
+ readonly dimensions: number;
12
+ readonly model: string;
13
+ embed(text: string): Promise<Float32Array>;
14
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
15
+ }
16
+ export interface EmbeddingApiConfig {
17
+ /** OpenAI-compatible embedding API base URL */
18
+ baseUrl: string;
19
+ /** API key */
20
+ apiKey: string;
21
+ /** Model name (e.g. "text-embedding-3-small") */
22
+ model: string;
23
+ /** Expected dimensions (default: 1536 for text-embedding-3-small) */
24
+ dimensions?: number;
25
+ /** Request timeout in ms (default: 10000) */
26
+ timeoutMs?: number;
27
+ /**
28
+ * Provider-specific API format.
29
+ * - "openai": Standard /v1/embeddings with input:string[] → data[].embedding (default)
30
+ * - "minimax": /v1/embeddings with texts:string[] → vectors[]
31
+ * - "volcengine": /v1/embeddings/multimodal with input:[{type,text}] → data.embedding
32
+ */
33
+ format?: "openai" | "minimax" | "volcengine";
34
+ }
35
+ export declare class NullEmbeddingProvider implements EmbeddingProvider {
36
+ readonly dimensions = 0;
37
+ readonly model = "none";
38
+ embed(_text: string): Promise<Float32Array>;
39
+ embedBatch(_texts: string[]): Promise<Float32Array[]>;
40
+ }
41
+ /**
42
+ * Wraps a primary EmbeddingProvider with automatic fallback to a local provider.
43
+ * When the primary fails (timeout, network error, 5xx), transparently retries with local.
44
+ *
45
+ * IMPORTANT: primary and fallback MUST have the same dimensions.
46
+ * If they differ, vectors in the same index will be incomparable.
47
+ * Use this only when both produce the same dimensionality (e.g. hub TEI bge-m3 1024d
48
+ * + local ONNX bge-m3-small 1024d).
49
+ */
50
+ export declare class FallbackEmbeddingProvider implements EmbeddingProvider {
51
+ readonly dimensions: number;
52
+ readonly model: string;
53
+ private primary;
54
+ private fallback;
55
+ private onFallback?;
56
+ constructor(opts: {
57
+ primary: EmbeddingProvider;
58
+ fallback: EmbeddingProvider;
59
+ onFallback?: (error: Error) => void;
60
+ });
61
+ embed(text: string): Promise<Float32Array>;
62
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
63
+ }
64
+ export declare class ApiEmbeddingProvider implements EmbeddingProvider {
65
+ readonly dimensions: number;
66
+ readonly model: string;
67
+ private baseUrl;
68
+ private apiKey;
69
+ private timeoutMs;
70
+ private format;
71
+ constructor(config: EmbeddingApiConfig);
72
+ embed(text: string): Promise<Float32Array>;
73
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
74
+ private buildRequest;
75
+ private parseResponse;
76
+ }
77
+ export interface LocalEmbeddingConfig {
78
+ strategy: "api" | "onnx" | "none";
79
+ api?: EmbeddingApiConfig;
80
+ onnx?: OnnxEmbeddingConfig;
81
+ /**
82
+ * When strategy=api, if the API fails (timeout/error), fallback to this.
83
+ * - "onnx": use local ONNX model (download on first use, ~23MB)
84
+ * - "none": give up embedding (FTS-only)
85
+ * Requires same dimensions for vector compatibility. Default ONNX model
86
+ * (bge-small-zh-v1.5, 512d) differs from bge-m3 (1024d).
87
+ * Accept dimension mismatch for degraded recall in fallback mode.
88
+ */
89
+ fallbackStrategy?: "onnx" | "none";
90
+ fallbackOnnx?: OnnxEmbeddingConfig;
91
+ }
92
+ export interface OnnxEmbeddingConfig {
93
+ /** Model ID for @xenova/transformers (default: "Xenova/bge-small-zh-v1.5") */
94
+ modelId?: string;
95
+ /** Expected dimensions (default: 512 for bge-small-zh-v1.5) */
96
+ dimensions?: number;
97
+ /** Max sequence length before truncation (default: 256) */
98
+ maxLength?: number;
99
+ /** Override local model path (for testing). */
100
+ localModelPath?: string;
101
+ }
102
+ /**
103
+ * Offline embedding provider using ONNX Runtime via @xenova/transformers.
104
+ *
105
+ * Model is lazily downloaded on first use (~24MB for bge-small-zh-v1.5 quantized).
106
+ * Subsequent loads are instant from local cache (~/.qlogicagent/models/).
107
+ *
108
+ * For China network: set ONNX_MODEL_MIRROR to OSS URL or HF_MIRROR=https://hf-mirror.com
109
+ */
110
+ export declare class OnnxEmbeddingProvider implements EmbeddingProvider {
111
+ readonly dimensions: number;
112
+ readonly model: string;
113
+ private maxLength;
114
+ private localModelPath;
115
+ private pipeline;
116
+ private loading;
117
+ constructor(config?: OnnxEmbeddingConfig);
118
+ private getPipeline;
119
+ embed(text: string): Promise<Float32Array>;
120
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
121
+ /**
122
+ * Pre-download and load the ONNX model without blocking.
123
+ * Call this at process startup for instant readiness on first real embed().
124
+ */
125
+ warmup(): Promise<void>;
126
+ }
127
+ export interface WarmupResult {
128
+ onnxAvailable: boolean;
129
+ modelCached: boolean;
130
+ modelDownloaded: boolean;
131
+ dimensions: number;
132
+ error?: string;
133
+ }
134
+ /**
135
+ * Run at process startup to verify environment and pre-download ONNX model.
136
+ *
137
+ * - Checks if @xenova/transformers is installed
138
+ * - Checks if model already in local cache
139
+ * - If not cached, downloads from OSS CDN in background
140
+ * - Returns status for diagnostics logging
141
+ *
142
+ * Fire-and-forget: never throws, never blocks critical path.
143
+ */
144
+ export declare function warmupEmbeddingModel(config?: OnnxEmbeddingConfig): Promise<WarmupResult>;
145
+ /**
146
+ * Create an embedding provider based on configuration.
147
+ *
148
+ * Resolution order:
149
+ * 1. Explicit config (api/onnx/none)
150
+ * 2. Auto-detect: @xenova/transformers available → use ONNX (lazy download)
151
+ * 3. Fallback to NullEmbeddingProvider (FTS-only)
152
+ *
153
+ * When config.fallbackStrategy is set and strategy=api, wraps primary in
154
+ * FallbackEmbeddingProvider for automatic local retry on API failure.
155
+ */
156
+ export declare function createEmbeddingProvider(config?: LocalEmbeddingConfig): EmbeddingProvider;
157
+ /**
158
+ * Known provider → format mapping.
159
+ * Used by auto-cascade to build the correct EmbeddingApiConfig
160
+ * when the user's LLM provider also has an embedding API.
161
+ */
162
+ export declare const PROVIDER_EMBEDDING_REGISTRY: Record<string, {
163
+ format: "openai" | "minimax" | "volcengine";
164
+ baseUrl: string;
165
+ defaultModel: string;
166
+ defaultDimensions: number;
167
+ }>;
168
+ /**
169
+ * Resolve EmbeddingApiConfig from a known provider name + API key.
170
+ * Returns null if the provider has no known embedding endpoint.
171
+ */
172
+ export declare function resolveProviderEmbeddingConfig(provider: string, apiKey: string, overrides?: {
173
+ model?: string;
174
+ baseUrl?: string;
175
+ dimensions?: number;
176
+ }): EmbeddingApiConfig | null;