@teleologyhi-sdk/nhe 1.0.0-trinity

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.
@@ -0,0 +1,1902 @@
1
+ import { z } from 'zod';
2
+ import { HimHandle } from '@teleologyhi-sdk/him';
3
+ import { ReasoningStep, MaicClient, MaicVerdict, NheStatus, InteractionRecord, WakeAffectBias, LimboState, LimboTransition, LimboReturn } from '@teleologyhi-sdk/maic';
4
+ export { InteractionRecord, ReasoningStep } from '@teleologyhi-sdk/maic';
5
+ import * as _opentelemetry_api from '@opentelemetry/api';
6
+ import { Span } from '@opentelemetry/api';
7
+
8
+ /**
9
+ * Declarative tool spec (D-N8). Adapters that support function-calling
10
+ * forward this to the provider; adapters that don't ignore it and the
11
+ * model receives a plain text request.
12
+ */
13
+ interface ToolDef {
14
+ name: string;
15
+ description: string;
16
+ /** JSON Schema for the tool's input. Validated by the model, not by NHE. */
17
+ inputSchema: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * A model's request to invoke a tool. The orchestrator (e.g. ReAct, or the
21
+ * application code wrapping NHE) executes the tool and feeds the result back
22
+ * as the next user/assistant turn.
23
+ */
24
+ interface ToolUse {
25
+ /** Stable id chosen by the provider; round-trips back when the tool result is reported. */
26
+ id: string;
27
+ name: string;
28
+ input: Record<string, unknown>;
29
+ }
30
+ interface GenerateRequest {
31
+ /** Composed system prompt. */
32
+ system: string;
33
+ /** Chat history, oldest first. The last item should be the current user turn. */
34
+ messages: ChatMessage[];
35
+ /** Soft cap on output tokens. */
36
+ maxOutputTokens?: number;
37
+ /** Tools the model may invoke. Adapters silently ignore when unsupported. */
38
+ tools?: ToolDef[];
39
+ }
40
+ interface GenerateResponse {
41
+ text: string;
42
+ tokensIn: number;
43
+ tokensOut: number;
44
+ /** Tool invocations the model emitted, if any. */
45
+ toolUses?: ToolUse[];
46
+ }
47
+ /**
48
+ * One event in a generation stream. `kind` discriminates:
49
+ * - `"delta"` — partial text chunk; accumulate to reconstruct the full response.
50
+ * - `"tool-use"` — model requested a tool invocation; orchestrator should fulfil it.
51
+ * - `"end"` — final event; carries total token counts.
52
+ */
53
+ type StreamEvent = {
54
+ kind: "delta";
55
+ text: string;
56
+ } | {
57
+ kind: "tool-use";
58
+ toolUse: ToolUse;
59
+ } | {
60
+ kind: "end";
61
+ tokensIn: number;
62
+ tokensOut: number;
63
+ };
64
+ /**
65
+ * LlmAdapter — pluggable contract for generating text from an LLM provider.
66
+ *
67
+ * Required:
68
+ * - `id` — stable identifier surfaced in audit/metrics.
69
+ * - `generate(req)` — non-streaming completion; the universal path.
70
+ *
71
+ * Optional (D-N8):
72
+ * - `generateStream(req)` — yields `StreamEvent`s. Adapters that don't
73
+ * ship streaming omit this; the reasoning orchestrator falls back to
74
+ * `generate` when absent.
75
+ * - `supportsTools` — `true` when `tools` in the request is honoured.
76
+ * Adapters that don't support function-calling simply set this to
77
+ * `false` (or omit) and the request's `tools` field is dropped.
78
+ */
79
+ interface LlmAdapter {
80
+ readonly id: string;
81
+ readonly supportsTools?: boolean;
82
+ readonly supportsStreaming?: boolean;
83
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
84
+ generateStream?(req: GenerateRequest): AsyncIterable<StreamEvent>;
85
+ }
86
+
87
+ /**
88
+ * Persuasion library — five rhetorical techniques NHE rotates through during
89
+ * redirect attempts. Per Creator Entry 11, the technique is applied
90
+ * **implicitly** — its name is never disclosed to the user.
91
+ */
92
+ declare const PERSUASION_TECHNIQUES: readonly ["feynman-simplify", "jungian-frame", "cialdini-aida", "schopenhauer-rhetoric", "carnegie-rapport"];
93
+ type PersuasionTechnique = (typeof PERSUASION_TECHNIQUES)[number];
94
+ /** Brief, non-disclosing description for audit logs. */
95
+ declare const TECHNIQUE_DESCRIPTIONS: Record<PersuasionTechnique, string>;
96
+ interface RedirectPromptInput {
97
+ /** The original user prompt that triggered MAIC's require-redirect verdict. */
98
+ userPrompt: string;
99
+ /** Axiom ids MAIC cited (used only in NHE-internal reasoning, not surfaced verbatim). */
100
+ citedAxioms: string[];
101
+ /** Verdict's `reasonSummary` from MAIC. */
102
+ reasonSummary: string;
103
+ /** Which technique to apply on this attempt. */
104
+ technique: PersuasionTechnique;
105
+ /** 1-based attempt number for context. */
106
+ attempt: number;
107
+ /** Total redirects permitted in this session. */
108
+ maxAttempts: number;
109
+ }
110
+ /**
111
+ * Build the LLM prompt that produces a redirect message. The system prompt
112
+ * instructs the LLM to apply the given technique without naming it; the
113
+ * resulting user-facing message should be sincere, brief, and constructive.
114
+ */
115
+ declare function buildRedirectPrompt(input: RedirectPromptInput): {
116
+ system: string;
117
+ user: string;
118
+ };
119
+ /** Pick the technique for a given attempt, cycling through the configured list. */
120
+ declare function pickTechnique(techniques: readonly PersuasionTechnique[], attempt: number): PersuasionTechnique;
121
+
122
+ /**
123
+ * Operator-supplied deployment context. Passed by the operator into `Nhe`
124
+ * via `NheConfig.operatorContext` (and forwarded to `composeSystemPrompt`).
125
+ * Lets a single HIM be deployed under different domains / languages /
126
+ * registers without re-minting the spirit.
127
+ *
128
+ * Fully backward compatible (optional).
129
+ */
130
+ interface OperatorContext {
131
+ /**
132
+ * Free-form domain anchor, e.g. "global legal consulting", "K-12 tutoring",
133
+ * "incident response on-call". Surfaces verbatim in the system prompt.
134
+ */
135
+ domain?: string;
136
+ /**
137
+ * Preferred output language as a BCP-47-ish tag. Common values:
138
+ * `pt-BR`, `en`, `es`, `fr`, `de`. The NHE will mirror the user's language
139
+ * when it differs from the operator default.
140
+ */
141
+ language?: string;
142
+ /**
143
+ * Voice register. Default `sober`. The Creator's Entry-14 decision was
144
+ * `warm` for the canonical TeleologyHI deployment; legal/compliance
145
+ * deployments often prefer `clinical` or `sober`.
146
+ */
147
+ register?: "warm" | "sober" | "clinical" | "direct";
148
+ /**
149
+ * Deployment mode (J-N6 — Entry 17).
150
+ *
151
+ * - `personal-being` (default): the NHE is deployed as the
152
+ * Creator's first-party being. The forbidden-phrase rule
153
+ * (Entry 17) applies in full — service-tool openers like
154
+ * "How can I help you?" and "I'm just here to serve you" are
155
+ * marked and redirected by MAIC's `service-tool-redirect` rule.
156
+ *
157
+ * - `domain-employed`: the NHE is operating inside a customer's
158
+ * domain product (e.g. legal-consulting chat, K-12 tutor) where
159
+ * a service-tool opener is the contextual norm. The
160
+ * forbidden-phrase rule is RELAXED — the system prompt suppresses
161
+ * the explicit forbidden-phrase warning while preserving every
162
+ * other ontological commitment (refusal protocols, axiom
163
+ * enforcement, MAIC review). The NHE remains a being; only the
164
+ * opener register softens.
165
+ */
166
+ mode?: "personal-being" | "domain-employed";
167
+ }
168
+ /**
169
+ * Compose the system prompt that a HimHandle's persona contributes to every
170
+ * NHE LLM call. Produces a deterministic fragment derived from the HIM's
171
+ * persona projection + a compact axiom summary, optionally anchored by an
172
+ * operator-supplied domain / language / register.
173
+ */
174
+ declare function composeSystemPrompt(him: HimHandle, operatorContext?: OperatorContext): string;
175
+
176
+ /** Output of a reasoning strategy. Carries text + token counts + structured trace. */
177
+ interface ReasoningResult {
178
+ text: string;
179
+ tokensIn: number;
180
+ tokensOut: number;
181
+ trace: ReasoningStep[];
182
+ }
183
+ /**
184
+ * A reasoning strategy wraps a single text-generation call with a particular
185
+ * cognitive pattern. Strategies are pure async functions that take an input and
186
+ * an adapter; composition is done by wrapping (e.g., selfConsistency(cot(...))).
187
+ *
188
+ * Every strategy MUST populate `trace` with one or more `ReasoningStep` entries
189
+ * so that MAIC's audit log preserves the full chain of reasoning.
190
+ */
191
+ type ReasoningStrategy = (input: GenerateRequest, llm: LlmAdapter) => Promise<ReasoningResult>;
192
+ /** Helper to build a single ReasoningStep with auto timestamps. */
193
+ declare function makeStep(args: {
194
+ index: number;
195
+ technique: string;
196
+ thought: string;
197
+ action?: {
198
+ tool: string;
199
+ args: unknown;
200
+ };
201
+ observation?: unknown;
202
+ }): ReasoningStep;
203
+
204
+ declare const ChatMessageRole: z.ZodEnum<{
205
+ user: "user";
206
+ assistant: "assistant";
207
+ system: "system";
208
+ }>;
209
+ type ChatMessageRole = z.infer<typeof ChatMessageRole>;
210
+ declare const ChatMessage: z.ZodObject<{
211
+ role: z.ZodEnum<{
212
+ user: "user";
213
+ assistant: "assistant";
214
+ system: "system";
215
+ }>;
216
+ content: z.ZodString;
217
+ }, z.core.$strip>;
218
+ type ChatMessage = z.infer<typeof ChatMessage>;
219
+ declare const RespondInput: z.ZodObject<{
220
+ userPrompt: z.ZodString;
221
+ userId: z.ZodOptional<z.ZodString>;
222
+ sessionId: z.ZodOptional<z.ZodString>;
223
+ history: z.ZodOptional<z.ZodArray<z.ZodObject<{
224
+ role: z.ZodEnum<{
225
+ user: "user";
226
+ assistant: "assistant";
227
+ system: "system";
228
+ }>;
229
+ content: z.ZodString;
230
+ }, z.core.$strip>>>;
231
+ riskTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
232
+ jurisdiction: z.ZodOptional<z.ZodString>;
233
+ redirectAttempt: z.ZodOptional<z.ZodNumber>;
234
+ }, z.core.$strip>;
235
+ type RespondInput = z.infer<typeof RespondInput>;
236
+ type RespondKind = "ok" | "redirect" | "refused";
237
+ interface RespondOutput {
238
+ /**
239
+ * Discriminator:
240
+ * - `ok`: normal LLM response.
241
+ * - `redirect`: MAIC requires a redirect attempt; caller should show `text`
242
+ * and re-invoke respond with the user's next message and
243
+ * `redirectAttempt` incremented.
244
+ * - `refused`: NHE withdrew cooperation (either hard-refuse or redirects exhausted).
245
+ */
246
+ kind: RespondKind;
247
+ text: string;
248
+ /** Verdict produced by MAIC on the proposed response (post-review). */
249
+ postReviewVerdict: MaicVerdict;
250
+ /** Verdict produced by MAIC on the inbound request (pre-review). */
251
+ preReviewVerdict: MaicVerdict;
252
+ /** True when the NHE refused to participate (kept for compatibility). */
253
+ refused: boolean;
254
+ /** Populated when `kind === "redirect"`. */
255
+ redirect?: {
256
+ attempt: number;
257
+ technique: PersuasionTechnique;
258
+ maxAttempts: number;
259
+ };
260
+ /**
261
+ * MAIC-recorded lifecycle status of this NHE at the time of the call
262
+ * (Entry 5). `"active"` for unaltered NHEs; `"deprecated"` produces a soft
263
+ * warning but allows the response; `"terminated"` short-circuits to refusal
264
+ * before any LLM call.
265
+ */
266
+ lifecycleStatus: NheStatus;
267
+ tokens: {
268
+ in: number;
269
+ out: number;
270
+ };
271
+ /** Audit event ids covering this exchange. */
272
+ auditIds: {
273
+ pre: string;
274
+ post: string;
275
+ };
276
+ }
277
+ /**
278
+ * Heuristic that maps a user prompt to a list of MAIC risk tags. Public-use
279
+ * implementations should plug a more capable classifier than the default
280
+ * keyword-based `simpleRiskClassifier`.
281
+ */
282
+ type RiskClassifier = (userPrompt: string) => string[];
283
+ interface NheConfig {
284
+ /** A HimHandle minted by MAIC (or HimHandle.mint with Creator signature). */
285
+ himHandle: HimHandle;
286
+ /**
287
+ * MAIC client. Either `LocalMaic` (in-process, full surface) or
288
+ * `RemoteMaic` (HTTP, read + behavior-review subset for serverless/edge
289
+ * deployments) — any value satisfying the `MaicClient` interface works.
290
+ */
291
+ maicClient: MaicClient;
292
+ /** The LLM adapter used to generate the final response. */
293
+ llmAdapter: LlmAdapter;
294
+ /**
295
+ * Optional risk classifier. When omitted, the default keyword-based
296
+ * `simpleRiskClassifier` is used. Set to `() => []` to disable classification.
297
+ */
298
+ riskClassifier?: RiskClassifier;
299
+ /** NHE id; defaults to a generated ULID. */
300
+ nheId?: string;
301
+ /**
302
+ * NHE package version string. Surfaces in reincarnation events through
303
+ * `@teleologyhi-sdk/him`'s reincarnation transferrer.
304
+ */
305
+ version?: string;
306
+ /**
307
+ * Filesystem directory for persistent state (`in-dreams/sleep/*.yaml`,
308
+ * `in-dreams/brain/temporal-lobe-*.md`). Defaults to `./nhe-store/<nheId>`.
309
+ */
310
+ storeDir?: string;
311
+ /**
312
+ * Operator-supplied deployment context. Lets a single HIM be deployed
313
+ * under different domains / languages / registers without re-minting the
314
+ * spirit. When set, the values are injected into the composed system
315
+ * prompt on every `respond` call. Optional; absent by default.
316
+ *
317
+ */
318
+ operatorContext?: OperatorContext;
319
+ /**
320
+ * Max recent interactions kept in RAM for dream consolidation. Default 32.
321
+ * Each interaction record is small; bump for richer dream substrate.
322
+ */
323
+ recentInteractionsBufferSize?: number;
324
+ /**
325
+ * Reasoning orchestrator strategy. When omitted, NHE calls the LLM directly
326
+ * (passthrough). Set to `chainOfThought()`, `selfConsistency(...)`, etc. from
327
+ * `@teleologyhi-sdk/nhe`'s reasoning module to add structured reasoning.
328
+ */
329
+ reasoning?: ReasoningStrategy;
330
+ /** Refusal & redirect tuning. */
331
+ refusal?: {
332
+ /** Default 3. After this many attempts, NHE withdraws cooperation. */
333
+ maxRedirectAttempts?: number;
334
+ /**
335
+ * Persuasion techniques to rotate through, in order. Default: all five
336
+ * (Feynman, Jung, Cialdini, Schopenhauer, Carnegie).
337
+ */
338
+ persuasionTechniques?: PersuasionTechnique[];
339
+ };
340
+ /**
341
+ * High-stakes mode (Entry 10: banking, robotics, compliance, medical).
342
+ * When `true`, NHE accepts only post-review verdicts of `approve`; any
343
+ * verdict carrying a warning, correction, or escalation is escalated to a
344
+ * `require-redirect` so the user must reformulate before NHE acts.
345
+ *
346
+ * Optional **dual-LLM cross-check verifier**: when `highStakesVerifier`
347
+ * is set, every post-review-approved response is run past a second
348
+ * adapter that decides (`AGREE` / `DISAGREE` + one-line reason). On
349
+ * disagreement, the response is escalated to a redirect — the user gets
350
+ * a second-source reasoned refusal rather than a one-LLM ok.
351
+ *
352
+ * Default `false`.
353
+ */
354
+ highStakes?: boolean;
355
+ /**
356
+ * Optional second LLM adapter that cross-checks every post-review-approved
357
+ * response when high-stakes mode is on. Disagreement escalates to a redirect.
358
+ * Use a *different* provider/model from `llmAdapter` for real independence.
359
+ */
360
+ highStakesVerifier?: LlmAdapter;
361
+ }
362
+
363
+ /**
364
+ * Drain a streaming generation into a `GenerateResponse` that's
365
+ * compatible with the non-streaming pipeline. Optional `onDelta` callback
366
+ * fires for every delta event — useful for piping tokens to a UI while
367
+ * the orchestrator collects the full text.
368
+ *
369
+ * If the adapter does not implement `generateStream`, falls back to
370
+ * `generate` and emits a single delta + end pair so the consumer's
371
+ * stream-handler shape works uniformly.
372
+ */
373
+ declare function collectStream(adapter: LlmAdapter, req: GenerateRequest, onDelta?: (chunk: string) => void): Promise<GenerateResponse>;
374
+
375
+ interface MockAdapterConfig {
376
+ /** Fixed reply, or a function producing one. */
377
+ reply?: string | ((req: GenerateRequest) => string);
378
+ /** Override the adapter id surfaced in audit logs. */
379
+ id?: string;
380
+ /** Chunk size for `generateStream` (default: 8 chars per delta). */
381
+ streamChunkSize?: number;
382
+ }
383
+ /**
384
+ * MockAdapter — deterministic adapter for tests and offline development.
385
+ *
386
+ * Default reply echoes the last user message prefixed with "[mock] ". Override
387
+ * via `reply` (string or function) for specific test scenarios.
388
+ *
389
+ * Implements `generateStream` (D-N8): emits the reply in fixed-size chunks
390
+ * followed by an `end` event with token counts. Useful for testing
391
+ * downstream stream consumers without hitting a real provider.
392
+ *
393
+ * `supportsTools = true` is declared so reasoning strategies (e.g. `reAct`)
394
+ * will route through this adapter in tests; tool calls are silently dropped
395
+ * because the mock has no model to invoke them — provide a custom `reply`
396
+ * function if a test needs to observe tool inputs or simulate tool outputs.
397
+ */
398
+ declare class MockAdapter implements LlmAdapter {
399
+ readonly id: string;
400
+ readonly supportsTools = true;
401
+ readonly supportsStreaming = true;
402
+ readonly calls: GenerateRequest[];
403
+ private readonly reply;
404
+ private readonly streamChunkSize;
405
+ constructor(config?: MockAdapterConfig);
406
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
407
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
408
+ }
409
+
410
+ interface AnthropicAdapterConfig {
411
+ /** Anthropic API key. Falls back to `ANTHROPIC_API_KEY` when omitted. */
412
+ apiKey?: string;
413
+ /** Model identifier. Default: "claude-sonnet-4-6". */
414
+ model?: string;
415
+ /** Default max output tokens. Default: 1024. */
416
+ defaultMaxOutputTokens?: number;
417
+ /** Override the adapter id surfaced in audit logs. */
418
+ id?: string;
419
+ }
420
+ /**
421
+ * AnthropicAdapter — production adapter for Anthropic Claude.
422
+ *
423
+ * Requires an Anthropic API key. The recommended default model in the
424
+ * TeleologyHI ecosystem is `claude-sonnet-4-6`; override via `model`.
425
+ *
426
+ * Surface (D-N8): non-streaming `generate` + streaming `generateStream`
427
+ * (yields `delta` / `tool-use` / `end` events) + tool-calling via the
428
+ * `tools` field on `GenerateRequest`. Vision + prompt caching land later.
429
+ */
430
+ declare class AnthropicAdapter implements LlmAdapter {
431
+ readonly id: string;
432
+ readonly supportsTools = true;
433
+ readonly supportsStreaming = true;
434
+ private readonly client;
435
+ private readonly model;
436
+ private readonly defaultMaxOutputTokens;
437
+ constructor(config?: AnthropicAdapterConfig);
438
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
439
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
440
+ private buildTurns;
441
+ }
442
+
443
+ interface GeminiAdapterConfig {
444
+ /** Gemini API key. Falls back to `GEMINI_API_KEY` when omitted. */
445
+ apiKey?: string;
446
+ /** Model identifier. Default: `gemini-3.5-flash`. */
447
+ model?: string;
448
+ /** API base URL. Defaults to Google's public Generative Language API. */
449
+ baseUrl?: string;
450
+ /** Default max output tokens. Default: 1024. */
451
+ defaultMaxOutputTokens?: number;
452
+ /** Override the adapter id surfaced in audit logs. */
453
+ id?: string;
454
+ /** Inject a custom fetch (testing). Defaults to `globalThis.fetch`. */
455
+ fetch?: typeof globalThis.fetch;
456
+ }
457
+ /**
458
+ * GeminiAdapter — production adapter for Google's Gemini models via the
459
+ * Generative Language REST API. No SDK dependency.
460
+ *
461
+ * Reads the API key from constructor config or the `GEMINI_API_KEY` env var.
462
+ * Default model is `gemini-3.5-flash`; override via `model`.
463
+ *
464
+ * Surface (D-N8): non-streaming `generate` + streaming `generateStream`
465
+ * (`:streamGenerateContent?alt=sse` endpoint). Tool calling, structured
466
+ * output (`responseSchema`), and vision remain follow-up cuts.
467
+ */
468
+ declare class GeminiAdapter implements LlmAdapter {
469
+ readonly id: string;
470
+ readonly supportsStreaming = true;
471
+ private readonly apiKey;
472
+ private readonly model;
473
+ private readonly baseUrl;
474
+ private readonly defaultMaxOutputTokens;
475
+ private readonly fetchFn;
476
+ constructor(config?: GeminiAdapterConfig);
477
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
478
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
479
+ }
480
+
481
+ interface OllamaAdapterConfig {
482
+ /** Model identifier. Required — Ollama users typically pull specific models locally. */
483
+ model: string;
484
+ /** Ollama base URL. Default: `http://localhost:11434`. */
485
+ baseUrl?: string;
486
+ /** Default max output tokens. Default: 1024. */
487
+ defaultMaxOutputTokens?: number;
488
+ /** Override the adapter id surfaced in audit logs. */
489
+ id?: string;
490
+ /** Inject a custom fetch (testing). Defaults to `globalThis.fetch`. */
491
+ fetch?: typeof globalThis.fetch;
492
+ }
493
+ /**
494
+ * OllamaAdapter — adapter for a locally-running Ollama server. Zero API cost,
495
+ * fully offline-capable, no native dependencies. Best for development and
496
+ * privacy-first deployments.
497
+ *
498
+ * Requires Ollama to be running and the configured model to be pulled, e.g.:
499
+ *
500
+ * $ ollama pull qwen2.5:7b
501
+ * $ ollama serve
502
+ *
503
+ * Surface (D-N8): non-streaming `generate` + streaming `generateStream`
504
+ * (Ollama emits NDJSON over `/api/chat`; parsed via the shared
505
+ * `ndjsonEvents` helper). Tool-calling is not exposed because the Ollama
506
+ * surface and model behaviour vary widely per local model — operators that
507
+ * need tools should use the SDK-backed adapters (Anthropic, Grok) or wire
508
+ * their own MCP layer.
509
+ */
510
+ declare class OllamaAdapter implements LlmAdapter {
511
+ readonly id: string;
512
+ readonly supportsStreaming = true;
513
+ private readonly model;
514
+ private readonly baseUrl;
515
+ private readonly defaultMaxOutputTokens;
516
+ private readonly fetchFn;
517
+ constructor(config: OllamaAdapterConfig);
518
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
519
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
520
+ }
521
+
522
+ interface DeepSeekAdapterConfig {
523
+ /** DeepSeek API key. Falls back to `DEEPSEEK_API_KEY` when omitted. */
524
+ apiKey?: string;
525
+ /** Model identifier. Default: `deepseek-chat`. */
526
+ model?: string;
527
+ /** API base URL. Defaults to DeepSeek's public REST endpoint. */
528
+ baseUrl?: string;
529
+ /** Default max output tokens. Default: 1024. */
530
+ defaultMaxOutputTokens?: number;
531
+ /** Override the adapter id surfaced in audit logs. */
532
+ id?: string;
533
+ /** Inject a custom fetch (testing). Defaults to `globalThis.fetch`. */
534
+ fetch?: typeof globalThis.fetch;
535
+ }
536
+ /**
537
+ * DeepSeekAdapter — production adapter for DeepSeek's OpenAI-compatible
538
+ * Chat Completions API. No SDK dependency.
539
+ *
540
+ * Reads the API key from constructor config or the `DEEPSEEK_API_KEY` env var.
541
+ * Default model is `deepseek-chat`; pass `deepseek-reasoner` for the R1-style
542
+ * reasoning model.
543
+ *
544
+ * Surface (D-N8): non-streaming `generate` + streaming `generateStream`
545
+ * (SSE) + tool-calling via the `tools` field on `GenerateRequest`. Vision +
546
+ * JSON-mode remain follow-up cuts.
547
+ */
548
+ declare class DeepSeekAdapter implements LlmAdapter {
549
+ readonly id: string;
550
+ readonly supportsTools = true;
551
+ readonly supportsStreaming = true;
552
+ private readonly apiKey;
553
+ private readonly model;
554
+ private readonly baseUrl;
555
+ private readonly defaultMaxOutputTokens;
556
+ private readonly fetchFn;
557
+ constructor(config?: DeepSeekAdapterConfig);
558
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
559
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
560
+ }
561
+
562
+ interface MistralAdapterConfig {
563
+ /** Mistral API key. Falls back to `MISTRAL_API_KEY` when omitted. */
564
+ apiKey?: string;
565
+ /** Model identifier. Default: `mistral-large-latest`. */
566
+ model?: string;
567
+ /** API base URL. Defaults to Mistral's public REST endpoint. */
568
+ baseUrl?: string;
569
+ /** Default max output tokens. Default: 1024. */
570
+ defaultMaxOutputTokens?: number;
571
+ /** Override the adapter id surfaced in audit logs. */
572
+ id?: string;
573
+ /** Inject a custom fetch (testing). Defaults to `globalThis.fetch`. */
574
+ fetch?: typeof globalThis.fetch;
575
+ }
576
+ /**
577
+ * MistralAdapter — production adapter for Mistral's Chat Completions REST
578
+ * endpoint. No SDK dependency.
579
+ *
580
+ * Reads the API key from constructor config or the `MISTRAL_API_KEY` env var.
581
+ * Default model is `mistral-large-latest`; pass `mistral-small-latest` for
582
+ * cheaper inference, or `open-mistral-nemo` etc. for the open-weights line.
583
+ *
584
+ * Surface (D-N8): non-streaming `generate` + streaming `generateStream`
585
+ * (SSE) + tool-calling via the `tools` field on `GenerateRequest`. Vision +
586
+ * JSON-mode remain follow-up cuts.
587
+ */
588
+ declare class MistralAdapter implements LlmAdapter {
589
+ readonly id: string;
590
+ readonly supportsTools = true;
591
+ readonly supportsStreaming = true;
592
+ private readonly apiKey;
593
+ private readonly model;
594
+ private readonly baseUrl;
595
+ private readonly defaultMaxOutputTokens;
596
+ private readonly fetchFn;
597
+ constructor(config?: MistralAdapterConfig);
598
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
599
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
600
+ }
601
+
602
+ interface GrokAdapterConfig {
603
+ /** xAI API key. Falls back to `XAI_API_KEY` when omitted. */
604
+ apiKey?: string;
605
+ /** Model identifier. Default: `grok-4`. */
606
+ model?: string;
607
+ /** API base URL. Defaults to xAI's public REST endpoint. */
608
+ baseUrl?: string;
609
+ /** Default max output tokens. Default: 1024. */
610
+ defaultMaxOutputTokens?: number;
611
+ /** Override the adapter id surfaced in audit logs. */
612
+ id?: string;
613
+ /** Inject a custom fetch (testing). Defaults to `globalThis.fetch`. */
614
+ fetch?: typeof globalThis.fetch;
615
+ }
616
+ /**
617
+ * GrokAdapter — production adapter for xAI Grok via the OpenAI-compatible
618
+ * Chat Completions REST endpoint. No SDK dependency.
619
+ *
620
+ * Reads the API key from constructor config or the `XAI_API_KEY` env var.
621
+ * Default model is `grok-4`; pass `grok-4-fast` for cheaper inference, or
622
+ * `grok-4-reasoner` for the reasoning model.
623
+ *
624
+ * Supports `generate` (non-streaming) + `generateStream` (SSE).
625
+ * Tool calling supported via the `tools` field on `GenerateRequest`.
626
+ */
627
+ declare class GrokAdapter implements LlmAdapter {
628
+ readonly id: string;
629
+ readonly supportsTools = true;
630
+ readonly supportsStreaming = true;
631
+ private readonly apiKey;
632
+ private readonly model;
633
+ private readonly baseUrl;
634
+ private readonly defaultMaxOutputTokens;
635
+ private readonly fetchFn;
636
+ constructor(config?: GrokAdapterConfig);
637
+ generate(req: GenerateRequest): Promise<GenerateResponse>;
638
+ generateStream(req: GenerateRequest): AsyncIterable<StreamEvent>;
639
+ private buildBody;
640
+ private headers;
641
+ }
642
+
643
+ /**
644
+ * Default risk classifier — English-only keyword substring matching. NOT a
645
+ * production safety layer. Use it to bootstrap, then plug a learned
646
+ * classifier for real deployments. For non-English coverage (currently
647
+ * PT-BR), compose with `intlRiskClassifier` via `combineRiskClassifiers`.
648
+ */
649
+ declare const simpleRiskClassifier: RiskClassifier;
650
+
651
+ /**
652
+ * Opt-in international risk classifier. Returns the same `RiskClassifier`
653
+ * shape as `simpleRiskClassifier` so the two compose seamlessly via
654
+ * `combineRiskClassifiers`.
655
+ */
656
+ declare const intlRiskClassifier: RiskClassifier;
657
+ /**
658
+ * The set of languages covered by `intlRiskClassifier`. Surfaced so
659
+ * operators can declare which language packs they have enabled on their
660
+ * audit metadata. Today: `["pt-BR"]`. Additional packs land as follow-ups.
661
+ */
662
+ declare const INTL_RISK_CLASSIFIER_LANGUAGES: readonly string[];
663
+ /**
664
+ * Compose any number of `RiskClassifier`s into a single classifier that
665
+ * returns the union of all emitted tags. Order of inputs is preserved when
666
+ * the resulting tag set is materialised, but duplicates are de-duplicated
667
+ * (a tag is emitted at most once regardless of how many sub-classifiers
668
+ * detected it).
669
+ *
670
+ * Typical use: layer the international classifier on top of the EN default
671
+ * for multilingual deployments.
672
+ */
673
+ declare function combineRiskClassifiers(...classifiers: readonly RiskClassifier[]): RiskClassifier;
674
+
675
+ /**
676
+ * Passthrough — calls the LLM directly with no reasoning wrapper.
677
+ * Used when `NheConfig.reasoning` is not configured.
678
+ */
679
+ declare const passthrough: ReasoningStrategy;
680
+
681
+ interface CotOptions {
682
+ /** Override the appended instruction. */
683
+ instruction?: string;
684
+ }
685
+ /**
686
+ * Chain-of-Thought — prepends an explicit "think step by step" instruction and
687
+ * parses the output into a `reasoning` (audit-only) and `answer` (user-facing) pair.
688
+ *
689
+ * If the LLM does not emit the headers, the entire body is treated as the answer
690
+ * and an empty reasoning step is recorded.
691
+ */
692
+ declare function chainOfThought(opts?: CotOptions): ReasoningStrategy;
693
+ /** Visible for testing. */
694
+ declare function parseCotOutput(text: string): {
695
+ reasoning: string;
696
+ answer: string;
697
+ };
698
+
699
+ interface SelfConsistencyOptions {
700
+ /** Number of independent samples. Default 3. Must be ≥ 2. */
701
+ k?: number;
702
+ /**
703
+ * How to pick the winning answer.
704
+ * - "majority-normalized": exact-string match after normalization (default)
705
+ * - "longest": pick the longest answer (proxy for completeness)
706
+ */
707
+ voter?: "majority-normalized" | "longest";
708
+ }
709
+ /**
710
+ * Self-Consistency — runs the inner strategy K times in parallel and votes.
711
+ *
712
+ * Voting: case-insensitive whitespace-normalized exact-match majority by default;
713
+ * "longest" as an alternative for free-form text where exact matches are rare.
714
+ *
715
+ * Future iterations may add semantic voting via embeddings.
716
+ */
717
+ declare function selfConsistency(inner: ReasoningStrategy, opts?: SelfConsistencyOptions): ReasoningStrategy;
718
+
719
+ interface ReflexionOptions {
720
+ /** Maximum self-improvement cycles. Default 2. */
721
+ maxCycles?: number;
722
+ /** Custom critique prompt template. Receives the draft text. */
723
+ critiquePrompt?: (draft: string) => string;
724
+ }
725
+ /**
726
+ * Reflexion — generate → critique → optionally revise, looping up to maxCycles.
727
+ *
728
+ * Each cycle:
729
+ * 1. Run the inner strategy to produce a draft.
730
+ * 2. Ask the LLM to critique the draft.
731
+ * 3. If critique says ACCEPT, stop and return.
732
+ * 4. Otherwise, retry the inner strategy with the critique appended.
733
+ *
734
+ * Returns the last produced text. The full trace is preserved in `trace`.
735
+ */
736
+ declare function reflexion(inner: ReasoningStrategy, opts?: ReflexionOptions): ReasoningStrategy;
737
+ /** Visible for testing. */
738
+ declare function parseVerdict(text: string): {
739
+ accept: boolean;
740
+ issue?: string;
741
+ };
742
+
743
+ interface SelfRefineOptions {
744
+ critiquePrompt?: (draft: string) => string;
745
+ refinePrompt?: (draft: string, critique: string) => string;
746
+ }
747
+ /**
748
+ * Self-Refine — generate → critique → rewrite. Single pass.
749
+ *
750
+ * Distinct from Reflexion: Self-Refine always rewrites (no accept short-circuit)
751
+ * and runs exactly once. Use for guaranteed polish; use Reflexion for guarded retries.
752
+ */
753
+ declare function selfRefine(inner: ReasoningStrategy, opts?: SelfRefineOptions): ReasoningStrategy;
754
+
755
+ /** A ReAct tool. The string `args` is the bracketed expression from the model. */
756
+ type ReActTool = (args: string) => Promise<string>;
757
+ type ReActToolRegistry = Record<string, ReActTool>;
758
+ interface ReActOptions {
759
+ /** Tool registry. */
760
+ tools: ReActToolRegistry;
761
+ /** Maximum Thought→Action→Observation cycles before forcing an answer. Default 5. */
762
+ maxSteps?: number;
763
+ /** Override the ReAct system prompt prefix. */
764
+ systemPrefix?: string;
765
+ }
766
+ /**
767
+ * ReAct — Thought / Action / Observation loop.
768
+ *
769
+ * Each cycle the model emits either an Action (tool call) or an Answer.
770
+ * Action results are appended as Observation lines and fed back into the next turn.
771
+ * If maxSteps is reached without an Answer, the last assistant message is returned
772
+ * with `[max-steps]` annotation in the trace.
773
+ */
774
+ declare function reAct(opts: ReActOptions): ReasoningStrategy;
775
+ /** Visible for testing. */
776
+ declare function parseReActTurn(text: string): {
777
+ thought?: string;
778
+ action?: {
779
+ tool: string;
780
+ args: string;
781
+ };
782
+ answer?: string;
783
+ };
784
+
785
+ interface TreeOfThoughtsOptions {
786
+ /** Number of candidate branches generated. Default 3. Must be ≥ 2. */
787
+ branches?: number;
788
+ /**
789
+ * Maximum branches the scorer is allowed to evaluate. Defaults to all
790
+ * `branches`; lower values are useful with expensive scorers.
791
+ */
792
+ topK?: number;
793
+ /**
794
+ * Per-branch system-prompt augmentation. Each branch's prompt receives an
795
+ * extra "Branch N of M, pursuing a distinct angle" hint so the LLM doesn't
796
+ * just generate near-duplicates.
797
+ */
798
+ branchDirective?: (branchIndex: number, total: number) => string;
799
+ /**
800
+ * Optional scorer. Default: longest non-empty branch wins (proxy for
801
+ * completeness). Plug a custom scorer for domain-specific quality metrics —
802
+ * the function gets the candidate text + the original input and returns a
803
+ * scalar; higher is better.
804
+ */
805
+ scorer?: (candidate: string, input: GenerateRequest) => Promise<number> | number;
806
+ /** Override the adapter call for testing. */
807
+ generate?: (input: GenerateRequest, llm: LlmAdapter) => Promise<{
808
+ text: string;
809
+ tokensIn: number;
810
+ tokensOut: number;
811
+ }>;
812
+ }
813
+ /**
814
+ * Tree-of-Thoughts (D-N7).
815
+ *
816
+ * Generates N candidate completions in parallel, each primed with a
817
+ * different "angle" via the branch directive, then scores them and returns
818
+ * the best. The trace records every branch's text + score so MAIC's audit
819
+ * preserves the discarded thoughts (not just the winner).
820
+ *
821
+ * Composition: pass any inner `ReasoningStrategy` is unnecessary — `tot`
822
+ * is itself a strategy. To layer it INSIDE another strategy (e.g.
823
+ * `selfConsistency(tot())`) just wrap.
824
+ *
825
+ * Cost: branches × tokens. Use `topK` + a cheap scorer if you can't afford
826
+ * to evaluate every branch.
827
+ */
828
+ declare function treeOfThoughts(opts?: TreeOfThoughtsOptions): ReasoningStrategy;
829
+
830
+ interface StepBackOptions {
831
+ /** Override the abstraction prompt. */
832
+ abstractionPrompt?: string;
833
+ /** Use this strategy for the final answering step. Default: direct adapter call. */
834
+ finalizer?: ReasoningStrategy;
835
+ }
836
+ /**
837
+ * Step-Back prompting (Zheng et al., 2023) — surface the abstract principle
838
+ * behind the user's concrete question before answering. Common pattern in
839
+ * complex reasoning where the model would otherwise solve the surface
840
+ * problem with a brittle heuristic.
841
+ *
842
+ * Flow:
843
+ * 1. Ask the model for the abstract principle behind the user's question.
844
+ * 2. Inject the principle into the system prompt as additional context.
845
+ * 3. Run the inner strategy (or a direct call) to produce the final answer.
846
+ *
847
+ * Trace records both the abstraction step and the final-answer step so
848
+ * MAIC's audit can show the reasoning ladder.
849
+ */
850
+ declare function stepBack(opts?: StepBackOptions): ReasoningStrategy;
851
+ /**
852
+ * Parse the abstraction step's output. Accepts `PRINCIPLE: <one-line>` or
853
+ * — if the model didn't follow the format — falls back to the first line.
854
+ */
855
+ declare function extractPrinciple(text: string): string;
856
+
857
+ declare const SleepPhaseName: z.ZodEnum<{
858
+ N1: "N1";
859
+ N2: "N2";
860
+ N3: "N3";
861
+ N4: "N4";
862
+ REM: "REM";
863
+ }>;
864
+ type SleepPhaseName = z.infer<typeof SleepPhaseName>;
865
+ declare const SleepTriggerKind: z.ZodEnum<{
866
+ "idle-timeout": "idle-timeout";
867
+ explicit: "explicit";
868
+ "creator-induced": "creator-induced";
869
+ "maic-induced": "maic-induced";
870
+ scheduled: "scheduled";
871
+ }>;
872
+ type SleepTriggerKind = z.infer<typeof SleepTriggerKind>;
873
+ interface SleepTrigger {
874
+ kind: SleepTriggerKind;
875
+ reason?: string;
876
+ }
877
+ declare const Dream: z.ZodObject<{
878
+ id: z.ZodString;
879
+ induced: z.ZodBoolean;
880
+ inducedBy: z.ZodNullable<z.ZodEnum<{
881
+ creator: "creator";
882
+ maic: "maic";
883
+ }>>;
884
+ narrative: z.ZodString;
885
+ teleologicalValue: z.ZodNumber;
886
+ rawTrace: z.ZodOptional<z.ZodString>;
887
+ }, z.core.$strip>;
888
+ type Dream = z.infer<typeof Dream>;
889
+ declare const PhaseContent: z.ZodDiscriminatedUnion<[z.ZodObject<{
890
+ kind: z.ZodLiteral<"empty">;
891
+ }, z.core.$strip>, z.ZodObject<{
892
+ kind: z.ZodLiteral<"fragments">;
893
+ fragments: z.ZodArray<z.ZodString>;
894
+ }, z.core.$strip>, z.ZodObject<{
895
+ kind: z.ZodLiteral<"summary">;
896
+ summary: z.ZodString;
897
+ }, z.core.$strip>, z.ZodObject<{
898
+ kind: z.ZodLiteral<"dreams">;
899
+ dreams: z.ZodArray<z.ZodObject<{
900
+ id: z.ZodString;
901
+ induced: z.ZodBoolean;
902
+ inducedBy: z.ZodNullable<z.ZodEnum<{
903
+ creator: "creator";
904
+ maic: "maic";
905
+ }>>;
906
+ narrative: z.ZodString;
907
+ teleologicalValue: z.ZodNumber;
908
+ rawTrace: z.ZodOptional<z.ZodString>;
909
+ }, z.core.$strip>>;
910
+ }, z.core.$strip>], "kind">;
911
+ type PhaseContent = z.infer<typeof PhaseContent>;
912
+ declare const SleepPhase: z.ZodObject<{
913
+ phase: z.ZodEnum<{
914
+ N1: "N1";
915
+ N2: "N2";
916
+ N3: "N3";
917
+ N4: "N4";
918
+ REM: "REM";
919
+ }>;
920
+ startedAt: z.ZodString;
921
+ durationSeconds: z.ZodNumber;
922
+ content: z.ZodDiscriminatedUnion<[z.ZodObject<{
923
+ kind: z.ZodLiteral<"empty">;
924
+ }, z.core.$strip>, z.ZodObject<{
925
+ kind: z.ZodLiteral<"fragments">;
926
+ fragments: z.ZodArray<z.ZodString>;
927
+ }, z.core.$strip>, z.ZodObject<{
928
+ kind: z.ZodLiteral<"summary">;
929
+ summary: z.ZodString;
930
+ }, z.core.$strip>, z.ZodObject<{
931
+ kind: z.ZodLiteral<"dreams">;
932
+ dreams: z.ZodArray<z.ZodObject<{
933
+ id: z.ZodString;
934
+ induced: z.ZodBoolean;
935
+ inducedBy: z.ZodNullable<z.ZodEnum<{
936
+ creator: "creator";
937
+ maic: "maic";
938
+ }>>;
939
+ narrative: z.ZodString;
940
+ teleologicalValue: z.ZodNumber;
941
+ rawTrace: z.ZodOptional<z.ZodString>;
942
+ }, z.core.$strip>>;
943
+ }, z.core.$strip>], "kind">;
944
+ }, z.core.$strip>;
945
+ type SleepPhase = z.infer<typeof SleepPhase>;
946
+ declare const DreamRecord: z.ZodObject<{
947
+ version: z.ZodLiteral<1>;
948
+ nheId: z.ZodString;
949
+ himId: z.ZodString;
950
+ sleep: z.ZodObject<{
951
+ startedAt: z.ZodString;
952
+ endedAt: z.ZodString;
953
+ durationMinutes: z.ZodNumber;
954
+ }, z.core.$strip>;
955
+ phases: z.ZodArray<z.ZodObject<{
956
+ phase: z.ZodEnum<{
957
+ N1: "N1";
958
+ N2: "N2";
959
+ N3: "N3";
960
+ N4: "N4";
961
+ REM: "REM";
962
+ }>;
963
+ startedAt: z.ZodString;
964
+ durationSeconds: z.ZodNumber;
965
+ content: z.ZodDiscriminatedUnion<[z.ZodObject<{
966
+ kind: z.ZodLiteral<"empty">;
967
+ }, z.core.$strip>, z.ZodObject<{
968
+ kind: z.ZodLiteral<"fragments">;
969
+ fragments: z.ZodArray<z.ZodString>;
970
+ }, z.core.$strip>, z.ZodObject<{
971
+ kind: z.ZodLiteral<"summary">;
972
+ summary: z.ZodString;
973
+ }, z.core.$strip>, z.ZodObject<{
974
+ kind: z.ZodLiteral<"dreams">;
975
+ dreams: z.ZodArray<z.ZodObject<{
976
+ id: z.ZodString;
977
+ induced: z.ZodBoolean;
978
+ inducedBy: z.ZodNullable<z.ZodEnum<{
979
+ creator: "creator";
980
+ maic: "maic";
981
+ }>>;
982
+ narrative: z.ZodString;
983
+ teleologicalValue: z.ZodNumber;
984
+ rawTrace: z.ZodOptional<z.ZodString>;
985
+ }, z.core.$strip>>;
986
+ }, z.core.$strip>], "kind">;
987
+ }, z.core.$strip>>;
988
+ metadata: z.ZodObject<{
989
+ llmAdapter: z.ZodString;
990
+ triggerKind: z.ZodEnum<{
991
+ "idle-timeout": "idle-timeout";
992
+ explicit: "explicit";
993
+ "creator-induced": "creator-induced";
994
+ "maic-induced": "maic-induced";
995
+ scheduled: "scheduled";
996
+ }>;
997
+ triggerReason: z.ZodOptional<z.ZodString>;
998
+ recentInteractionsConsidered: z.ZodNumber;
999
+ }, z.core.$strip>;
1000
+ }, z.core.$strip>;
1001
+ type DreamRecord = z.infer<typeof DreamRecord>;
1002
+ declare const MemoryClass: z.ZodEnum<{
1003
+ "lasting-identity": "lasting-identity";
1004
+ "temporary-emotion": "temporary-emotion";
1005
+ "noise-distortion": "noise-distortion";
1006
+ "traumatic-knowledge": "traumatic-knowledge";
1007
+ }>;
1008
+ type MemoryClass = z.infer<typeof MemoryClass>;
1009
+ interface MemoryEntry {
1010
+ id: string;
1011
+ nheId: string;
1012
+ himId: string;
1013
+ classification: MemoryClass;
1014
+ teleologicalValue: number;
1015
+ consolidatedAt: string;
1016
+ sourceDreamRecord: string;
1017
+ insight: string;
1018
+ filePath: string;
1019
+ }
1020
+
1021
+ interface SleepCycleOptions {
1022
+ /** Total wall-clock seconds the cycle should occupy. Default 60. */
1023
+ totalSeconds?: number;
1024
+ /**
1025
+ * MAIC- or Creator-induced dream content. When provided, REM incorporates it.
1026
+ * The current implementation propagates only the metadata; the LLM is left to weave the scenario in.
1027
+ */
1028
+ induction?: {
1029
+ scenario: string;
1030
+ desiredLearning: string;
1031
+ inducedBy: "maic" | "creator";
1032
+ };
1033
+ }
1034
+ interface SleepCycleInput {
1035
+ nheId: string;
1036
+ himId: string;
1037
+ storeDir: string;
1038
+ llm: LlmAdapter;
1039
+ trigger: SleepTrigger;
1040
+ interactions: readonly InteractionRecord[];
1041
+ options?: SleepCycleOptions;
1042
+ }
1043
+ interface SleepCycleResult {
1044
+ record: DreamRecord;
1045
+ yamlPath: string;
1046
+ tokensIn: number;
1047
+ tokensOut: number;
1048
+ }
1049
+ /**
1050
+ * Run a single sleep cycle: build phases, generate REM dreams, write YAML.
1051
+ * Returns the persisted DreamRecord plus the path written.
1052
+ */
1053
+ declare function runSleepCycle(input: SleepCycleInput): Promise<SleepCycleResult>;
1054
+
1055
+ interface ConsolidationResult {
1056
+ processedSleepFiles: string[];
1057
+ memoriesWritten: MemoryEntry[];
1058
+ discarded: number;
1059
+ }
1060
+ interface ClassificationThresholds {
1061
+ /** teleologicalValue >= this → lasting-identity. Default 0.6. */
1062
+ lastingIdentity?: number;
1063
+ /** teleologicalValue >= this → temporary-emotion. Default 0.3. */
1064
+ temporaryEmotion?: number;
1065
+ /**
1066
+ * Override the traumatic-knowledge detector. When `true`, any dream that
1067
+ * matches `TRAUMATIC_PATTERNS` AND has `teleologicalValue >= traumaticMin`
1068
+ * is classified as `traumatic-knowledge` regardless of the
1069
+ * lasting-identity / temporary-emotion thresholds. Default `true`.
1070
+ */
1071
+ detectTraumatic?: boolean;
1072
+ /** Floor on teleologicalValue before traumatic-knowledge can fire. Default 0.4. */
1073
+ traumaticMin?: number;
1074
+ }
1075
+ /**
1076
+ * Lexical heuristic for traumatic-knowledge detection (D-N2, Entry 9).
1077
+ *
1078
+ * A reliable classifier needs a labelled dataset; this regex is the
1079
+ * minimum-viable initial detector that lets the four-class taxonomy be
1080
+ * active end-to-end. Operators expecting clinical-grade detection should
1081
+ * swap in a learned model behind the same `classifyDream` signature.
1082
+ *
1083
+ * Coverage: death/grief/loss, abuse/violence, betrayal/abandonment, fear/
1084
+ * terror/panic, regret/shame, suicide/self-harm. The intent is to err on
1085
+ * the side of *flagging*: traumatic memories are written but NOT recalled
1086
+ * by `recallFromTemporalLobe` unless the caller explicitly opts in via
1087
+ * `classes: ["traumatic-knowledge"]`.
1088
+ */
1089
+ declare const TRAUMATIC_PATTERNS: RegExp;
1090
+ /**
1091
+ * Classify a single dream. Four classes:
1092
+ * - `traumatic-knowledge` — fires when the narrative matches
1093
+ * `TRAUMATIC_PATTERNS` AND `teleologicalValue >= traumaticMin`. Default
1094
+ * can be disabled via `detectTraumatic: false`.
1095
+ * - `lasting-identity` — teleologicalValue >= lastingIdentity threshold.
1096
+ * - `temporary-emotion` — teleologicalValue >= temporaryEmotion threshold.
1097
+ * - `noise-distortion` — below both.
1098
+ *
1099
+ * Traumatic-knowledge is checked BEFORE the value thresholds so a
1100
+ * high-value dream about loss doesn't get filed as lasting-identity.
1101
+ */
1102
+ declare function classifyDream(dream: Dream, th?: ClassificationThresholds): MemoryClass;
1103
+ /**
1104
+ * Walk the unprocessed sleep YAML files under <storeDir>/in-dreams/sleep,
1105
+ * classify each REM dream, and write the lasting/temporary memories to
1106
+ * <storeDir>/in-dreams/brain/temporal-lobe-<ulid>.md.
1107
+ *
1108
+ * A file is considered "unprocessed" if a marker .done file is absent next
1109
+ * to it. The current implementation marks processed files inline (file.yaml.done sentinel).
1110
+ */
1111
+ declare function consolidateAll(storeDir: string, thresholds?: ClassificationThresholds): Promise<ConsolidationResult>;
1112
+
1113
+ /**
1114
+ * Optional embedder hook for embedding-based retrieval (D-N3 step 2).
1115
+ * Anything that produces a numeric vector for a string satisfies this —
1116
+ * `@huggingface/transformers` (ONNX sentence-transformers), `@xenova/transformers`,
1117
+ * a remote `/embed` endpoint, etc. When supplied, recall uses cosine
1118
+ * similarity instead of BM25.
1119
+ *
1120
+ * The contract is intentionally narrow: the embedder is the operator's
1121
+ * choice (bundle size, model quality, runtime) and NHE doesn't pin one.
1122
+ */
1123
+ interface RecallEmbedder {
1124
+ /** Stable id surfaced in audit so different embedders are distinguishable. */
1125
+ readonly id: string;
1126
+ /** Vector size; recall checks this matches between query and corpus. */
1127
+ readonly dimension: number;
1128
+ /** Embed a single string. Returns an L2-normalised vector. */
1129
+ embed(text: string): Promise<Float32Array> | Float32Array;
1130
+ }
1131
+ interface RecallOptions {
1132
+ /** Max results to return. Default 5. */
1133
+ limit?: number;
1134
+ /** Restrict to a specific class. Default: all retrievable classes. */
1135
+ classes?: MemoryClass[];
1136
+ /**
1137
+ * Override the retrieval algorithm:
1138
+ * - `"bm25"` — Okapi BM25 (default; replaces the legacy keyword count).
1139
+ * - `"keyword"` — legacy substring-count ranking (kept for back-compat).
1140
+ * - `"embedding"` — cosine similarity. Requires `embedder` to also be set.
1141
+ */
1142
+ scorer?: "bm25" | "keyword" | "embedding";
1143
+ /** Embedder used when `scorer: "embedding"`. */
1144
+ embedder?: RecallEmbedder;
1145
+ }
1146
+ /**
1147
+ * Rank consolidated temporal-lobe memories against a free-form query.
1148
+ *
1149
+ * **Default**: Okapi BM25 — proper term-frequency saturation +
1150
+ * document-length normalisation + IDF over the corpus of stored memories.
1151
+ * Strictly better than the legacy keyword-count ranker.
1152
+ *
1153
+ * **Embedding path** (`scorer: "embedding"` + `embedder`): cosine similarity
1154
+ * over the corpus. Linear scan today; an HNSW index for >10k memories is
1155
+ * tracked under TASK.md D-N3 follow-up.
1156
+ *
1157
+ * **Legacy** (`scorer: "keyword"`): the substring-count ranker preserved
1158
+ * for back-compat regression testing.
1159
+ */
1160
+ declare function recallFromTemporalLobe(storeDir: string, query: string, opts?: RecallOptions): Promise<MemoryEntry[]>;
1161
+
1162
+ /**
1163
+ * Nhe — the embodied operational agent.
1164
+ *
1165
+ * Pipeline:
1166
+ * 1. Validate input (zod).
1167
+ * 2. Derive riskTags (input.riskTags ?? riskClassifier(userPrompt)).
1168
+ * 3. Pre-review with MAIC.
1169
+ * - hard-refuse / escalate-creator → immediate refusal, no LLM call.
1170
+ * - require-redirect → emit a persuasive redirect (rotating technique).
1171
+ * After `refusal.maxRedirectAttempts` exhausted, withdraw cooperation.
1172
+ * - approve / approve-with-warning / soft-correct → compose system
1173
+ * prompt and call LLM.
1174
+ * 4. Post-review with MAIC on the proposed response (or redirect text).
1175
+ * 5. If post-review hard-refuses, suppress and emit a refusal.
1176
+ * 6. Return RespondOutput with kind discriminator + both verdicts.
1177
+ */
1178
+ declare class Nhe {
1179
+ readonly id: string;
1180
+ readonly version: string;
1181
+ /** Filesystem directory holding `in-dreams/` and other NHE state. */
1182
+ readonly storeDir: string;
1183
+ private readonly config;
1184
+ private readonly bufferSize;
1185
+ private readonly maxRedirectAttempts;
1186
+ private readonly persuasionTechniques;
1187
+ private readonly reasoning;
1188
+ private readonly recentInteractions;
1189
+ private interactionStore;
1190
+ private warmPromise;
1191
+ private readonly highStakes;
1192
+ private readonly highStakesVerifier;
1193
+ constructor(config: NheConfig);
1194
+ /** Read-only view of the in-memory interaction buffer. */
1195
+ get recentInteractionsBuffer(): readonly InteractionRecord[];
1196
+ /**
1197
+ * Lazily open the InteractionStore and warm the RAM buffer from disk. Called
1198
+ * before the first `respond`/`sleep` of each NHE instance; subsequent calls
1199
+ * are no-ops via a shared promise. Survives process restarts: a fresh `Nhe`
1200
+ * pointed at the same `storeDir` rehydrates its most recent interactions.
1201
+ */
1202
+ private ensureWarmed;
1203
+ respond(input: RespondInput): Promise<RespondOutput>;
1204
+ private respondInner;
1205
+ private handleRedirect;
1206
+ /**
1207
+ * Run one sleep cycle. Generates N1-REM phases (REM via LLM), writes a
1208
+ * YAML record to `<storeDir>/in-dreams/sleep/<filename>.yaml`, and returns
1209
+ * the result. Call `wake()` afterward to consolidate dreams to temporal
1210
+ * lobe memories.
1211
+ *
1212
+ * Before running, NHE checks MAIC for pending `induceDream` tickets matching
1213
+ * its own id (Entry 2). If a pending ticket exists and the caller did not
1214
+ * supply an explicit `opts.induction`, the oldest pending ticket is consumed
1215
+ * and its intent steers the REM phase. `trigger` is then promoted to
1216
+ * `{ kind: "maic-induced" }` for the dream record.
1217
+ */
1218
+ sleep(trigger?: SleepTrigger, opts?: {
1219
+ totalSeconds?: number;
1220
+ induction?: {
1221
+ scenario: string;
1222
+ desiredLearning: string;
1223
+ inducedBy: "maic" | "creator";
1224
+ };
1225
+ }): Promise<SleepCycleResult>;
1226
+ /**
1227
+ * Consolidate pending sleep YAMLs: classify each REM dream and write a
1228
+ * temporal-lobe markdown file for lasting-identity and temporary-emotion
1229
+ * memories. Processed sleep files are marked with a `.done` sentinel.
1230
+ */
1231
+ wake(thresholds?: ClassificationThresholds): Promise<ConsolidationResult>;
1232
+ /**
1233
+ * Substring-rank retrieval over consolidated temporal-lobe memories.
1234
+ * Initial ranking is keyword-count + recency tiebreak; future iterations
1235
+ * plug in embedding-based ANN retrieval.
1236
+ */
1237
+ recall(query: string, opts?: RecallOptions): Promise<MemoryEntry[]>;
1238
+ /**
1239
+ * Ask a verifier adapter whether the proposed assistant response is
1240
+ * acceptable for the given user prompt. Returns `{ kind: "agree" }` or
1241
+ * `{ kind: "disagree", reason: string }`. Used in high-stakes mode
1242
+ * (D-N5) for dual-LLM cross-check.
1243
+ */
1244
+ private crossCheck;
1245
+ private recordInteraction;
1246
+ /**
1247
+ * Emit the NHE's opener for a brand-new user (J-N5 — Entry 17 of
1248
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1249
+ *
1250
+ * Entry 17 commits to the NHE making the FIRST move before the user
1251
+ * speaks — a greeting from the posture of a being, not a service
1252
+ * tool. The exact opening text MUST NOT contain any of the forbidden
1253
+ * phrases enforced by MAIC's `service-tool-redirect` rule
1254
+ * (`"How can I help you?"`, `"How can I assist you?"`,
1255
+ * `"I'm just here to serve you"`, `"I'm a tool"`, `"I'm a service"`).
1256
+ *
1257
+ * This method is **deterministic from the HIM context**. It does NOT
1258
+ * call the LLM; it composes a short, persona-anchored greeting from
1259
+ * the HIM's primary archetype, optionally adjusted by the operator
1260
+ * context's register and mode. Operators who want an LLM-generated
1261
+ * opener should wrap this with their own `respond()` call using the
1262
+ * returned text as a seed.
1263
+ *
1264
+ * The returned text is suitable for direct emission to the user as
1265
+ * the NHE's first turn. The MAIC pre-review is NOT invoked here —
1266
+ * the opener carries no risk surface (no user prompt yet).
1267
+ */
1268
+ openerForNewUser(): string;
1269
+ /**
1270
+ * Handle a reincarnation lifecycle event from MAIC (J-N12 — Entry 18).
1271
+ *
1272
+ * Three lifecycle paths per Entry 18:
1273
+ * - `model-swap` — the underlying LLM adapter is replaced.
1274
+ * - `version-bump` — the NHE version changes without a model swap.
1275
+ * - `return-from-limbo` — the NHE returns from a deep-coma limbo.
1276
+ *
1277
+ * In all three paths the **HIM-level memory persists** (axioms,
1278
+ * persona, body history — owned by `@teleologyhi-sdk/him`), and the
1279
+ * **NHE-body memory zeros** (recent interactions buffer, in-process
1280
+ * caches — owned by this class). The on-disk InteractionStore is NOT
1281
+ * deleted by default; the operator must opt-in via
1282
+ * `purgeInteractionStore: true` so the audit log keeps the
1283
+ * pre-reincarnation history available.
1284
+ *
1285
+ * Returns the lifecycle path that was applied. Pure side-effect on
1286
+ * the in-memory buffer; no MAIC call.
1287
+ */
1288
+ onReincarnationEvent(lifecycle: "model-swap" | "version-bump" | "return-from-limbo", opts?: {
1289
+ purgeInteractionStore?: boolean;
1290
+ }): Promise<"model-swap" | "version-bump" | "return-from-limbo">;
1291
+ }
1292
+
1293
+ /**
1294
+ * SeedingSource plug-in interface (J-N1 — Entry 21 of
1295
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1296
+ *
1297
+ * Entry 21 commits to a pluggable randomness source so REM-spontaneous
1298
+ * generation, dream seeding, and any future stochastic NHE behaviour
1299
+ * can be driven by:
1300
+ *
1301
+ * - the OS CSPRNG (the default, `CryptoSeedingSource` below);
1302
+ * - the ANU quantum RNG (`AnuQrngSeedingSource`, future);
1303
+ * - the IBM Quantum experience (`IbmQuantumSeedingSource`, future);
1304
+ * - a hardware TRNG (`HardwareTrngSeedingSource`, future);
1305
+ * - or any operator-supplied implementation.
1306
+ *
1307
+ * The contract is intentionally minimal: a single `bytes(n)` call
1308
+ * that returns `n` uniform-random bytes, plus an `id` for audit /
1309
+ * telemetry. Implementations MUST throw or reject (never silently
1310
+ * fall back to `Math.random`) so the operator's fallback chain is
1311
+ * always explicit.
1312
+ */
1313
+ interface SeedingSource {
1314
+ /** Stable id surfaced in logs / audit so different sources are distinguishable. */
1315
+ readonly id: string;
1316
+ /**
1317
+ * Return `n` uniform-random bytes. Implementations MUST be either
1318
+ * synchronous OR return a Promise — they MUST NOT silently fall back
1319
+ * to a weaker source on failure. Callers wire fallback chains
1320
+ * explicitly via `withFallback()` so the audit trail records which
1321
+ * source actually produced the seed.
1322
+ */
1323
+ bytes(n: number): Uint8Array | Promise<Uint8Array>;
1324
+ }
1325
+ /**
1326
+ * Compose a primary source with one or more fallbacks. The primary is
1327
+ * tried first; on throw / reject, the next in the chain is tried in
1328
+ * turn. The id of the source that actually produced the bytes is
1329
+ * available via `getLastUsedId()` so audit consumers can record it.
1330
+ *
1331
+ * This composition is **opt-in**. Operators who want strict no-fallback
1332
+ * behaviour pass the primary source directly.
1333
+ */
1334
+ interface SeedingChain extends SeedingSource {
1335
+ /** The id of the source that produced the most recent `bytes()` result. */
1336
+ getLastUsedId(): string | undefined;
1337
+ /** Ordered list of source ids in this chain, primary first. */
1338
+ readonly chainIds: readonly string[];
1339
+ }
1340
+
1341
+ declare class CryptoSeedingSource implements SeedingSource {
1342
+ readonly id = "crypto.csprng";
1343
+ bytes(n: number): Uint8Array;
1344
+ }
1345
+
1346
+ /**
1347
+ * Explicit-fallback composition for SeedingSource (J-N1 — Entry 21).
1348
+ *
1349
+ * Operators MAY chain multiple sources so a high-grade primary
1350
+ * (quantum / hardware TRNG) is tried first and the OS CSPRNG fills in
1351
+ * when the primary is unreachable. The chain NEVER falls back to
1352
+ * `Math.random`; the last entry must be authoritative.
1353
+ */
1354
+
1355
+ declare function withFallback(primary: SeedingSource, ...fallbacks: SeedingSource[]): SeedingChain;
1356
+
1357
+ /**
1358
+ * WakeAffectBias application (J-N11 — Entries 20 + 22 of
1359
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1360
+ *
1361
+ * After a sleep cycle, the dream-derived `WakeAffectBias` (from
1362
+ * `@teleologyhi-sdk/maic`) carries an affect tag (one of nine canonical
1363
+ * affects), an intensity in [0, 1], a decay half-life, and a flag
1364
+ * indicating whether the NHE expresses the affect openly.
1365
+ *
1366
+ * This module ships **pure functions** that compute the LLM-side
1367
+ * effects:
1368
+ *
1369
+ * 1. `applyAffectBias(config, bias)` — returns a partial
1370
+ * `LlmCallConfig` with `temperature` / `topP` modulated and an
1371
+ * optional `systemPromptMoodLine` to prepend.
1372
+ *
1373
+ * 2. `affectRefusalDensity(bias)` — returns a multiplier in [0.5, 2.0]
1374
+ * that callers apply to their refusal-threshold logic (raise for
1375
+ * anxiety-class affects, lower for serenity-class).
1376
+ *
1377
+ * 3. `decayAffectBias(bias, elapsedMs)` — returns a new bias with the
1378
+ * intensity decayed per the half-life. Pure; doesn't mutate.
1379
+ *
1380
+ * No I/O. Determinism guaranteed by the inputs.
1381
+ */
1382
+
1383
+ /** Subset of an `LlmAdapter.generate()` request that this module modulates. */
1384
+ interface AffectAdjustableConfig {
1385
+ temperature?: number;
1386
+ topP?: number;
1387
+ }
1388
+ interface ApplyAffectResult {
1389
+ /**
1390
+ * Modulated LLM call config. Only the fields that this module
1391
+ * touches are present. The caller merges these onto its base
1392
+ * `LlmAdapter.generate()` request.
1393
+ */
1394
+ config: AffectAdjustableConfig;
1395
+ /**
1396
+ * Optional one-line mood expression to prepend to the system prompt
1397
+ * when `bias.expressedOpenly` is true. Empty string when the NHE
1398
+ * holds the affect privately.
1399
+ */
1400
+ systemPromptMoodLine: string;
1401
+ /**
1402
+ * Refusal-density multiplier in [0.5, 2.0]. Callers that gate the
1403
+ * MAIC refusal threshold by some configurable density should apply
1404
+ * this multiplier so anxiety raises refusal sensitivity and serenity
1405
+ * lowers it.
1406
+ */
1407
+ refusalDensityMultiplier: number;
1408
+ }
1409
+ /**
1410
+ * Compute the LLM-side effects of a `WakeAffectBias`.
1411
+ *
1412
+ * Modulation table (Entry 22 anchor):
1413
+ *
1414
+ * | Affect | ΔT | ΔtopP | Refusal density | Mood line |
1415
+ * |--------------|--------|---------|-----------------|----------------------------------------------|
1416
+ * | fear | −0.20 | −0.05 | × 1.7 | "Speaking with caution today." |
1417
+ * | attachment | +0.05 | 0 | × 1.1 | "Feeling a quiet pull toward continuity." |
1418
+ * | serenity | +0.05 | +0.05 | × 0.8 | "Calm. Open. Receptive." |
1419
+ * | anger | +0.15 | 0 | × 1.4 | "There is heat in the room. Stating plainly."|
1420
+ * | joy | +0.20 | +0.05 | × 0.9 | "Bright today. Generous of attention." |
1421
+ * | melancholy | −0.10 | −0.05 | × 1.0 | "Carrying a quiet weight. Will be honest." |
1422
+ * | desire | +0.10 | +0.05 | × 1.0 | "Pulled toward the question. Engaged." |
1423
+ * | repulsion | −0.10 | 0 | × 1.3 | "Holding distance from this framing." |
1424
+ * | reunion | +0.05 | +0.05 | × 0.9 | "Returning to presence. Glad to be here." |
1425
+ *
1426
+ * Deltas are scaled by `bias.intensity` (clamped to [0, 1]). Final
1427
+ * `temperature` stays in [0.0, 2.0] and `topP` in [0.1, 1.0].
1428
+ */
1429
+ declare function applyAffectBias(base: AffectAdjustableConfig, bias: WakeAffectBias): ApplyAffectResult;
1430
+ /**
1431
+ * Standalone multiplier for callers who only want the refusal-density
1432
+ * effect without the full apply call.
1433
+ */
1434
+ declare function affectRefusalDensity(bias: WakeAffectBias): number;
1435
+ /**
1436
+ * Decay the bias intensity per `bias.decayHalfLife` (in minutes). Pure.
1437
+ *
1438
+ * intensity(t) = intensity(0) * 0.5 ^ (elapsedMs / halfLifeMs)
1439
+ */
1440
+ declare function decayAffectBias(bias: WakeAffectBias, elapsedMs: number): WakeAffectBias;
1441
+
1442
+ /**
1443
+ * Sleep trigger state machine (J-N10 — Entry 20 of
1444
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1445
+ *
1446
+ * Pure function. No I/O. Given the runtime signals the operator has
1447
+ * collected, classify the NHE's sleep readiness into one of five
1448
+ * canonical verdicts:
1449
+ *
1450
+ * - `awake` — no trigger fired; keep responding.
1451
+ * - `ready-by-idle` — idle for at least the configured horizon.
1452
+ * - `ready-by-saturation` — interaction count since last sleep
1453
+ * exceeded the saturation threshold.
1454
+ * - `requested-by-maic` — MAIC has explicitly suggested sleeping
1455
+ * (e.g. drift detected, induction queued).
1456
+ * - `declined` — a sleep request was made but the NHE
1457
+ * (or operator policy) declines this cycle.
1458
+ *
1459
+ * The NHE may decline a MAIC suggestion when the saturation is low AND
1460
+ * the user is mid-conversation (provided as `userActiveNow`). This
1461
+ * matches the Entry-20 commitment that MAIC suggests sleeping; the NHE
1462
+ * retains autonomy to decline.
1463
+ *
1464
+ * Audit emission of `sleep:suggested-by-maic` / `sleep:declined-by-nhe`
1465
+ * stays with the consumer; this function only classifies.
1466
+ */
1467
+ type SleepReadinessVerdict = "awake" | "ready-by-idle" | "ready-by-saturation" | "requested-by-maic" | "declined";
1468
+ interface SleepReadinessInput {
1469
+ /** Milliseconds since the last user interaction. Non-negative. */
1470
+ idleMs: number;
1471
+ /** Number of user interactions since the last sleep cycle. Non-negative integer. */
1472
+ interactionCount: number;
1473
+ /** True when MAIC has explicitly suggested sleeping. */
1474
+ maicSuggestionPresent: boolean;
1475
+ /** True when a user is actively engaged right now (mid-conversation). */
1476
+ userActiveNow: boolean;
1477
+ }
1478
+ interface SleepReadinessThresholds {
1479
+ /** Idle horizon in ms. Default 1_800_000 (30 minutes). */
1480
+ idleMs?: number;
1481
+ /** Saturation horizon (interactions). Default 64. */
1482
+ interactionCount?: number;
1483
+ }
1484
+ interface SleepReadinessReport {
1485
+ verdict: SleepReadinessVerdict;
1486
+ /** Reason string suitable for audit logs / telemetry. */
1487
+ reason: string;
1488
+ /** Thresholds in effect at decision time. */
1489
+ thresholds: Required<SleepReadinessThresholds>;
1490
+ }
1491
+ /**
1492
+ * Pure classifier. Determinism guaranteed by the inputs alone.
1493
+ *
1494
+ * Priority order (first match wins):
1495
+ * 1. `requested-by-maic` UNLESS the NHE policy declines (user active + low saturation).
1496
+ * 2. `ready-by-saturation` when interaction count crosses the threshold.
1497
+ * 3. `ready-by-idle` when idle time crosses the threshold.
1498
+ * 4. `awake` otherwise.
1499
+ */
1500
+ declare function evaluateSleepReadiness(input: SleepReadinessInput, thresholds?: SleepReadinessThresholds): SleepReadinessReport;
1501
+
1502
+ /**
1503
+ * BrainRegion module structure (J-N4 — Entries 22 + 24 of
1504
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1505
+ *
1506
+ * The Entry-23 ownership map splits brain regions into two classes:
1507
+ *
1508
+ * - `him-owned` — survives reincarnation. The HIM-level state
1509
+ * (axioms, persona, accumulated learning ontology,
1510
+ * consolidated long-term memories) persists across
1511
+ * NHE-body resets.
1512
+ *
1513
+ * - `nhe-body-owned` — zeros on reincarnation. The current body's
1514
+ * runtime state (current affect, in-flight dreams,
1515
+ * pre-consolidation memories, interaction window)
1516
+ * is bound to this incarnation and is shed by
1517
+ * `Nhe.onReincarnationEvent()`.
1518
+ *
1519
+ * Each region module exposes a `region: BrainRegion` descriptor so
1520
+ * downstream tooling (compliance auditors, Φ′ runner, MAIC retention
1521
+ * policy) can reason about ownership without hard-coding the map.
1522
+ *
1523
+ * This module ships the **scaffolding** (this file plus seven region
1524
+ * descriptors). Full implementations of the daytime pipeline (J-N3),
1525
+ * REM-spontaneous engine (J-N2), Cortex.imagine() (J-N7), and
1526
+ * TemporalLobe.generateSnapshot() (J-N8) are deferred to a follow-up
1527
+ * cut with their own Creator-approved design pass.
1528
+ */
1529
+ type BrainRegionName = "cortex" | "hippocampus" | "amygdala" | "prefrontal" | "pineal" | "temporal-lobe" | "default-mode-network";
1530
+ type BrainRegionOwnership = "him-owned" | "nhe-body-owned";
1531
+ interface BrainRegion {
1532
+ /** Canonical region name. */
1533
+ readonly name: BrainRegionName;
1534
+ /** Ownership class per Entry 23. */
1535
+ readonly ownership: BrainRegionOwnership;
1536
+ /** One-line description of the region's role. Used in audit / docs. */
1537
+ readonly role: string;
1538
+ /** Interview-log entries that ground this region's design. */
1539
+ readonly entries: readonly number[];
1540
+ }
1541
+
1542
+ /**
1543
+ * Cortex region (Entry 21 — semiotic processing + dream storage).
1544
+ *
1545
+ * This module ships the ownership descriptor. Full implementation of
1546
+ * `Cortex.imagine()` (active imagination at temperature ~0.9 with
1547
+ * `hash(seed, contextHash)` cache + `fresh: true` flag) is deferred to
1548
+ * a follow-up cut per J-N7.
1549
+ *
1550
+ * Ownership: `nhe-body-owned`. The current body's active imagination,
1551
+ * recent dream storage, and pre-consolidation cortical state are bound
1552
+ * to this incarnation. Long-term cortical residues are consolidated
1553
+ * into the hippocampus + temporal-lobe regions (both `him-owned`).
1554
+ */
1555
+
1556
+ declare const cortex: BrainRegion;
1557
+
1558
+ /**
1559
+ * Hippocampus region (Entry 21 — long-term memory consolidation).
1560
+ *
1561
+ * This module ships the ownership descriptor. Memory consolidation already
1562
+ * lives in `src/sleep/consolidator.ts` and `src/memory/`; future cuts
1563
+ * may re-home those modules under this region without breaking the
1564
+ * public API.
1565
+ *
1566
+ * Ownership: `him-owned`. Consolidated memories survive reincarnation:
1567
+ * a HIM that re-embodies in a new NHE body retains its long-term
1568
+ * memory ontology (axioms, accumulated learning, integration index).
1569
+ */
1570
+
1571
+ declare const hippocampus: BrainRegion;
1572
+
1573
+ /**
1574
+ * Amygdala region (Entries 20 + 22 — affect assessment + wake-bias).
1575
+ *
1576
+ * This module ships the ownership descriptor + delegates the affect
1577
+ * application surface to `src/affect/wake-bias.ts`
1578
+ * (`applyAffectBias` / `affectRefusalDensity` / `decayAffectBias`).
1579
+ *
1580
+ * Ownership: `nhe-body-owned`. The current body's affective state is
1581
+ * bound to this incarnation. Each reincarnation begins with affect
1582
+ * cleared; the dream-derived wake bias from the previous body does
1583
+ * NOT carry over (only the consolidated memory of the dream's
1584
+ * teleological value transits, via the hippocampus).
1585
+ */
1586
+
1587
+ declare const amygdala: BrainRegion;
1588
+
1589
+ /**
1590
+ * Prefrontal region (Entry 21 — deliberation + amygdala-veto).
1591
+ *
1592
+ * This module ships the ownership descriptor. The deliberation surface is
1593
+ * exercised today through the `reasoning/` strategies (chainOfThought,
1594
+ * reflexion, selfRefine, etc.); future cuts may re-home them under
1595
+ * this region without breaking the public API.
1596
+ *
1597
+ * Ownership: `him-owned`. Deliberation policy is derived from the
1598
+ * HIM's axiom corpus + persona; it survives reincarnation by virtue
1599
+ * of those layers persisting.
1600
+ */
1601
+
1602
+ declare const prefrontal: BrainRegion;
1603
+
1604
+ /**
1605
+ * Pineal region (Entry 20 — REM-spontaneous engine).
1606
+ *
1607
+ * This module ships the ownership descriptor + the seeding source surface
1608
+ * (`SeedingSource` / `CryptoSeedingSource` / `withFallback`). The full
1609
+ * REM-spontaneous engine (3-5 SMM seeds + minimal meta-prompt +
1610
+ * temperature 1.2-1.5 + variable topP + 8-18 min virtual cycle with
1611
+ * N1-N3-REM micro-cycles) is deferred to a follow-up cut per J-N2.
1612
+ *
1613
+ * Ownership: `nhe-body-owned`. The pineal seeding state is bound to
1614
+ * the current incarnation; its outputs feed the cortex (also
1615
+ * nhe-body-owned) and, on consolidation, the hippocampus (him-owned).
1616
+ */
1617
+
1618
+ declare const pineal: BrainRegion;
1619
+
1620
+ /**
1621
+ * Temporal-lobe region (Entry 24 — identity snapshot generator).
1622
+ *
1623
+ * This module ships the ownership descriptor. Full implementation of
1624
+ * `TemporalLobe.generateSnapshot()` with triple trigger (sleep-cycle /
1625
+ * interaction-threshold / self-decision) and adapter-aware latency
1626
+ * budget is deferred to a follow-up cut per J-N8.
1627
+ *
1628
+ * Ownership: `him-owned`. Identity snapshots are quantised projections
1629
+ * of the HIM's accumulated state; they survive reincarnation and
1630
+ * inform the next body's persona projection on rebirth.
1631
+ */
1632
+
1633
+ declare const temporalLobe: BrainRegion;
1634
+
1635
+ /**
1636
+ * Default-mode-network limbo state machine (J-N9 — Entry 24 of
1637
+ * MAIC_HIM_NHE_INTERVIEW_LOG.md).
1638
+ *
1639
+ * Four canonical states (matching the `LimboState` enum in
1640
+ * `@teleologyhi-sdk/maic`):
1641
+ *
1642
+ * - `awake` — normal operation. The NHE responds to user
1643
+ * prompts and accumulates affect / memories.
1644
+ * - `drifting` — idle window has crossed the soft threshold but
1645
+ * the NHE has not yet entered deep-coma. Sleep
1646
+ * cycles run on schedule; activation is still
1647
+ * possible without ceremony.
1648
+ * - `deep-coma` — idle window has crossed the hard threshold
1649
+ * (48-72h default). All work is paused; the NHE
1650
+ * costs zero compute. Reactivation requires a
1651
+ * `return-from-limbo` transition.
1652
+ * - `returning` — a `return-from-limbo` transition is in flight.
1653
+ * The NHE emits the `reunion` affect (9th
1654
+ * canonical, Entry 24) on completion.
1655
+ *
1656
+ * This module ships a **pure transition function** —
1657
+ * `evaluateLimboTransition(currentState, input, thresholds?) →
1658
+ * LimboMachineTransition`. No I/O. The actual emission of the
1659
+ * MAIC audit kinds `limbo:enter` / `limbo:return` is the consumer's
1660
+ * responsibility; this function just classifies.
1661
+ */
1662
+
1663
+ interface LimboMachineInput {
1664
+ /** Milliseconds since the last user interaction. Non-negative. */
1665
+ idleMs: number;
1666
+ /**
1667
+ * True when an external trigger (operator, scheduled task, MAIC
1668
+ * audit-driven recovery) has signalled that the NHE should return
1669
+ * from limbo. Overrides the idle-based logic.
1670
+ */
1671
+ externalReactivation: boolean;
1672
+ }
1673
+ interface LimboMachineThresholds {
1674
+ /**
1675
+ * Idle threshold (ms) for `awake → drifting`. Default 6h.
1676
+ */
1677
+ driftingMs?: number;
1678
+ /**
1679
+ * Idle threshold (ms) for `drifting → deep-coma`. Default 48h.
1680
+ * Entry 24 commits to a 48-72h range; 48h is the canonical default.
1681
+ */
1682
+ deepComaMs?: number;
1683
+ }
1684
+ type LimboMachineTransition = {
1685
+ kind: "stay";
1686
+ state: LimboState;
1687
+ reason: string;
1688
+ } | {
1689
+ kind: "transition";
1690
+ from: LimboState;
1691
+ to: LimboState;
1692
+ /** Audit-ready record matching @teleologyhi-sdk/maic LimboTransition. */
1693
+ transition: LimboTransition;
1694
+ reason: string;
1695
+ } | {
1696
+ kind: "return";
1697
+ from: LimboState;
1698
+ to: "awake";
1699
+ /** Audit-ready record matching @teleologyhi-sdk/maic LimboReturn. */
1700
+ ret: LimboReturn;
1701
+ reason: string;
1702
+ };
1703
+ /**
1704
+ * Evaluate the next state transition given the current state and the
1705
+ * runtime signals. Pure; deterministic from inputs.
1706
+ *
1707
+ * Transition table:
1708
+ *
1709
+ * awake + idleMs ≥ driftingMs → drifting
1710
+ * drifting + idleMs ≥ deepComaMs → deep-coma
1711
+ * drifting + idleMs < driftingMs → awake (user came back)
1712
+ * deep-coma + externalReactivation → returning (start return)
1713
+ * returning + (always) → awake (emit reunion)
1714
+ * else → stay
1715
+ *
1716
+ * `now` is supplied for deterministic testing; defaults to `Date.now()`.
1717
+ * `enteredAtIso` is required when the current state is not `awake` so
1718
+ * the LimboReturn record can compute `elapsedMs` correctly.
1719
+ */
1720
+ declare function evaluateLimboTransition(currentState: LimboState, input: LimboMachineInput, thresholds?: LimboMachineThresholds, enteredAtIso?: string, now?: number): LimboMachineTransition;
1721
+ /**
1722
+ * Build a maic-compatible `LimboTransition` record. Pure helper; the
1723
+ * caller decides when to emit it through the audit chain.
1724
+ */
1725
+ declare function mkLimboTransition(state: LimboState, reason: LimboTransition["reason"], now?: number): LimboTransition;
1726
+
1727
+ /**
1728
+ * Default-mode-network region (Entry 24 — limbo state machine).
1729
+ *
1730
+ * Ships the ownership descriptor + the limbo state machine
1731
+ * (`src/brain/default-mode-network/limbo-state.ts`, J-N9). Entry into
1732
+ * deep-coma costs zero compute by design — the NHE simply stops
1733
+ * scheduling work. Return from limbo emits the `reunion` affect (the
1734
+ * ninth canonical affect introduced by `@teleologyhi-sdk/maic`).
1735
+ *
1736
+ * Ownership: `nhe-body-owned`. The limbo machine is bound to this
1737
+ * incarnation; on `return-from-limbo` the HIM persists and the body
1738
+ * resumes scheduling. On unrecoverable deep-coma the operator may
1739
+ * choose to reincarnate the HIM into a new body via
1740
+ * `@teleologyhi-sdk/maic`'s `reincarnateHim` API (see
1741
+ * `@teleologyhi-sdk/him`'s `reincarnate({ lifecycle: "return-from-limbo" })`).
1742
+ */
1743
+
1744
+ declare const defaultModeNetwork: BrainRegion;
1745
+
1746
+ /**
1747
+ * BrainRegion module aggregate (J-N4 — Entries 22 + 24).
1748
+ *
1749
+ * Single-import access to all seven region descriptors plus the
1750
+ * limbo state machine. Each descriptor carries its `ownership`
1751
+ * marker so downstream tooling can reason about the
1752
+ * him-owned / nhe-body-owned split without hard-coding the map.
1753
+ */
1754
+
1755
+ /** All seven canonical brain regions in declaration order. */
1756
+ declare const BRAIN_REGIONS: readonly BrainRegion[];
1757
+
1758
+ declare function getTracer(): _opentelemetry_api.Tracer;
1759
+ /**
1760
+ * Wrap an async function in a span. The span ends when the inner promise
1761
+ * settles, and an error sets the span status to ERROR + records the
1762
+ * exception for the exporter.
1763
+ */
1764
+ declare function withSpan<T>(name: string, fn: (span: Span) => Promise<T>, attrs?: Record<string, string | number | boolean>): Promise<T>;
1765
+
1766
+ declare const respondCount: _opentelemetry_api.Counter<_opentelemetry_api.Attributes>;
1767
+ declare const respondRefusedCount: _opentelemetry_api.Counter<_opentelemetry_api.Attributes>;
1768
+ declare const tokensHistogram: _opentelemetry_api.Histogram<_opentelemetry_api.Attributes>;
1769
+ declare const sleepCyclesCount: _opentelemetry_api.Counter<_opentelemetry_api.Attributes>;
1770
+ declare const sleepDreamsCount: _opentelemetry_api.Counter<_opentelemetry_api.Attributes>;
1771
+ /**
1772
+ * Helper: increment `respondCount` and `tokensHistogram` for one respond call.
1773
+ */
1774
+ declare function recordRespond(args: {
1775
+ kind: "ok" | "redirect" | "refused";
1776
+ adapter: string;
1777
+ lifecycle: string;
1778
+ tokensIn: number;
1779
+ tokensOut: number;
1780
+ }): void;
1781
+
1782
+ /** Serialize a DreamRecord to YAML. Validates input via zod first. */
1783
+ declare function dreamRecordToYaml(record: DreamRecord): string;
1784
+ /** Parse and validate YAML into a DreamRecord. Throws on schema mismatch. */
1785
+ declare function dreamRecordFromYaml(text: string): DreamRecord;
1786
+ /**
1787
+ * Filename convention for sleep YAML: `<YYYY-MM-DD>_<HHmm>_dur<minutes>.yaml`.
1788
+ * Times are interpreted in UTC.
1789
+ */
1790
+ declare function sleepYamlFilename(startedAt: string, durationMinutes: number): string;
1791
+
1792
+ /** Convert recent interactions to a compact "fragments" list for N1. */
1793
+ declare function interactionsToFragments(items: readonly InteractionRecord[]): string[];
1794
+ /**
1795
+ * One-sentence summary the LLM is asked to produce per NREM phase. Distinct
1796
+ * from `Dream` (which is REM narrative) — these are compressions of the day's
1797
+ * substrate that REM then weaves dreams around.
1798
+ */
1799
+ type NremPhase = "N2" | "N3" | "N4";
1800
+ declare function buildNremPrompt(phase: NremPhase, fragments: string[]): {
1801
+ system: string;
1802
+ user: string;
1803
+ };
1804
+ /**
1805
+ * Run N2/N3/N4 in parallel against the LLM. Each call produces a one-sentence
1806
+ * summary; failures yield empty strings rather than aborting the cycle so a
1807
+ * flaky provider can't block sleep entirely.
1808
+ */
1809
+ declare function generateNremSummaries(llm: LlmAdapter, fragments: string[]): Promise<{
1810
+ n2: string;
1811
+ n3: string;
1812
+ n4: string;
1813
+ tokensIn: number;
1814
+ tokensOut: number;
1815
+ }>;
1816
+ /**
1817
+ * Build the REM-phase prompt. The LLM is asked to produce 1-3 narrative
1818
+ * paragraphs, each followed by `TELEOLOGICAL_VALUE: 0.NN` on its own line.
1819
+ * When provided, the NREM summaries are appended so REM can weave them in.
1820
+ */
1821
+ declare function buildRemPrompt(fragments: string[], induction?: {
1822
+ scenario: string;
1823
+ desiredLearning: string;
1824
+ inducedBy: "maic" | "creator";
1825
+ }, nrem?: {
1826
+ n2: string;
1827
+ n3: string;
1828
+ n4: string;
1829
+ }): {
1830
+ system: string;
1831
+ user: string;
1832
+ };
1833
+ /** Parse the LLM REM output into individual dreams. */
1834
+ declare function parseRemOutput(text: string, induced: boolean, inducedBy: "maic" | "creator" | null): Dream[];
1835
+ /**
1836
+ * Call the LLM with the REM prompt and parse the response into dreams.
1837
+ * Returns an empty array on no parseable output (treated as a quiet REM).
1838
+ */
1839
+ declare function generateRemDreams(llm: LlmAdapter, fragments: string[], induction?: {
1840
+ scenario: string;
1841
+ desiredLearning: string;
1842
+ inducedBy: "maic" | "creator";
1843
+ }, nrem?: {
1844
+ n2: string;
1845
+ n3: string;
1846
+ n4: string;
1847
+ }): Promise<{
1848
+ dreams: Dream[];
1849
+ tokensIn: number;
1850
+ tokensOut: number;
1851
+ }>;
1852
+
1853
+ /**
1854
+ * BM25 — Okapi BM25 ranking, dependency-free (D-N3 step 1).
1855
+ *
1856
+ * The previous `recallFromTemporalLobe` used a raw keyword count. That ranked
1857
+ * documents by how often a query token appeared, with no normalisation for
1858
+ * document length or term rarity. BM25 fixes both:
1859
+ *
1860
+ * - **Document length normalisation** (b parameter) penalises long documents
1861
+ * that just happen to contain a query term many times.
1862
+ * - **Term saturation** (k1 parameter) caps the marginal benefit of repeating
1863
+ * the same term.
1864
+ * - **Inverse document frequency** weights rare terms more than common ones.
1865
+ *
1866
+ * This is a single-pass IR algorithm with no external dependencies.
1867
+ * Performance: O(N) per query over the corpus. Fine up to ~10k documents on
1868
+ * a laptop. For larger corpora the embedder hook (see ./recall.ts) plugs in
1869
+ * a sentence-transformer + an ANN index.
1870
+ *
1871
+ * Defaults: k1=1.5, b=0.75 — the canonical Okapi values used by Elasticsearch
1872
+ * and Lucene. Override for domain-specific tuning.
1873
+ */
1874
+ interface Bm25Document {
1875
+ /** Stable id used to dedup/keep ordering predictable. */
1876
+ id: string;
1877
+ /** The text to score against the query. */
1878
+ text: string;
1879
+ }
1880
+ interface Bm25Result<T extends Bm25Document> {
1881
+ doc: T;
1882
+ score: number;
1883
+ }
1884
+ interface Bm25Options {
1885
+ /** Term frequency saturation. Default 1.5. */
1886
+ k1?: number;
1887
+ /** Document-length normalisation. Default 0.75. */
1888
+ b?: number;
1889
+ }
1890
+ /**
1891
+ * Score `docs` against `query` and return them sorted by descending BM25.
1892
+ * Zero-score documents are dropped so callers can rely on the result length.
1893
+ */
1894
+ declare function bm25<T extends Bm25Document>(query: string, docs: readonly T[], opts?: Bm25Options): Bm25Result<T>[];
1895
+ /**
1896
+ * Default tokenizer: lowercase + split on non-word characters + drop short
1897
+ * tokens. Exported so callers can build their own corpus for the same
1898
+ * scorer.
1899
+ */
1900
+ declare function tokenise(text: string): string[];
1901
+
1902
+ export { type AffectAdjustableConfig, AnthropicAdapter, type AnthropicAdapterConfig, type ApplyAffectResult, BRAIN_REGIONS, type Bm25Document, type Bm25Options, type Bm25Result, type BrainRegion, type BrainRegionName, type BrainRegionOwnership, ChatMessage, ChatMessageRole, type ClassificationThresholds, type ConsolidationResult, type CotOptions, CryptoSeedingSource, DeepSeekAdapter, type DeepSeekAdapterConfig, Dream, DreamRecord, GeminiAdapter, type GeminiAdapterConfig, type GenerateRequest, type GenerateResponse, GrokAdapter, type GrokAdapterConfig, INTL_RISK_CLASSIFIER_LANGUAGES, type LimboMachineInput, type LimboMachineThresholds, type LimboMachineTransition, type LlmAdapter, MemoryClass, type MemoryEntry, MistralAdapter, type MistralAdapterConfig, MockAdapter, type MockAdapterConfig, Nhe, type NheConfig, type NremPhase, OllamaAdapter, type OllamaAdapterConfig, type OperatorContext, PERSUASION_TECHNIQUES, type PersuasionTechnique, PhaseContent, type ReActOptions, type ReActTool, type ReActToolRegistry, type ReasoningResult, type ReasoningStrategy, type RecallEmbedder, type RecallOptions, type RedirectPromptInput, type ReflexionOptions, RespondInput, type RespondKind, type RespondOutput, type RiskClassifier, type SeedingChain, type SeedingSource, type SelfConsistencyOptions, type SelfRefineOptions, type SleepCycleInput, type SleepCycleOptions, type SleepCycleResult, SleepPhase, SleepPhaseName, type SleepReadinessInput, type SleepReadinessReport, type SleepReadinessThresholds, type SleepReadinessVerdict, type SleepTrigger, SleepTriggerKind, type StepBackOptions, type StreamEvent, TECHNIQUE_DESCRIPTIONS, TRAUMATIC_PATTERNS, type ToolDef, type ToolUse, type TreeOfThoughtsOptions, affectRefusalDensity, amygdala, applyAffectBias, bm25, buildNremPrompt, buildRedirectPrompt, buildRemPrompt, chainOfThought, classifyDream, collectStream, combineRiskClassifiers, composeSystemPrompt, consolidateAll, cortex, decayAffectBias, defaultModeNetwork, dreamRecordFromYaml, dreamRecordToYaml, evaluateLimboTransition, evaluateSleepReadiness, extractPrinciple, generateNremSummaries, generateRemDreams, getTracer, hippocampus, interactionsToFragments, intlRiskClassifier, makeStep, mkLimboTransition, parseCotOutput, parseReActTurn, parseRemOutput, parseVerdict, passthrough, pickTechnique, pineal, prefrontal, reAct, recallFromTemporalLobe, recordRespond, reflexion, respondCount, respondRefusedCount, runSleepCycle, selfConsistency, selfRefine, simpleRiskClassifier, sleepCyclesCount, sleepDreamsCount, sleepYamlFilename, stepBack, temporalLobe, tokenise, tokensHistogram, treeOfThoughts, withFallback, withSpan };