iranti 0.1.3 → 0.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 (85) hide show
  1. package/README.md +203 -7
  2. package/dist/scripts/iranti-cli.js +1030 -35
  3. package/dist/scripts/iranti-mcp.js +30 -11
  4. package/dist/scripts/seed.js +10 -10
  5. package/dist/src/api/middleware/validation.d.ts +1 -1
  6. package/dist/src/api/middleware/validation.js +1 -1
  7. package/dist/src/api/middleware/validation.js.map +1 -1
  8. package/dist/src/api/routes/knowledge.d.ts.map +1 -1
  9. package/dist/src/api/routes/knowledge.js +29 -1
  10. package/dist/src/api/routes/knowledge.js.map +1 -1
  11. package/dist/src/api/server.js +1 -1
  12. package/dist/src/archivist/index.d.ts.map +1 -1
  13. package/dist/src/archivist/index.js +99 -54
  14. package/dist/src/archivist/index.js.map +1 -1
  15. package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
  16. package/dist/src/attendant/AttendantInstance.js +17 -6
  17. package/dist/src/attendant/AttendantInstance.js.map +1 -1
  18. package/dist/src/generated/prisma/commonInputTypes.d.ts +181 -50
  19. package/dist/src/generated/prisma/commonInputTypes.d.ts.map +1 -1
  20. package/dist/src/generated/prisma/enums.d.ts +21 -1
  21. package/dist/src/generated/prisma/enums.d.ts.map +1 -1
  22. package/dist/src/generated/prisma/enums.js +19 -0
  23. package/dist/src/generated/prisma/enums.js.map +1 -1
  24. package/dist/src/generated/prisma/internal/class.js +4 -4
  25. package/dist/src/generated/prisma/internal/class.js.map +1 -1
  26. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts +34 -4
  27. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts.map +1 -1
  28. package/dist/src/generated/prisma/internal/prismaNamespace.js +6 -0
  29. package/dist/src/generated/prisma/internal/prismaNamespace.js.map +1 -1
  30. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts +6 -0
  31. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  32. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js +6 -0
  33. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -1
  34. package/dist/src/generated/prisma/models/Archive.d.ts +110 -16
  35. package/dist/src/generated/prisma/models/Archive.d.ts.map +1 -1
  36. package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts +100 -3
  37. package/dist/src/generated/prisma/models/KnowledgeEntry.d.ts.map +1 -1
  38. package/dist/src/lib/decay.d.ts +13 -0
  39. package/dist/src/lib/decay.d.ts.map +1 -0
  40. package/dist/src/lib/decay.js +54 -0
  41. package/dist/src/lib/decay.js.map +1 -0
  42. package/dist/src/lib/llm.d.ts +2 -0
  43. package/dist/src/lib/llm.d.ts.map +1 -1
  44. package/dist/src/lib/llm.js +57 -0
  45. package/dist/src/lib/llm.js.map +1 -1
  46. package/dist/src/lib/providers/claude.d.ts.map +1 -1
  47. package/dist/src/lib/providers/claude.js +12 -5
  48. package/dist/src/lib/providers/claude.js.map +1 -1
  49. package/dist/src/lib/providers/gemini.d.ts.map +1 -1
  50. package/dist/src/lib/providers/gemini.js +3 -1
  51. package/dist/src/lib/providers/gemini.js.map +1 -1
  52. package/dist/src/lib/providers/groq.d.ts.map +1 -1
  53. package/dist/src/lib/providers/groq.js +3 -1
  54. package/dist/src/lib/providers/groq.js.map +1 -1
  55. package/dist/src/lib/providers/mistral.d.ts.map +1 -1
  56. package/dist/src/lib/providers/mistral.js +3 -1
  57. package/dist/src/lib/providers/mistral.js.map +1 -1
  58. package/dist/src/lib/providers/mock.d.ts.map +1 -1
  59. package/dist/src/lib/providers/mock.js +25 -4
  60. package/dist/src/lib/providers/mock.js.map +1 -1
  61. package/dist/src/lib/providers/openai.d.ts.map +1 -1
  62. package/dist/src/lib/providers/openai.js +2 -2
  63. package/dist/src/lib/providers/openai.js.map +1 -1
  64. package/dist/src/librarian/chunker.d.ts +1 -0
  65. package/dist/src/librarian/chunker.d.ts.map +1 -1
  66. package/dist/src/librarian/chunker.js +50 -10
  67. package/dist/src/librarian/chunker.js.map +1 -1
  68. package/dist/src/librarian/index.d.ts +3 -0
  69. package/dist/src/librarian/index.d.ts.map +1 -1
  70. package/dist/src/librarian/index.js +168 -198
  71. package/dist/src/librarian/index.js.map +1 -1
  72. package/dist/src/library/queries.d.ts +36 -7
  73. package/dist/src/library/queries.d.ts.map +1 -1
  74. package/dist/src/library/queries.js +160 -31
  75. package/dist/src/library/queries.js.map +1 -1
  76. package/dist/src/sdk/index.d.ts +38 -3
  77. package/dist/src/sdk/index.d.ts.map +1 -1
  78. package/dist/src/sdk/index.js +131 -61
  79. package/dist/src/sdk/index.js.map +1 -1
  80. package/dist/src/types.d.ts +6 -1
  81. package/dist/src/types.d.ts.map +1 -1
  82. package/package.json +7 -1
  83. package/prisma/migrations/20260314120000_add_temporal_versioning_mvp/migration.sql +61 -0
  84. package/prisma/migrations/20260314164000_add_memory_decay_fields/migration.sql +23 -0
  85. package/prisma/schema.prisma +45 -16
