limen-ai 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/api/convenience/convenience_init.d.ts +46 -0
- package/dist/api/convenience/convenience_init.d.ts.map +1 -0
- package/dist/api/convenience/convenience_init.js +111 -0
- package/dist/api/convenience/convenience_init.js.map +1 -0
- package/dist/api/convenience/convenience_layer.d.ts +59 -0
- package/dist/api/convenience/convenience_layer.d.ts.map +1 -0
- package/dist/api/convenience/convenience_layer.js +373 -0
- package/dist/api/convenience/convenience_layer.js.map +1 -0
- package/dist/api/convenience/convenience_prompt.d.ts +19 -0
- package/dist/api/convenience/convenience_prompt.d.ts.map +1 -0
- package/dist/api/convenience/convenience_prompt.js +76 -0
- package/dist/api/convenience/convenience_prompt.js.map +1 -0
- package/dist/api/convenience/convenience_types.d.ts +244 -0
- package/dist/api/convenience/convenience_types.d.ts.map +1 -0
- package/dist/api/convenience/convenience_types.js +30 -0
- package/dist/api/convenience/convenience_types.js.map +1 -0
- package/dist/api/facades/claim_api_impl.d.ts +11 -3
- package/dist/api/facades/claim_api_impl.d.ts.map +1 -1
- package/dist/api/facades/claim_api_impl.js +31 -3
- package/dist/api/facades/claim_api_impl.js.map +1 -1
- package/dist/api/facades/claim_facade.d.ts +5 -1
- package/dist/api/facades/claim_facade.d.ts.map +1 -1
- package/dist/api/facades/claim_facade.js +19 -0
- package/dist/api/facades/claim_facade.js.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +112 -7
- package/dist/api/index.js.map +1 -1
- package/dist/api/interfaces/api.d.ts +91 -51
- package/dist/api/interfaces/api.d.ts.map +1 -1
- package/dist/api/migration/028_fts5_search.d.ts +25 -0
- package/dist/api/migration/028_fts5_search.d.ts.map +1 -0
- package/dist/api/migration/028_fts5_search.js +97 -0
- package/dist/api/migration/028_fts5_search.js.map +1 -0
- package/dist/api/migration/029_fts5_cjk.d.ts +24 -0
- package/dist/api/migration/029_fts5_cjk.d.ts.map +1 -0
- package/dist/api/migration/029_fts5_cjk.js +88 -0
- package/dist/api/migration/029_fts5_cjk.js.map +1 -0
- package/dist/api/migration/030_cognitive_metabolism.d.ts +20 -0
- package/dist/api/migration/030_cognitive_metabolism.d.ts.map +1 -0
- package/dist/api/migration/030_cognitive_metabolism.js +59 -0
- package/dist/api/migration/030_cognitive_metabolism.js.map +1 -0
- package/dist/claims/interfaces/claim_types.d.ts +75 -0
- package/dist/claims/interfaces/claim_types.d.ts.map +1 -1
- package/dist/claims/interfaces/claim_types.js +4 -0
- package/dist/claims/interfaces/claim_types.js.map +1 -1
- package/dist/claims/store/claim_stores.d.ts.map +1 -1
- package/dist/claims/store/claim_stores.js +258 -20
- package/dist/claims/store/claim_stores.js.map +1 -1
- package/dist/cognitive/access_tracker.d.ts +45 -0
- package/dist/cognitive/access_tracker.d.ts.map +1 -0
- package/dist/cognitive/access_tracker.js +134 -0
- package/dist/cognitive/access_tracker.js.map +1 -0
- package/dist/cognitive/decay.d.ts +48 -0
- package/dist/cognitive/decay.d.ts.map +1 -0
- package/dist/cognitive/decay.js +73 -0
- package/dist/cognitive/decay.js.map +1 -0
- package/dist/cognitive/freshness.d.ts +36 -0
- package/dist/cognitive/freshness.d.ts.map +1 -0
- package/dist/cognitive/freshness.js +41 -0
- package/dist/cognitive/freshness.js.map +1 -0
- package/dist/cognitive/stability.d.ts +47 -0
- package/dist/cognitive/stability.d.ts.map +1 -0
- package/dist/cognitive/stability.js +90 -0
- package/dist/cognitive/stability.js.map +1 -0
- package/dist/search/search_utils.d.ts +60 -0
- package/dist/search/search_utils.d.ts.map +1 -0
- package/dist/search/search_utils.js +93 -0
- package/dist/search/search_utils.js.map +1 -0
- package/package.json +12 -3
- package/dist/api/knowledge/knowledge_api.d.ts +0 -55
- package/dist/api/knowledge/knowledge_api.d.ts.map +0 -1
- package/dist/api/knowledge/knowledge_api.js +0 -89
- package/dist/api/knowledge/knowledge_api.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,35 @@ All notable changes to Limen are documented in this file.
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0] - 2026-03-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Convenience API** (`remember`, `recall`, `forget`, `connect`, `reflect`, `promptInstructions`) — the thesis becomes accessible. 3 lines to store a belief. Full engineering controls: Design Source, Breaker pass, Certifier gate.
|
|
12
|
+
- **FTS5 Full-Text Search** (`search`) — find beliefs by content. Primary index (`unicode61` tokenizer) for Latin/Cyrillic, secondary index (`trigram`) for CJK and substring matching. External content mode (zero data duplication). Tenant-scoped. FTS5 query injection sanitized.
|
|
13
|
+
- **Cognitive Metabolism** — beliefs that breathe. FSRS power-decay formula `R(t) = (1 + t/(9*S))^(-1)` computed on every read, never stored. `effective_confidence` returned alongside raw `confidence`. Freshness classification (Fresh/Aging/Stale). Access tracking with batched flush. `minConfidence` filters by decayed confidence.
|
|
14
|
+
- **Wrongness containment** — `maxAutoConfidence` ceiling (default 0.7) prevents confidence laundering. Auto-extracted claims cannot start above 0.7 unless human-verified via `evidence_path` grounding.
|
|
15
|
+
- **Stability per claim** — predicate-based stability assignment: governance 365d, architectural 180d, finding 90d, warning 30d, ephemeral 7d, preference 120d. Configurable patterns.
|
|
16
|
+
- `retractClaim` on `ClaimApi` — programmatic claim retraction with audit trail.
|
|
17
|
+
- `searchClaims` on `ClaimApi` — programmatic FTS5 search with BM25 ranking.
|
|
18
|
+
- Migrations v37 (FTS5 primary + triggers), v38 (FTS5 CJK trigram + triggers), v39 (cognitive metabolism columns).
|
|
19
|
+
- 235 new tests (3,188 → 3,423). Every test through A21 dual-path (success + rejection).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- npm description updated to "Governed knowledge engine for AI agents."
|
|
23
|
+
- npm keywords expanded for discoverability.
|
|
24
|
+
- `BeliefView` extended with `effectiveConfidence`, `freshness`, `stability`, `lastAccessedAt`, `accessCount`.
|
|
25
|
+
- `SearchResult.score` now uses `effectiveConfidence * BM25` — old claims rank lower than fresh ones.
|
|
26
|
+
- `recall()` and `search()` return decay-aware results by default.
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
- **Knowledge API stub** (`KnowledgeApi`, `KnowledgeApiImpl`, MCP knowledge tools) — dead code that returned `{ memoriesCreated: 0 }`. Replaced by the convenience API built through full engineering controls.
|
|
30
|
+
|
|
31
|
+
## [1.2.0] - 2026-03-28
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `setDefaultAgent` API for library-mode agent identity.
|
|
35
|
+
- MCP server: session adapter with knowledge tools (subsequently removed in v1.3.0).
|
|
36
|
+
|
|
8
37
|
## [1.1.0] - 2026-03-24
|
|
9
38
|
|
|
10
39
|
### Added
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1: Convenience API eager initialization.
|
|
3
|
+
*
|
|
4
|
+
* Registers the "limen-convenience" agent and creates the convenience mission
|
|
5
|
+
* during createLimen(). This provides the missionId and taskId needed for
|
|
6
|
+
* all convenience API claim operations.
|
|
7
|
+
*
|
|
8
|
+
* Design Source: Decision 1 (MissionId for Convenience Claims)
|
|
9
|
+
* Invariants: I-CONV-01 (immediately usable), I-CONV-02 (created once, cached)
|
|
10
|
+
*
|
|
11
|
+
* Trade-off: Adds ~30ms to createLimen() (already async). All convenience
|
|
12
|
+
* methods are synchronous Result<T> after engine creation.
|
|
13
|
+
*/
|
|
14
|
+
import type { AgentId, MissionId, TaskId } from '../../kernel/interfaces/index.js';
|
|
15
|
+
import type { TimeProvider } from '../../kernel/interfaces/time.js';
|
|
16
|
+
import type { AgentApi, MissionApi } from '../interfaces/api.js';
|
|
17
|
+
/**
|
|
18
|
+
* Result of convenience initialization.
|
|
19
|
+
* Contains the cached IDs needed for all convenience operations.
|
|
20
|
+
*/
|
|
21
|
+
export interface ConvenienceInitResult {
|
|
22
|
+
readonly agentId: AgentId;
|
|
23
|
+
readonly missionId: MissionId;
|
|
24
|
+
readonly taskId: TaskId | null;
|
|
25
|
+
}
|
|
26
|
+
/** Well-known agent name for convenience API */
|
|
27
|
+
export declare const CONVENIENCE_AGENT_NAME = "limen-convenience";
|
|
28
|
+
/** Well-known mission objective for convenience API */
|
|
29
|
+
export declare const CONVENIENCE_MISSION_OBJECTIVE = "limen-convenience-api";
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the convenience API infrastructure.
|
|
32
|
+
*
|
|
33
|
+
* 1. Register (or retrieve) the "limen-convenience" agent
|
|
34
|
+
* 2. Create the convenience mission with standard config
|
|
35
|
+
* 3. Propose a task graph with a single task
|
|
36
|
+
* 4. Return cached IDs for all subsequent operations
|
|
37
|
+
*
|
|
38
|
+
* This runs during createLimen() (already async). All failures
|
|
39
|
+
* propagate as exceptions to the createLimen() caller.
|
|
40
|
+
*
|
|
41
|
+
* @param agents - The AgentApi for agent registration
|
|
42
|
+
* @param missions - The MissionApi for mission creation
|
|
43
|
+
* @param setDefaultAgent - Function to set the default agent identity
|
|
44
|
+
*/
|
|
45
|
+
export declare function initializeConvenience(agents: AgentApi, missions: MissionApi, setDefaultAgent: (agentId: AgentId) => void, time: TimeProvider): Promise<ConvenienceInitResult>;
|
|
46
|
+
//# sourceMappingURL=convenience_init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convenience_init.d.ts","sourceRoot":"","sources":["../../../src/api/convenience/convenience_init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,gDAAgD;AAChD,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,uDAAuD;AACvD,eAAO,MAAM,6BAA6B,0BAA0B,CAAC;AAErE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,QAAQ,EAChB,QAAQ,EAAE,UAAU,EACpB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,EAC3C,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,qBAAqB,CAAC,CAkFhC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1: Convenience API eager initialization.
|
|
3
|
+
*
|
|
4
|
+
* Registers the "limen-convenience" agent and creates the convenience mission
|
|
5
|
+
* during createLimen(). This provides the missionId and taskId needed for
|
|
6
|
+
* all convenience API claim operations.
|
|
7
|
+
*
|
|
8
|
+
* Design Source: Decision 1 (MissionId for Convenience Claims)
|
|
9
|
+
* Invariants: I-CONV-01 (immediately usable), I-CONV-02 (created once, cached)
|
|
10
|
+
*
|
|
11
|
+
* Trade-off: Adds ~30ms to createLimen() (already async). All convenience
|
|
12
|
+
* methods are synchronous Result<T> after engine creation.
|
|
13
|
+
*/
|
|
14
|
+
/** Well-known agent name for convenience API */
|
|
15
|
+
export const CONVENIENCE_AGENT_NAME = 'limen-convenience';
|
|
16
|
+
/** Well-known mission objective for convenience API */
|
|
17
|
+
export const CONVENIENCE_MISSION_OBJECTIVE = 'limen-convenience-api';
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the convenience API infrastructure.
|
|
20
|
+
*
|
|
21
|
+
* 1. Register (or retrieve) the "limen-convenience" agent
|
|
22
|
+
* 2. Create the convenience mission with standard config
|
|
23
|
+
* 3. Propose a task graph with a single task
|
|
24
|
+
* 4. Return cached IDs for all subsequent operations
|
|
25
|
+
*
|
|
26
|
+
* This runs during createLimen() (already async). All failures
|
|
27
|
+
* propagate as exceptions to the createLimen() caller.
|
|
28
|
+
*
|
|
29
|
+
* @param agents - The AgentApi for agent registration
|
|
30
|
+
* @param missions - The MissionApi for mission creation
|
|
31
|
+
* @param setDefaultAgent - Function to set the default agent identity
|
|
32
|
+
*/
|
|
33
|
+
export async function initializeConvenience(agents, missions, setDefaultAgent, time) {
|
|
34
|
+
// 1. Register agent (idempotent -- if already exists, retrieve it)
|
|
35
|
+
let agentId;
|
|
36
|
+
try {
|
|
37
|
+
const agent = await agents.register({
|
|
38
|
+
name: CONVENIENCE_AGENT_NAME,
|
|
39
|
+
domains: ['convenience'],
|
|
40
|
+
capabilities: ['remember', 'recall', 'forget', 'connect', 'reflect'],
|
|
41
|
+
});
|
|
42
|
+
agentId = agent.id;
|
|
43
|
+
}
|
|
44
|
+
catch (regErr) {
|
|
45
|
+
// Agent may already exist from a previous createLimen() with the same dataDir.
|
|
46
|
+
// Try to retrieve it instead.
|
|
47
|
+
const existing = await agents.get(CONVENIENCE_AGENT_NAME);
|
|
48
|
+
if (existing) {
|
|
49
|
+
agentId = existing.id;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
throw regErr;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// 2. Set default agent so all ClaimApi calls carry this agentId
|
|
56
|
+
setDefaultAgent(agentId);
|
|
57
|
+
// 3. Create convenience mission
|
|
58
|
+
// Deadline: 1 year from now. Budget: 1,000,000 tokens.
|
|
59
|
+
const deadline = new Date(time.nowMs() + 365 * 24 * 60 * 60 * 1000).toISOString();
|
|
60
|
+
const missionHandle = await missions.create({
|
|
61
|
+
agent: CONVENIENCE_AGENT_NAME,
|
|
62
|
+
objective: CONVENIENCE_MISSION_OBJECTIVE,
|
|
63
|
+
constraints: {
|
|
64
|
+
tokenBudget: 1_000_000,
|
|
65
|
+
deadline,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
const missionId = missionHandle.id;
|
|
69
|
+
// 4. Propose a task graph with a single convenience task
|
|
70
|
+
await missionHandle.proposeTaskGraph({
|
|
71
|
+
missionId,
|
|
72
|
+
tasks: [{
|
|
73
|
+
id: 'convenience-task',
|
|
74
|
+
description: 'Convenience API operations',
|
|
75
|
+
executionMode: 'deterministic',
|
|
76
|
+
estimatedTokens: 1_000_000,
|
|
77
|
+
}],
|
|
78
|
+
dependencies: [],
|
|
79
|
+
objectiveAlignment: 'Convenience API thin delegation layer for remember/recall/forget/connect/reflect',
|
|
80
|
+
});
|
|
81
|
+
// 5. Get the task ID from the graph
|
|
82
|
+
// The task graph creates tasks with IDs that are mission-scoped.
|
|
83
|
+
// We need to query the mission's tasks to find the one we created.
|
|
84
|
+
// The task ID format is typically the mission's task graph ID.
|
|
85
|
+
// For simplicity, we look up the mission to get the task.
|
|
86
|
+
const missionState = await missions.get(missionId);
|
|
87
|
+
if (!missionState) {
|
|
88
|
+
throw new Error(`Convenience mission ${missionId} not found after creation`);
|
|
89
|
+
}
|
|
90
|
+
// Propose task execution to get the actual taskId
|
|
91
|
+
// The taskId from the graph is a string, but we need the internal TaskId.
|
|
92
|
+
// We'll use the graph's task count to derive it.
|
|
93
|
+
// Actually, looking at the orchestration, tasks are created by proposeTaskGraph
|
|
94
|
+
// and their IDs are returned. But proposeTaskGraph returns TaskGraphOutput
|
|
95
|
+
// which has taskCount but not individual task IDs.
|
|
96
|
+
//
|
|
97
|
+
// For the convenience API, the missionId is the critical piece.
|
|
98
|
+
// The taskId can be null for convenience claims. Let me verify...
|
|
99
|
+
// Looking at ClaimCreateInput: taskId is TaskId | null.
|
|
100
|
+
// MissionId is required (not null). TaskId can be null.
|
|
101
|
+
//
|
|
102
|
+
// Decision: Use null for taskId. The missionId is sufficient for
|
|
103
|
+
// SC-11 validation. This avoids the complexity of retrieving the
|
|
104
|
+
// internal TaskId from the task graph.
|
|
105
|
+
return {
|
|
106
|
+
agentId,
|
|
107
|
+
missionId,
|
|
108
|
+
taskId: null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=convenience_init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convenience_init.js","sourceRoot":"","sources":["../../../src/api/convenience/convenience_init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAgBH,gDAAgD;AAChD,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAE1D,uDAAuD;AACvD,MAAM,CAAC,MAAM,6BAA6B,GAAG,uBAAuB,CAAC;AAErE;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAgB,EAChB,QAAoB,EACpB,eAA2C,EAC3C,IAAkB;IAElB,mEAAmE;IACnE,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;YAClC,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,YAAY,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;SACrE,CAAC,CAAC;QACH,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,MAAe,EAAE,CAAC;QACzB,+EAA+E;QAC/E,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,eAAe,CAAC,OAAO,CAAC,CAAC;IAEzB,gCAAgC;IAChC,uDAAuD;IACvD,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAClF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC1C,KAAK,EAAE,sBAAsB;QAC7B,SAAS,EAAE,6BAA6B;QACxC,WAAW,EAAE;YACX,WAAW,EAAE,SAAS;YACtB,QAAQ;SACT;KACF,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC;IAEnC,yDAAyD;IACzD,MAAM,aAAa,CAAC,gBAAgB,CAAC;QACnC,SAAS;QACT,KAAK,EAAE,CAAC;gBACN,EAAE,EAAE,kBAAkB;gBACtB,WAAW,EAAE,4BAA4B;gBACzC,aAAa,EAAE,eAAe;gBAC9B,eAAe,EAAE,SAAS;aAC3B,CAAC;QACF,YAAY,EAAE,EAAE;QAChB,kBAAkB,EAAE,kFAAkF;KACvG,CAAC,CAAC;IAEH,oCAAoC;IACpC,iEAAiE;IACjE,mEAAmE;IACnE,+DAA+D;IAC/D,0DAA0D;IAC1D,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,2BAA2B,CAAC,CAAC;IAC/E,CAAC;IAED,kDAAkD;IAClD,0EAA0E;IAC1E,iDAAiD;IACjD,gFAAgF;IAChF,2EAA2E;IAC3E,mDAAmD;IACnD,EAAE;IACF,gEAAgE;IAChE,kEAAkE;IAClE,wDAAwD;IACxD,wDAAwD;IACxD,EAAE;IACF,iEAAiE;IACjE,iEAAiE;IACjE,uCAAuC;IAEvC,OAAO;QACL,OAAO;QACP,SAAS;QACT,MAAM,EAAE,IAAI;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1 Convenience API Implementation.
|
|
3
|
+
*
|
|
4
|
+
* Thin delegation layer that translates cognitive operations (remember, recall,
|
|
5
|
+
* forget, connect, reflect) into ClaimApi system calls. No new system calls.
|
|
6
|
+
* No new database tables. No new schema.
|
|
7
|
+
*
|
|
8
|
+
* Design Source: docs/sprints/PHASE-1-DESIGN-SOURCE.md
|
|
9
|
+
* Invariants: I-CONV-01 through I-CONV-18
|
|
10
|
+
*
|
|
11
|
+
* Architecture: This is the "store" layer in the three-file pattern.
|
|
12
|
+
* convenience_types.ts (contract) -> convenience_layer.ts (implementation)
|
|
13
|
+
*
|
|
14
|
+
* Governance boundary (I-17): Only imports ClaimApi, never ClaimSystem/ClaimStore.
|
|
15
|
+
*/
|
|
16
|
+
import type { Result } from '../../kernel/interfaces/index.js';
|
|
17
|
+
import type { MissionId, TaskId } from '../../kernel/interfaces/index.js';
|
|
18
|
+
import type { DatabaseConnection } from '../../kernel/interfaces/database.js';
|
|
19
|
+
import type { TimeProvider } from '../../kernel/interfaces/time.js';
|
|
20
|
+
import type { ClaimApi } from '../interfaces/api.js';
|
|
21
|
+
import type { RememberOptions, RememberResult, RecallOptions, BeliefView, ReflectEntry, ReflectResult, SearchOptions, SearchResult } from './convenience_types.js';
|
|
22
|
+
/**
|
|
23
|
+
* Dependencies for the convenience layer.
|
|
24
|
+
* Injected during createLimen() -- no direct access to internals.
|
|
25
|
+
*/
|
|
26
|
+
export interface ConvenienceLayerDeps {
|
|
27
|
+
readonly claims: ClaimApi;
|
|
28
|
+
readonly getConnection: () => DatabaseConnection;
|
|
29
|
+
readonly time: TimeProvider;
|
|
30
|
+
readonly missionId: MissionId;
|
|
31
|
+
readonly taskId: TaskId | null;
|
|
32
|
+
readonly maxAutoConfidence: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The convenience layer interface -- methods added to the Limen object.
|
|
36
|
+
*/
|
|
37
|
+
export interface ConvenienceLayer {
|
|
38
|
+
remember(subject: string, predicate: string, value: string, options?: RememberOptions): Result<RememberResult>;
|
|
39
|
+
remember(text: string, options?: RememberOptions): Result<RememberResult>;
|
|
40
|
+
remember(subjectOrText: string, predicateOrOptions?: string | RememberOptions, value?: string, options?: RememberOptions): Result<RememberResult>;
|
|
41
|
+
recall(subject?: string, predicate?: string, options?: RecallOptions): Result<readonly BeliefView[]>;
|
|
42
|
+
forget(claimId: string, reason?: string): Result<void>;
|
|
43
|
+
connect(claimId1: string, claimId2: string, type: 'supports' | 'contradicts' | 'supersedes' | 'derived_from'): Result<void>;
|
|
44
|
+
reflect(entries: readonly ReflectEntry[]): Result<ReflectResult>;
|
|
45
|
+
promptInstructions(): string;
|
|
46
|
+
/** Phase 2 §2.4: Full-text search across claim content. */
|
|
47
|
+
search(query: string, options?: SearchOptions): Result<readonly SearchResult[]>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create the convenience layer.
|
|
51
|
+
*
|
|
52
|
+
* Returns an object with all convenience methods, ready to be spread
|
|
53
|
+
* onto the Limen engine object.
|
|
54
|
+
*
|
|
55
|
+
* All methods are synchronous Result<T> (I-CONV-01: immediately usable).
|
|
56
|
+
* Closure captures deps -- survives Object.freeze (I-CONV-15).
|
|
57
|
+
*/
|
|
58
|
+
export declare function createConvenienceLayer(deps: ConvenienceLayerDeps): ConvenienceLayer;
|
|
59
|
+
//# sourceMappingURL=convenience_layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convenience_layer.d.ts","sourceRoot":"","sources":["../../../src/api/convenience/convenience_layer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AASpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACb,MAAM,wBAAwB,CAAC;AAuChC;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,kBAAkB,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAC/G,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAC1E,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,eAAe,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAClJ,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;IACrG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5H,OAAO,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IACjE,kBAAkB,IAAI,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;CACjF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAqYnF"}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1 Convenience API Implementation.
|
|
3
|
+
*
|
|
4
|
+
* Thin delegation layer that translates cognitive operations (remember, recall,
|
|
5
|
+
* forget, connect, reflect) into ClaimApi system calls. No new system calls.
|
|
6
|
+
* No new database tables. No new schema.
|
|
7
|
+
*
|
|
8
|
+
* Design Source: docs/sprints/PHASE-1-DESIGN-SOURCE.md
|
|
9
|
+
* Invariants: I-CONV-01 through I-CONV-18
|
|
10
|
+
*
|
|
11
|
+
* Architecture: This is the "store" layer in the three-file pattern.
|
|
12
|
+
* convenience_types.ts (contract) -> convenience_layer.ts (implementation)
|
|
13
|
+
*
|
|
14
|
+
* Governance boundary (I-17): Only imports ClaimApi, never ClaimSystem/ClaimStore.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import { VALID_RELATIONSHIP_TYPES, VALID_CATEGORIES, MAX_STATEMENT_LENGTH, MAX_REFLECT_ENTRIES, DEFAULT_RECALL_LIMIT, DEFAULT_SEARCH_LIMIT, MAX_SEARCH_LIMIT, } from './convenience_types.js';
|
|
18
|
+
import { generatePromptInstructions } from './convenience_prompt.js';
|
|
19
|
+
// ── Result Helpers ──
|
|
20
|
+
function ok(value) {
|
|
21
|
+
return { ok: true, value };
|
|
22
|
+
}
|
|
23
|
+
function err(code, message) {
|
|
24
|
+
return { ok: false, error: { code, message, spec: 'Phase-1' } };
|
|
25
|
+
}
|
|
26
|
+
// ── SHA-256 Subject Generation ──
|
|
27
|
+
/**
|
|
28
|
+
* Generate a subject URN from text content using SHA-256.
|
|
29
|
+
* Format: entity:observation:<sha256-hex-first-12>
|
|
30
|
+
*
|
|
31
|
+
* I-CONV-13: Satisfies CCP subject validation (3 colon-separated segments).
|
|
32
|
+
*/
|
|
33
|
+
function hashSubject(text) {
|
|
34
|
+
const hash = createHash('sha256').update(text, 'utf8').digest('hex');
|
|
35
|
+
return `entity:observation:${hash.substring(0, 12)}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create the convenience layer.
|
|
39
|
+
*
|
|
40
|
+
* Returns an object with all convenience methods, ready to be spread
|
|
41
|
+
* onto the Limen engine object.
|
|
42
|
+
*
|
|
43
|
+
* All methods are synchronous Result<T> (I-CONV-01: immediately usable).
|
|
44
|
+
* Closure captures deps -- survives Object.freeze (I-CONV-15).
|
|
45
|
+
*/
|
|
46
|
+
export function createConvenienceLayer(deps) {
|
|
47
|
+
const { claims, getConnection, time, missionId, taskId, maxAutoConfidence } = deps;
|
|
48
|
+
/**
|
|
49
|
+
* Compute effective confidence, applying the maxAutoConfidence cap
|
|
50
|
+
* unless evidence_path grounding with non-empty evidenceRefs is provided.
|
|
51
|
+
*
|
|
52
|
+
* I-CONV-04 (CONSTITUTIONAL): Cap enforcement.
|
|
53
|
+
* I-CONV-05 (CONSTITUTIONAL): Bypass with evidence.
|
|
54
|
+
*/
|
|
55
|
+
function effectiveConfidence(requestedConfidence, groundingMode, evidenceRefs) {
|
|
56
|
+
const confidence = requestedConfidence ?? maxAutoConfidence;
|
|
57
|
+
// Bypass: evidence_path with non-empty evidenceRefs
|
|
58
|
+
if (groundingMode === 'evidence_path' && evidenceRefs && evidenceRefs.length > 0) {
|
|
59
|
+
return confidence;
|
|
60
|
+
}
|
|
61
|
+
// Cap at maxAutoConfidence
|
|
62
|
+
return Math.min(confidence, maxAutoConfidence);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 3-param remember: explicit subject, predicate, value.
|
|
66
|
+
*/
|
|
67
|
+
function remember3(subject, predicate, value, options) {
|
|
68
|
+
// Validate confidence if provided
|
|
69
|
+
if (options?.confidence !== undefined) {
|
|
70
|
+
if (!Number.isFinite(options.confidence) || options.confidence < 0 || options.confidence > 1) {
|
|
71
|
+
return err('CONV_INVALID_CONFIDENCE', `Confidence must be in [0.0, 1.0], got ${options.confidence}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const groundingMode = options?.groundingMode ?? 'runtime_witness';
|
|
75
|
+
const evidenceRefs = options?.evidenceRefs ?? [];
|
|
76
|
+
const confidence = effectiveConfidence(options?.confidence, groundingMode, evidenceRefs);
|
|
77
|
+
const validAt = options?.validAt ?? time.nowISO();
|
|
78
|
+
const objectType = options?.objectType ?? 'string';
|
|
79
|
+
// Design Source §Grounding Mode Decision:
|
|
80
|
+
// evidence_path with empty evidenceRefs falls back to runtime_witness behavior.
|
|
81
|
+
// This prevents SC-11 rejection AND prevents confidence laundering.
|
|
82
|
+
const effectiveGroundingMode = (groundingMode === 'evidence_path' && evidenceRefs.length > 0)
|
|
83
|
+
? 'evidence_path'
|
|
84
|
+
: 'runtime_witness';
|
|
85
|
+
const input = {
|
|
86
|
+
subject,
|
|
87
|
+
predicate,
|
|
88
|
+
object: { type: objectType, value },
|
|
89
|
+
confidence,
|
|
90
|
+
validAt,
|
|
91
|
+
missionId,
|
|
92
|
+
taskId,
|
|
93
|
+
evidenceRefs: effectiveGroundingMode === 'evidence_path'
|
|
94
|
+
? evidenceRefs.map(ref => ({ type: ref.type, id: ref.id }))
|
|
95
|
+
: [],
|
|
96
|
+
groundingMode: effectiveGroundingMode,
|
|
97
|
+
...(effectiveGroundingMode === 'runtime_witness' ? {
|
|
98
|
+
runtimeWitness: {
|
|
99
|
+
witnessType: 'convenience',
|
|
100
|
+
witnessedValues: { source: 'remember' },
|
|
101
|
+
witnessTimestamp: validAt,
|
|
102
|
+
},
|
|
103
|
+
} : {}),
|
|
104
|
+
};
|
|
105
|
+
const result = claims.assertClaim(input);
|
|
106
|
+
if (!result.ok)
|
|
107
|
+
return result;
|
|
108
|
+
return ok({
|
|
109
|
+
claimId: result.value.claim.id,
|
|
110
|
+
confidence: result.value.claim.confidence,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 1-param remember: auto-generate subject from text hash.
|
|
115
|
+
*/
|
|
116
|
+
function remember1(text, options) {
|
|
117
|
+
// Validate text is non-empty and not whitespace-only (I-CONV-09)
|
|
118
|
+
if (!text || text.trim().length === 0) {
|
|
119
|
+
return err('CONV_INVALID_TEXT', 'Text must be non-empty and not whitespace-only');
|
|
120
|
+
}
|
|
121
|
+
const subject = hashSubject(text);
|
|
122
|
+
return remember3(subject, 'observation.note', text, options);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
/**
|
|
126
|
+
* Phase 1 §1.1/§1.2: Store a belief.
|
|
127
|
+
*
|
|
128
|
+
* Overload resolution (I-CONV-12):
|
|
129
|
+
* typeof secondArg === 'string' -> 3-param form
|
|
130
|
+
* otherwise -> 1-param form
|
|
131
|
+
*/
|
|
132
|
+
remember(subjectOrText, predicateOrOptions, value, options) {
|
|
133
|
+
if (typeof predicateOrOptions === 'string') {
|
|
134
|
+
// 3-param form: (subject, predicate, value, options?)
|
|
135
|
+
return remember3(subjectOrText, predicateOrOptions, value, options);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// 1-param form: (text, options?)
|
|
139
|
+
return remember1(subjectOrText, predicateOrOptions);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Phase 1 §1.3: Retrieve beliefs.
|
|
144
|
+
*
|
|
145
|
+
* I-CONV-08: Excludes superseded claims by default.
|
|
146
|
+
*/
|
|
147
|
+
recall(subject, predicate, options) {
|
|
148
|
+
const input = {
|
|
149
|
+
...(subject ? { subject } : {}),
|
|
150
|
+
...(predicate ? { predicate } : {}),
|
|
151
|
+
status: 'active',
|
|
152
|
+
...(options?.minConfidence !== undefined ? { minConfidence: options.minConfidence } : {}),
|
|
153
|
+
limit: options?.limit ?? DEFAULT_RECALL_LIMIT,
|
|
154
|
+
includeEvidence: false,
|
|
155
|
+
includeRelationships: false,
|
|
156
|
+
};
|
|
157
|
+
const result = claims.queryClaims(input);
|
|
158
|
+
if (!result.ok)
|
|
159
|
+
return result;
|
|
160
|
+
// Map ClaimQueryResultItem -> BeliefView
|
|
161
|
+
let items = result.value.claims;
|
|
162
|
+
// I-CONV-08: Filter superseded unless explicitly included
|
|
163
|
+
if (!options?.includeSuperseded) {
|
|
164
|
+
items = items.filter(item => !item.superseded);
|
|
165
|
+
}
|
|
166
|
+
const beliefs = items.map(item => ({
|
|
167
|
+
claimId: item.claim.id,
|
|
168
|
+
subject: item.claim.subject,
|
|
169
|
+
predicate: item.claim.predicate,
|
|
170
|
+
value: String(item.claim.object.value),
|
|
171
|
+
confidence: item.claim.confidence,
|
|
172
|
+
validAt: item.claim.validAt,
|
|
173
|
+
createdAt: item.claim.createdAt,
|
|
174
|
+
superseded: item.superseded,
|
|
175
|
+
disputed: item.disputed,
|
|
176
|
+
// Phase 3: Cognitive Metabolism fields
|
|
177
|
+
effectiveConfidence: item.effectiveConfidence,
|
|
178
|
+
freshness: item.freshness,
|
|
179
|
+
stability: item.claim.stability,
|
|
180
|
+
lastAccessedAt: item.claim.lastAccessedAt,
|
|
181
|
+
accessCount: item.claim.accessCount,
|
|
182
|
+
}));
|
|
183
|
+
return ok(beliefs);
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* Phase 1 §1.4: Retract a belief.
|
|
187
|
+
*
|
|
188
|
+
* I-CONV-11: Delegates to ClaimApi.retractClaim().
|
|
189
|
+
* I-CONV-14: Maps system-call errors to convenience error codes.
|
|
190
|
+
*/
|
|
191
|
+
forget(claimId, reason) {
|
|
192
|
+
const input = {
|
|
193
|
+
claimId: claimId,
|
|
194
|
+
reason: reason ?? 'Retracted via forget()',
|
|
195
|
+
};
|
|
196
|
+
const result = claims.retractClaim(input);
|
|
197
|
+
if (!result.ok) {
|
|
198
|
+
// Map well-known error codes
|
|
199
|
+
if (result.error.code === 'CLAIM_NOT_FOUND') {
|
|
200
|
+
return err('CONV_CLAIM_NOT_FOUND', result.error.message);
|
|
201
|
+
}
|
|
202
|
+
if (result.error.code === 'CLAIM_ALREADY_RETRACTED') {
|
|
203
|
+
return err('CONV_ALREADY_RETRACTED', result.error.message);
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
return ok(undefined);
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Phase 1 §1.5: Create a relationship between two claims.
|
|
211
|
+
*
|
|
212
|
+
* DC-P1-804: Validates relationship type.
|
|
213
|
+
* DC-P1-805: Rejects self-reference.
|
|
214
|
+
*/
|
|
215
|
+
connect(claimId1, claimId2, type) {
|
|
216
|
+
// Validate relationship type
|
|
217
|
+
if (!VALID_RELATIONSHIP_TYPES.includes(type)) {
|
|
218
|
+
return err('CONV_INVALID_RELATIONSHIP', `Invalid relationship type: ${type}. Must be one of: ${VALID_RELATIONSHIP_TYPES.join(', ')}`);
|
|
219
|
+
}
|
|
220
|
+
const input = {
|
|
221
|
+
fromClaimId: claimId1,
|
|
222
|
+
toClaimId: claimId2,
|
|
223
|
+
type: type,
|
|
224
|
+
missionId,
|
|
225
|
+
};
|
|
226
|
+
const result = claims.relateClaims(input);
|
|
227
|
+
if (!result.ok) {
|
|
228
|
+
// Map well-known error codes
|
|
229
|
+
if (result.error.code === 'SELF_REFERENCE') {
|
|
230
|
+
return err('CONV_SELF_REFERENCE', result.error.message);
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
return ok(undefined);
|
|
235
|
+
},
|
|
236
|
+
/**
|
|
237
|
+
* Phase 1 §1.6: Batch-store categorized learnings.
|
|
238
|
+
*
|
|
239
|
+
* I-CONV-10: All-or-nothing transaction semantics.
|
|
240
|
+
* Uses SQLite BEGIN/COMMIT/ROLLBACK via getConnection().
|
|
241
|
+
*/
|
|
242
|
+
reflect(entries) {
|
|
243
|
+
// Validate: non-empty entries
|
|
244
|
+
if (!entries || entries.length === 0) {
|
|
245
|
+
return err('CONV_EMPTY_ENTRIES', 'reflect() requires at least one entry');
|
|
246
|
+
}
|
|
247
|
+
// Validate: entries count limit (F-P1-008: DoS protection)
|
|
248
|
+
if (entries.length > MAX_REFLECT_ENTRIES) {
|
|
249
|
+
return err('CONV_ENTRIES_LIMIT', `reflect() accepts at most ${MAX_REFLECT_ENTRIES} entries, got ${entries.length}`);
|
|
250
|
+
}
|
|
251
|
+
// Pre-validate all entries before starting transaction
|
|
252
|
+
for (let i = 0; i < entries.length; i++) {
|
|
253
|
+
const entry = entries[i];
|
|
254
|
+
// Validate category
|
|
255
|
+
if (!VALID_CATEGORIES.includes(entry.category)) {
|
|
256
|
+
return err('CONV_INVALID_CATEGORY', `Entry ${i}: invalid category '${entry.category}'. Must be one of: ${VALID_CATEGORIES.join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
// Validate statement length
|
|
259
|
+
if (entry.statement.length > MAX_STATEMENT_LENGTH) {
|
|
260
|
+
return err('CONV_STATEMENT_TOO_LONG', `Entry ${i}: statement exceeds ${MAX_STATEMENT_LENGTH} characters (${entry.statement.length})`);
|
|
261
|
+
}
|
|
262
|
+
// Validate confidence if provided
|
|
263
|
+
if (entry.confidence !== undefined) {
|
|
264
|
+
if (!Number.isFinite(entry.confidence) || entry.confidence < 0 || entry.confidence > 1) {
|
|
265
|
+
return err('CONV_INVALID_CONFIDENCE', `Entry ${i}: confidence must be in [0.0, 1.0], got ${entry.confidence}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Transaction: all-or-nothing
|
|
270
|
+
const conn = getConnection();
|
|
271
|
+
conn.run('BEGIN');
|
|
272
|
+
try {
|
|
273
|
+
const claimIds = [];
|
|
274
|
+
for (const entry of entries) {
|
|
275
|
+
const subject = hashSubject(entry.statement);
|
|
276
|
+
const confidence = Math.min(entry.confidence ?? maxAutoConfidence, maxAutoConfidence);
|
|
277
|
+
const validAt = time.nowISO();
|
|
278
|
+
const input = {
|
|
279
|
+
subject,
|
|
280
|
+
predicate: `reflection.${entry.category}`,
|
|
281
|
+
object: { type: 'string', value: entry.statement },
|
|
282
|
+
confidence,
|
|
283
|
+
validAt,
|
|
284
|
+
missionId,
|
|
285
|
+
taskId,
|
|
286
|
+
evidenceRefs: [],
|
|
287
|
+
groundingMode: 'runtime_witness',
|
|
288
|
+
runtimeWitness: {
|
|
289
|
+
witnessType: 'convenience',
|
|
290
|
+
witnessedValues: { source: 'reflect', category: entry.category },
|
|
291
|
+
witnessTimestamp: validAt,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
const result = claims.assertClaim(input);
|
|
295
|
+
if (!result.ok) {
|
|
296
|
+
conn.run('ROLLBACK');
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
claimIds.push(result.value.claim.id);
|
|
300
|
+
}
|
|
301
|
+
conn.run('COMMIT');
|
|
302
|
+
return ok({ stored: claimIds.length, claimIds });
|
|
303
|
+
}
|
|
304
|
+
catch (catchErr) {
|
|
305
|
+
try {
|
|
306
|
+
conn.run('ROLLBACK');
|
|
307
|
+
}
|
|
308
|
+
catch { /* already rolled back */ }
|
|
309
|
+
return err('CONV_BATCH_PARTIAL', `reflect() failed: ${String(catchErr)}`);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
/**
|
|
313
|
+
* Phase 1 §1.7: Get system prompt instructions.
|
|
314
|
+
*
|
|
315
|
+
* I-CONV-18: Pure function, no I/O, deterministic.
|
|
316
|
+
*/
|
|
317
|
+
promptInstructions() {
|
|
318
|
+
return generatePromptInstructions();
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* Phase 2 §2.4: Full-text search across claim content.
|
|
322
|
+
*
|
|
323
|
+
* Delegates to ClaimApi.searchClaims(). Maps SearchClaimResultItem -> SearchResult.
|
|
324
|
+
*
|
|
325
|
+
* Invariants: I-P2-02 (tenant isolation via facade), I-P2-05 (score), I-P2-07 (input validation)
|
|
326
|
+
* DCs: DC-P2-012 (limit validation), DC-P2-013 (empty query validation)
|
|
327
|
+
*/
|
|
328
|
+
search(query, options) {
|
|
329
|
+
// I-P2-07: Validate query is non-empty
|
|
330
|
+
if (!query || query.trim().length === 0) {
|
|
331
|
+
return err('CONV_SEARCH_EMPTY_QUERY', 'Search query must be non-empty and not whitespace-only');
|
|
332
|
+
}
|
|
333
|
+
// I-P2-07: Validate limit
|
|
334
|
+
const limit = options?.limit ?? DEFAULT_SEARCH_LIMIT;
|
|
335
|
+
if (limit <= 0 || limit > MAX_SEARCH_LIMIT) {
|
|
336
|
+
return err('CONV_SEARCH_INVALID_LIMIT', `Search limit must be in [1, ${MAX_SEARCH_LIMIT}], got ${limit}`);
|
|
337
|
+
}
|
|
338
|
+
const input = {
|
|
339
|
+
query: query.trim(),
|
|
340
|
+
...(options?.minConfidence !== undefined ? { minConfidence: options.minConfidence } : {}),
|
|
341
|
+
limit,
|
|
342
|
+
...(options?.includeSuperseded !== undefined ? { includeSuperseded: options.includeSuperseded } : {}),
|
|
343
|
+
};
|
|
344
|
+
const result = claims.searchClaims(input);
|
|
345
|
+
if (!result.ok)
|
|
346
|
+
return result;
|
|
347
|
+
// Map SearchClaimResultItem -> SearchResult (convenience type)
|
|
348
|
+
const searchResults = result.value.results.map(item => ({
|
|
349
|
+
belief: {
|
|
350
|
+
claimId: item.claim.id,
|
|
351
|
+
subject: item.claim.subject,
|
|
352
|
+
predicate: item.claim.predicate,
|
|
353
|
+
value: String(item.claim.object.value),
|
|
354
|
+
confidence: item.claim.confidence,
|
|
355
|
+
validAt: item.claim.validAt,
|
|
356
|
+
createdAt: item.claim.createdAt,
|
|
357
|
+
superseded: item.superseded,
|
|
358
|
+
disputed: item.disputed,
|
|
359
|
+
// Phase 3: Cognitive Metabolism fields
|
|
360
|
+
effectiveConfidence: item.effectiveConfidence,
|
|
361
|
+
freshness: item.freshness,
|
|
362
|
+
stability: item.claim.stability,
|
|
363
|
+
lastAccessedAt: item.claim.lastAccessedAt,
|
|
364
|
+
accessCount: item.claim.accessCount,
|
|
365
|
+
},
|
|
366
|
+
relevance: item.relevance,
|
|
367
|
+
score: item.score,
|
|
368
|
+
}));
|
|
369
|
+
return ok(searchResults);
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=convenience_layer.js.map
|