package/README.md CHANGED
@@ -70,6 +70,34 @@ Validated with multiple agent frameworks:
70
70
 
71
71
  Full validation report: [`docs/internal/validation_results.md`](docs/internal/validation_results.md) | Multi-framework details: [`docs/internal/MULTI_FRAMEWORK_VALIDATION.md`](docs/internal/MULTI_FRAMEWORK_VALIDATION.md)
72
72
 
73
+ ### Conflict Benchmark Baseline
74
+
75
+ Iranti now also has an adversarial conflict benchmark that measures contradiction handling rather than basic retrieval.
76
+
77
+ | Suite | Score | Notes |
78
+ |---|---|---|
79
+ | **Direct contradiction** | `4/4` | Same entity+key conflicts are explicitly resolved or escalated |
80
+ | **Temporal conflict** | `3/4` | One known-failing edge remains |
81
+ | **Cascading conflict** | `0/4` | Cross-key contradiction detection not implemented yet |
82
+ | **Multi-hop conflict** | `0/4` | Graph-aware conflict reasoning not implemented yet |
83
+ | **Total** | `7/16 (44%)` | Honest baseline for the current Librarian |
84
+
85
+ Conflict benchmark methodology: [`docs/internal/conflict_benchmark.md`](docs/internal/conflict_benchmark.md)
86
+
87
+ ### Consistency Validation
88
+
89
+ Iranti also now documents and validates its consistency model empirically:
90
+
91
+ | Check | Result |
92
+ |---|---|
93
+ | Concurrent write serialization | `PASS` |
94
+ | Read-after-write visibility | `PASS` |
95
+ | Escalation state integrity | `PASS` |
96
+ | Observe isolation from uncommitted writes | `PASS` |
97
+ | **Total** | `4/4` |
98
+
99
+ Consistency model and validation: [`docs/internal/consistency_model.md`](docs/internal/consistency_model.md)
100
+
73
101
  ### Goal 1: Easy Integration
74
102
 
75
103
  - **Entity**: `project/quantum_bridge`
@@ -108,9 +136,93 @@ Full validation report: [`docs/internal/validation_results.md`](docs/internal/va
108
136
 
109
137
  Full validation report: [`docs/internal/validation_results.md`](docs/internal/validation_results.md)
110
138
 
139
+ ## Gap Analysis
140
+
141
+ Iranti targets a specific gap in the agent infrastructure stack: most competing systems give you semantic retrieval, framework-specific memory, or raw vector storage, but not the same combination of structured fact storage, cross-agent sharing, identity-based lookup, explicit confidence, and developer-visible conflict handling in one self-hostable package.
142
+
143
+ The current competitive case for Iranti is strongest when a team needs memory that behaves more like shared infrastructure than a chat transcript: facts are attached to entities, retrieved deterministically by `entityType/entityId + key`, versioned over time, and made available across agents without framework lock-in.
144
+
145
+ ### Where Iranti Is Differentiated
146
+
147
+ - Identity-first fact retrieval through `entityType/entityId + key`
148
+ - Cross-agent fact sharing as a first-class model
149
+ - Conflict-aware writes through the Librarian
150
+ - Explicit per-fact confidence scores
151
+ - Per-agent memory injection through the Attendant
152
+ - Temporal exact lookup with `asOf` and ordered `history()`
153
+ - Relationship primitives through `relate()`, `getRelated()`, and `getRelatedDeep()`
154
+ - Hybrid retrieval when exact keys are unknown
155
+ - Local install + project binding flow for Claude Code and Codex
156
+ - Published npm / PyPI surfaces with machine-level CLI setup
157
+
158
+ ### Why That Gap Exists
159
+
160
+ The current landscape splits into three buckets:
161
+
162
+ 1. **Memory libraries**
163
+ - Systems like Mem0, Zep, Letta, and framework-native memory layers solve parts of the problem.
164
+ - They usually optimize for semantic retrieval, agent-local memory, or framework integration.
165
+ - They rarely expose deterministic `entity + key` lookup, explicit confidence surfaces, and developer-controlled conflict handling together.
166
+
167
+ 2. **Vector databases**
168
+ - Pinecone, Weaviate, Qdrant, Chroma, Milvus, LanceDB, and `pgvector` solve storage and retrieval infrastructure.
169
+ - They do not, by themselves, solve memory semantics such as conflict resolution, context injection, fact lifecycle, or shared agent-facing state.
170
+
171
+ 3. **Multi-agent frameworks**
172
+ - CrewAI, LangGraph, AutoGen, CAMEL, MetaGPT, and similar frameworks often include some memory support.
173
+ - In practice, that memory is usually framework-coupled, shallow on conflict semantics, and difficult to reuse outside the framework that created it.
174
+
175
+ ### Main Gaps
176
+
177
+ 1. **Operational maturity**
178
+ - Local PostgreSQL setup is still a real source of friction.
179
+ - The product needs stronger diagnostics, connection recovery, and less dependence on users debugging local database state by hand.
180
+
181
+ 2. **Onboarding still has sharp edges**
182
+ - `iranti setup` is materially better than before, but first-run still assumes too much infrastructure literacy.
183
+ - Managed Postgres paths, cleaner bootstrap verification, and fewer environment-level surprises are still needed.
184
+
185
+ 3. **No operator UI yet**
186
+ - Iranti is still CLI-first.
187
+ - There is no control plane yet for provider keys, project bindings, integrations, memory inspection, and escalation review.
188
+
189
+ 4. **Adoption proof is still early**
190
+ - The repo has validation experiments and real local end-to-end usage, but broad production adoption is still limited.
191
+ - The next product truth has to come from external users and real workloads, not more speculative architecture alone.
192
+
193
+ 5. **Hosted product is not built**
194
+ - Open-source/local infrastructure is the active surface today.
195
+ - Hosted deployment, multi-tenant operations, billing, and cloud onboarding remain future work.
196
+
197
+ 6. **Graph-native reasoning is still limited**
198
+ - Iranti supports explicit entity relationships today.
199
+ - It does not yet compete with graph-first systems on temporal graph traversal or graph-native reasoning depth.
200
+
201
+ 7. **Memory extraction is not the main model**
202
+ - Iranti supports structured writes and ingest/chunking, but it is not primarily a "dump arbitrary conversations in and auto-magically derive perfect memory" system.
203
+ - That is a deliberate tradeoff in favor of explicit, inspectable facts, but it increases integration work.
204
+
205
+ ### Current Position
206
+
207
+ Iranti is strongest today as infrastructure for developers building multi-agent systems who need shared, structured, queryable memory rather than pure semantic recall. The current evidence base is now more concrete than a positioning claim alone:
208
+
209
+ - `16/16` fictional-fact transfer in retrieval validation
210
+ - `7/16 (44%)` on an adversarial conflict benchmark
211
+ - `4/4` on empirical consistency validation for serialized writes and read visibility
212
+
213
+ That is not a claim that multi-agent memory is solved. It is a claim that Iranti now has reproducible evidence for three things at once:
214
+
215
+ - exact cross-agent fact transfer works
216
+ - same-key conflicting writes are serialized and observable
217
+ - conflict handling quality is measurable, including clearly documented failure modes
218
+
219
+ The next leverage is still product simplicity: setup, operations, and day-to-day inspection need to be simple enough that real users keep Iranti in the loop.
220
+
111
221
  ## Quickstart
112
222
 
113
- **Requirements**: Node.js 18+, Docker, Python 3.8+
223
+ **Requirements**: Node.js 18+, PostgreSQL, Python 3.8+
224
+
225
+ Docker is optional. It is one local way to run PostgreSQL if you do not already have a database.
114
226
 
115
227
  ```bash
116
228
  # 1. Clone and configure
@@ -136,6 +248,9 @@ npm run api # Runs on port 3001
136
248
 
137
249
  # 5. Install Python client
138
250
  pip install iranti
251
+
252
+ # Optional: install the TypeScript client
253
+ npm install @iranti/sdk
139
254
  ```
140
255
 
141
256
  ### Archivist Scheduling Knobs
@@ -220,9 +335,37 @@ npm install -g .
220
335
  ### 2) Initialize machine runtime root
221
336
 
222
337
  ```bash
338
+ iranti setup
339
+
340
+ # non-interactive automation
341
+ iranti setup --defaults --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
342
+ iranti setup --config ./iranti.setup.json
343
+
344
+ # or, if you want the lower-level manual path:
223
345
  iranti install --scope user
224
346
  ```
225
347
 
348
+ `iranti setup` is the recommended first-run path. It walks through:
349
+ - shared vs isolated runtime setup
350
+ - instance creation or update
351
+ - API port selection with conflict detection and next-free suggestions
352
+ - database onboarding:
353
+ - existing Postgres
354
+ - managed Postgres
355
+ - optional Docker-hosted Postgres for local development
356
+ - provider API keys
357
+ - Iranti client API key generation
358
+ - one or more project bindings
359
+ - optional Claude Code / Codex integration scaffolding
360
+
361
+ For automation:
362
+ - `iranti setup --defaults` uses sensible defaults plus environment/flag input, but still requires a real `DATABASE_URL`.
363
+ - `iranti setup --config <file>` reads a JSON setup plan for repeatable bootstrap.
364
+ - `--bootstrap-db` runs migrations and seeding during automated setup when the database is reachable.
365
+ - Example config: [docs/guides/iranti.setup.example.json](docs/guides/iranti.setup.example.json)
366
+
367
+ Default API port remains `3001`. The setup wizard now warns when that port is already in use and suggests the next free port instead of forcing users to debug the collision manually.
368
+
226
369
  Defaults:
227
370
  - Windows user scope: `%USERPROFILE%\\.iranti`
228
371
  - Windows system scope: `%ProgramData%\\Iranti`
@@ -243,11 +386,17 @@ Finish onboarding or change settings later with:
243
386
  iranti configure instance local --provider openai --provider-key sk-... --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
244
387
  iranti configure instance local --interactive
245
388
 
389
+ # Provider key shortcuts
390
+ iranti list api-keys --instance local
391
+ iranti add api-key openai --instance local
392
+ iranti update api-key claude --instance local
393
+ iranti remove api-key gemini --instance local
394
+
246
395
  # Create a registry-backed API key and sync it into the instance env
247
396
  iranti auth create-key --instance local --key-id local_admin --owner "Local Admin" --scopes "kb:read,kb:write,memory:read,memory:write,agents:read,agents:write" --write-instance
248
397
  ```
249
398
 
250
- You can rerun `iranti configure instance ...` later to rotate provider keys or replace the instance API token.
399
+ `iranti add|update|remove api-key` updates the stored upstream provider credentials in the instance env without hand-editing `.env` files. `iranti list api-keys` shows which provider keys are currently stored. Supported remote providers are OpenAI, Claude, Gemini, Groq, and Mistral. `mock` and `ollama` do not require remote API keys, and Perplexity is not yet supported.
251
400
 
252
401
  ### 4) Run Iranti from that instance
253
402
 
@@ -255,6 +404,8 @@ You can rerun `iranti configure instance ...` later to rotate provider keys or r
255
404
  iranti run --instance local
256
405
  ```
257
406
 
407
+ If a provider rejects requests because credits are exhausted, billing is disabled, or the account is quota-limited, Iranti now surfaces a direct message such as `OpenAI quota or billing limit reached. Add credits, update the API key, or switch providers.`
408
+
258
409
  ### 5) Bind any chatbot/app project to that instance
259
410
 
260
411
  ```bash
@@ -338,6 +489,51 @@ for fact in facts:
338
489
  print(f"[{fact['key']}] {fact['summary']} (confidence: {fact['confidence']})")
339
490
  ```
340
491
 
492
+ ### Graph Traversal
493
+
494
+ ```python
495
+ from clients.python.iranti import IrantiClient
496
+
497
+ client = IrantiClient(base_url="http://localhost:3001", api_key="your_api_key_here")
498
+
499
+ # Agent 1 writes facts and links them into a graph.
500
+ client.write("researcher/jane_smith", "affiliation", {"lab": "CSAIL"}, "Jane Smith is affiliated with CSAIL", 90, "OpenAlex", "research_agent")
501
+ client.write("project/quantum_bridge", "status", {"phase": "active"}, "Quantum Bridge is active", 88, "project_brief", "research_agent")
502
+
503
+ client.relate("researcher/jane_smith", "MEMBER_OF", "lab/csail", created_by="research_agent")
504
+ client.relate("lab/csail", "LEADS", "project/quantum_bridge", created_by="research_agent")
505
+
506
+ # Agent 2 starts cold and traverses outward from Jane Smith.
507
+ one_hop = client.related("researcher/jane_smith")
508
+ labs = [f"{r['toType']}/{r['toId']}" for r in one_hop if r["relationshipType"] == "MEMBER_OF"]
509
+
510
+ projects = []
511
+ for lab in labs:
512
+ for rel in client.related(lab):
513
+ if rel["relationshipType"] == "LEADS":
514
+ project = f"{rel['toType']}/{rel['toId']}"
515
+ status = client.query(project, "status")
516
+ projects.append((project, status.value["phase"]))
517
+
518
+ print(projects)
519
+ # Agent 2 learned which project Jane Smith is connected to without being told the project directly.
520
+ ```
521
+
522
+ ### Relationship Types
523
+
524
+ Relationship types are caller-defined strings. Common conventions:
525
+
526
+ | Relationship Type | Meaning |
527
+ |---|---|
528
+ | `MEMBER_OF` | Entity belongs to a team, lab, org, or group |
529
+ | `PART_OF` | Entity is a component or sub-unit of another entity |
530
+ | `AUTHORED` | Person or agent created a document, paper, or artifact |
531
+ | `LEADS` | Person, team, or org leads a project or effort |
532
+ | `DEPENDS_ON` | Project, service, or task depends on another entity |
533
+ | `REPORTS_TO` | Directed reporting relationship between people or agents |
534
+
535
+ Use uppercase snake case for consistency. Iranti does not enforce a fixed ontology here; the calling application owns the relationship vocabulary.
536
+
341
537
  ### Hybrid Search
342
538
 
343
539
  ```python
@@ -490,7 +686,7 @@ Iranti has four internal components:
490
686
 
491
687
  | Component | Role |
492
688
  |---|---|
493
- | **Library** | PostgreSQL knowledge base. Active truth in `knowledge_base` with full provenance in `archive`; archived rows are retained and marked `[ARCHIVED]` in active storage. |
689
+ | **Library** | PostgreSQL knowledge base. Current truth lives in `knowledge_base`; closed and contested intervals live in `archive`. |
494
690
  | **Librarian** | Manages all writes. Detects conflicts, reasons about resolution, escalates when uncertain. |
495
691
  | **Attendant** | Per-agent working memory manager. Implements `attend()`, `observe()`, and `handshake()` APIs. |
496
692
  | **Archivist** | Periodic cleanup. Archives expired and low-confidence entries. Processes human-resolved conflicts. |
@@ -500,7 +696,7 @@ Iranti has four internal components:
500
696
  Express server on port 3001 with endpoints:
501
697
 
502
698
  - `POST /kb/write` - Write atomic fact
503
- - `POST /kb/ingest` - Ingest raw text, auto-chunk into facts
699
+ - `POST /kb/ingest` - Ingest raw text for one entity, auto-chunk into facts with per-fact confidence and per-fact write outcomes
504
700
  - `GET /kb/query/:entityType/:entityId/:key` - Query specific fact
505
701
  - `GET /kb/query/:entityType/:entityId` - Query all facts for entity
506
702
  - `GET /kb/search` - Hybrid search across facts
@@ -520,8 +716,8 @@ All endpoints require `X-Iranti-Key` header for authentication.
520
716
  Six PostgreSQL tables:
521
717
 
522
718
  ```
523
- knowledge_base - active truth (archived rows retained with confidence=0)
524
- archive - full provenance history, never deleted
719
+ knowledge_base - current truth (one live row per entity/key)
720
+ archive - temporal and provenance history for superseded, contradicted, escalated, and expired rows
525
721
  entity_relationships - directional graph: MEMBER_OF, PART_OF, AUTHORED, etc.
526
722
  entities - canonical entity identity registry
527
723
  entity_aliases - normalized aliases mapped to canonical entities
@@ -530,7 +726,7 @@ write_receipts - idempotency receipts for requestId replay safety
530
726
 
531
727
  New entity types, relationship types, and fact keys do not require migrations; they are caller-defined strings.
532
728
 
533
- **Archive semantics**: When an entry is archived, it remains in knowledge_base with confidence set to 0 and summary marked as `[ARCHIVED]`. A full copy is written to the archive table for traceability. Nothing is ever truly deleted.
729
+ **Archive semantics**: When a current fact is superseded or contested, the current row is removed from `knowledge_base` and a closed historical interval is written to `archive`. Temporal queries use `validFrom` / `validUntil` plus archive metadata to answer point-in-time reads.
534
730
 
535
731
  ---
536
732