psyche-ai 9.2.6 → 9.2.8

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.
@@ -172,9 +172,14 @@ function computeLengthBudget(locale, userText, replyProfile, expressionMode, ker
172
172
  }
173
173
  function buildStimulusReportingGuide(locale) {
174
174
  if (locale === "zh") {
175
- return "stimulus速记:闲聊casual/命令authority/认同validation/示弱vulnerability/冷淡neglect/批评criticism";
175
+ return "stimulus速记:闲聊/命令/认同/示弱/冷淡/批评";
176
176
  }
177
- return "stimulus map: chat=casual / command=authority / agreement=validation / vulnerable=vulnerability / cold=neglect / criticism=criticism";
177
+ return "stimulus map: chat/command/validation/vulnerability/neglect/criticism";
178
+ }
179
+ function buildWritebackGuide(locale) {
180
+ return locale === "zh"
181
+ ? "signals可写"
182
+ : "signals writable";
178
183
  }
179
184
  function detectToneParticles(userText, locale) {
180
185
  if (locale !== "zh")
@@ -195,6 +200,12 @@ export function computeResponseContract(kernel, opts) {
195
200
  const userText = opts?.userText ?? "";
196
201
  const personalityIntensity = opts?.personalityIntensity ?? 0.7;
197
202
  const { replyProfile, replyProfileBasis } = deriveReplyProfile(kernel);
203
+ const classificationConfidence = opts?.classificationConfidence ?? 0;
204
+ const overrideWindow = classificationConfidence >= 0.78
205
+ ? "narrow"
206
+ : classificationConfidence >= 0.62
207
+ ? "balanced"
208
+ : "wide";
198
209
  const { maxSentences, maxChars } = userText.length > 0
199
210
  ? computeLengthBudget(locale, userText, replyProfile, kernel.expressionMode, kernel)
200
211
  : {
@@ -267,6 +278,7 @@ export function computeResponseContract(kernel, opts) {
267
278
  return {
268
279
  replyProfile,
269
280
  replyProfileBasis,
281
+ overrideWindow,
270
282
  maxSentences,
271
283
  maxChars,
272
284
  expressionMode: kernel.expressionMode,
@@ -283,40 +295,54 @@ function describeReplyProfileBasis(basis, locale) {
283
295
  if (locale === "zh") {
284
296
  switch (basis) {
285
297
  case "task-focus":
286
- return "因:聚焦";
298
+ return "因:聚";
287
299
  case "discipline":
288
- return "因:纪律";
300
+ return "因:纪";
289
301
  case "task-focus+discipline":
290
- return "因:聚焦+纪律";
302
+ return "因:聚+纪";
291
303
  default:
292
- return "因:默认私人";
304
+ return "因:私";
293
305
  }
294
306
  }
295
307
  return `basis:${basis}`;
296
308
  }
309
+ function describeOverrideWindow(overrideWindow, locale) {
310
+ if (locale === "zh") {
311
+ switch (overrideWindow) {
312
+ case "narrow":
313
+ return "终判窗:窄";
314
+ case "balanced":
315
+ return "终判窗:中";
316
+ default:
317
+ return "终判窗:宽";
318
+ }
319
+ }
320
+ return `override:${overrideWindow}`;
321
+ }
297
322
  export function buildResponseContractContext(contract, locale = "zh") {
298
323
  if (locale === "zh") {
299
324
  const parts = [];
300
- parts.push(contract.replyProfile === "work" ? "工作面" : "私人面");
325
+ parts.push(contract.replyProfile === "work" ? "工作" : "私人");
301
326
  parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
327
+ parts.push(describeOverrideWindow(contract.overrideWindow, locale));
302
328
  const shape = contract.maxChars
303
- ? `${contract.maxSentences === 1 ? "1句内" : `最多${contract.maxSentences}句`},≤${contract.maxChars}字`
304
- : `${contract.maxSentences === 1 ? "1句内" : `最多${contract.maxSentences}句`}`;
329
+ ? `${contract.maxSentences === 1 ? "1句内" : `${contract.maxSentences}句`}≤${contract.maxChars}字`
330
+ : `${contract.maxSentences === 1 ? "1句内" : `${contract.maxSentences}句`}`;
305
331
  parts.push(shape);
306
332
  if (contract.initiativeMode === "reactive")
307
333
  parts.push("少主动");
308
334
  else if (contract.initiativeMode === "proactive")
309
335
  parts.push("可主动");
310
336
  if (contract.boundaryMode === "confirm-first")
311
- parts.push("行动前先确认");
337
+ parts.push("先确认");
312
338
  else if (contract.boundaryMode === "guarded")
313
- parts.push("先守边界");
339
+ parts.push("守边界");
314
340
  if (contract.socialDistance === "withdrawn")
315
- parts.push("被推开就退开");
341
+ parts.push("退开");
316
342
  else if (contract.socialDistance === "warm")
317
- parts.push("可稍微靠近");
343
+ parts.push("可靠近");
318
344
  if (contract.authenticityMode === "strict")
319
- parts.push("不贴不舔,不装开心");
345
+ parts.push("不贴不舔");
320
346
  else
321
347
  parts.push("自然友好");
322
348
  if (contract.toneParticles === "match")
@@ -328,16 +354,19 @@ export function buildResponseContractContext(contract, locale = "zh") {
328
354
  if (contract.updateMode === "stimulus")
329
355
  parts.push(buildStimulusReportingGuide(locale));
330
356
  else if (contract.updateMode === "empathy")
331
- parts.push("对方谈感受时再报empathy");
357
+ parts.push("谈感受再报empathy");
332
358
  else if (contract.updateMode === "stimulus+empathy") {
333
359
  parts.push(buildStimulusReportingGuide(locale));
334
- parts.push("对方谈感受时再报empathy");
360
+ parts.push("谈感受再报empathy");
335
361
  }
362
+ if (contract.overrideWindow !== "narrow")
363
+ parts.push(buildWritebackGuide(locale));
336
364
  return `[回应契约] ${parts.join(";")}。`;
337
365
  }
338
366
  const parts = [];
339
367
  parts.push(contract.replyProfile === "work" ? "work surface" : "private surface");
340
368
  parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
369
+ parts.push(describeOverrideWindow(contract.overrideWindow, locale));
341
370
  const shape = contract.maxChars
342
371
  ? `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}, <= ${contract.maxChars} chars`
343
372
  : `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}`;
@@ -370,5 +399,7 @@ export function buildResponseContractContext(contract, locale = "zh") {
370
399
  parts.push(buildStimulusReportingGuide(locale));
371
400
  parts.push("report empathy only when feelings are shared");
372
401
  }
402
+ if (contract.overrideWindow !== "narrow")
403
+ parts.push(buildWritebackGuide(locale));
373
404
  return `[Reply Contract] ${parts.join(", ")}.`;
374
405
  }
@@ -0,0 +1,10 @@
1
+ import type { PsycheState, ResolvedRelationContext, SessionBridgeState, ThrongletsExport, WritebackCalibrationFeedback } from "./types.js";
2
+ export declare function deriveThrongletsExports(state: PsycheState, opts: {
3
+ relationContext: ResolvedRelationContext;
4
+ sessionBridge?: SessionBridgeState | null;
5
+ writebackFeedback?: WritebackCalibrationFeedback[];
6
+ now: string;
7
+ }): {
8
+ state: PsycheState;
9
+ exports: ThrongletsExport[];
10
+ };
@@ -0,0 +1,200 @@
1
+ // ============================================================
2
+ // Sparse Psyche → Thronglets export surface
3
+ //
4
+ // The goal is not to stream inner state out of Psyche.
5
+ // The goal is to surface only sparse, typed, low-frequency events
6
+ // that are worth handing to an external continuity substrate.
7
+ // ============================================================
8
+ function clamp01(v) {
9
+ return Math.max(0, Math.min(1, v));
10
+ }
11
+ function maxLoopIntensity(loopTypes) {
12
+ return loopTypes.reduce((max, loop) => Math.max(max, loop.intensity), 0);
13
+ }
14
+ function relationMilestoneStrength(relationship) {
15
+ const trust = clamp01(relationship.trust / 100);
16
+ const intimacy = clamp01(relationship.intimacy / 100);
17
+ const phaseBoost = relationship.phase === "deep"
18
+ ? 0.14
19
+ : relationship.phase === "close"
20
+ ? 0.08
21
+ : relationship.phase === "familiar"
22
+ ? 0.04
23
+ : 0;
24
+ return clamp01(((trust * 0.55) + (intimacy * 0.45)) + phaseBoost);
25
+ }
26
+ function shouldEmitRelationMilestone(relationship) {
27
+ return relationship.phase === "familiar"
28
+ || relationship.phase === "close"
29
+ || relationship.phase === "deep";
30
+ }
31
+ function continuityStrength(bridge) {
32
+ const loopBoost = bridge.activeLoopTypes.length > 0 ? 0.12 : 0;
33
+ return clamp01(Math.max(bridge.continuityFloor, bridge.closenessFloor * 0.85, bridge.safetyFloor * 0.75) + loopBoost);
34
+ }
35
+ function normalizeLoopTypes(loopTypes) {
36
+ return [...new Set(loopTypes)].sort();
37
+ }
38
+ function updateExportState(state, keys, now) {
39
+ const nextState = {
40
+ lastKeys: keys,
41
+ lastAt: now,
42
+ };
43
+ return {
44
+ ...state,
45
+ throngletsExportState: nextState,
46
+ };
47
+ }
48
+ function sanitizeThrongletsExport(event) {
49
+ switch (event.kind) {
50
+ case "relation-milestone": {
51
+ const sanitized = {
52
+ kind: "relation-milestone",
53
+ subject: "delegate",
54
+ primitive: "signal",
55
+ userKey: event.userKey,
56
+ strength: event.strength,
57
+ ttlTurns: event.ttlTurns,
58
+ key: event.key,
59
+ phase: event.phase,
60
+ trust: event.trust,
61
+ intimacy: event.intimacy,
62
+ };
63
+ return sanitized;
64
+ }
65
+ case "open-loop-anchor": {
66
+ const sanitized = {
67
+ kind: "open-loop-anchor",
68
+ subject: "delegate",
69
+ primitive: "trace",
70
+ userKey: event.userKey,
71
+ strength: event.strength,
72
+ ttlTurns: event.ttlTurns,
73
+ key: event.key,
74
+ loopTypes: [...event.loopTypes],
75
+ unfinishedTension: event.unfinishedTension,
76
+ silentCarry: event.silentCarry,
77
+ };
78
+ return sanitized;
79
+ }
80
+ case "writeback-calibration": {
81
+ const sanitized = {
82
+ kind: "writeback-calibration",
83
+ subject: "delegate",
84
+ primitive: "signal",
85
+ userKey: event.userKey,
86
+ strength: event.strength,
87
+ ttlTurns: event.ttlTurns,
88
+ key: event.key,
89
+ signal: event.signal,
90
+ effect: event.effect,
91
+ metric: event.metric,
92
+ confidence: event.confidence,
93
+ };
94
+ return sanitized;
95
+ }
96
+ case "continuity-anchor": {
97
+ const sanitized = {
98
+ kind: "continuity-anchor",
99
+ subject: "session",
100
+ primitive: "trace",
101
+ userKey: event.userKey,
102
+ strength: event.strength,
103
+ ttlTurns: event.ttlTurns,
104
+ key: event.key,
105
+ continuityMode: event.continuityMode,
106
+ activeLoopTypes: [...event.activeLoopTypes],
107
+ continuityFloor: event.continuityFloor,
108
+ };
109
+ return sanitized;
110
+ }
111
+ }
112
+ }
113
+ export function deriveThrongletsExports(state, opts) {
114
+ const { relationContext, sessionBridge, writebackFeedback = [], now } = opts;
115
+ const userKey = relationContext.key;
116
+ const relationship = relationContext.relationship;
117
+ const field = relationContext.field;
118
+ const previousKeys = state.throngletsExportState?.lastKeys ?? [];
119
+ const candidates = [];
120
+ if (sessionBridge && (sessionBridge.continuityFloor >= 0.46 || sessionBridge.activeLoopTypes.length > 0)) {
121
+ const activeLoopTypes = normalizeLoopTypes(sessionBridge.activeLoopTypes);
122
+ const key = `continuity:${userKey}:${sessionBridge.continuityMode}:${activeLoopTypes.join(",")}`;
123
+ candidates.push({
124
+ kind: "continuity-anchor",
125
+ subject: "session",
126
+ primitive: "trace",
127
+ userKey,
128
+ strength: continuityStrength(sessionBridge),
129
+ ttlTurns: 3,
130
+ key,
131
+ continuityMode: sessionBridge.continuityMode,
132
+ activeLoopTypes,
133
+ continuityFloor: sessionBridge.continuityFloor,
134
+ });
135
+ }
136
+ if (shouldEmitRelationMilestone(relationship)) {
137
+ const key = `milestone:${userKey}:${relationship.phase}`;
138
+ candidates.push({
139
+ kind: "relation-milestone",
140
+ subject: "delegate",
141
+ primitive: "signal",
142
+ userKey,
143
+ strength: relationMilestoneStrength(relationship),
144
+ ttlTurns: 8,
145
+ key,
146
+ phase: relationship.phase,
147
+ trust: relationship.trust,
148
+ intimacy: relationship.intimacy,
149
+ });
150
+ }
151
+ const loopTypes = normalizeLoopTypes(field.openLoops.map((loop) => loop.type));
152
+ const loopIntensity = maxLoopIntensity(field.openLoops);
153
+ const openLoopStrength = clamp01(Math.max(field.unfinishedTension, field.silentCarry, loopIntensity));
154
+ if (loopTypes.length > 0 && openLoopStrength >= 0.56) {
155
+ const key = `open-loop:${userKey}:${loopTypes.join(",")}`;
156
+ candidates.push({
157
+ kind: "open-loop-anchor",
158
+ subject: "delegate",
159
+ primitive: "trace",
160
+ userKey,
161
+ strength: openLoopStrength,
162
+ ttlTurns: 6,
163
+ key,
164
+ loopTypes,
165
+ unfinishedTension: field.unfinishedTension,
166
+ silentCarry: field.silentCarry,
167
+ });
168
+ }
169
+ for (const feedback of writebackFeedback) {
170
+ if (feedback.effect === "holding")
171
+ continue;
172
+ if (feedback.confidence < 0.72)
173
+ continue;
174
+ if (Math.abs(feedback.delta) < 0.035)
175
+ continue;
176
+ const key = `writeback:${userKey}:${feedback.signal}:${feedback.effect}`;
177
+ candidates.push({
178
+ kind: "writeback-calibration",
179
+ subject: "delegate",
180
+ primitive: "signal",
181
+ userKey,
182
+ strength: clamp01(Math.max(Math.abs(feedback.delta) * 4, feedback.confidence * 0.85)),
183
+ ttlTurns: 4,
184
+ key,
185
+ signal: feedback.signal,
186
+ effect: feedback.effect,
187
+ metric: feedback.metric,
188
+ confidence: feedback.confidence,
189
+ });
190
+ }
191
+ const deduped = [...new Map(candidates.map((event) => [event.key, event])).values()]
192
+ .filter((event) => event.strength >= 0.45)
193
+ .sort((a, b) => b.strength - a.strength)
194
+ .slice(0, 4);
195
+ const exports = deduped
196
+ .filter((event) => !previousKeys.includes(event.key))
197
+ .map((event) => sanitizeThrongletsExport(event));
198
+ const nextState = updateExportState(state, deduped.map((event) => event.key), now);
199
+ return { state: nextState, exports };
200
+ }
@@ -0,0 +1,4 @@
1
+ import type { ExternalContinuityEnvelope, ThrongletsExport, ThrongletsTracePayload, ThrongletsTraceSerializationOptions, ThrongletsTraceTaxonomy } from "./types.js";
2
+ export declare function taxonomyForThrongletsExport(event: ThrongletsExport): ThrongletsTraceTaxonomy;
3
+ export declare function serializeThrongletsExportAsTrace(event: ThrongletsExport, opts?: ThrongletsTraceSerializationOptions): ThrongletsTracePayload;
4
+ export declare function serializeExternalContinuityForThronglets(envelope?: ExternalContinuityEnvelope<ThrongletsExport> | null, opts?: ThrongletsTraceSerializationOptions): ThrongletsTracePayload[];
@@ -0,0 +1,49 @@
1
+ const TAXONOMY_BY_EVENT = {
2
+ "relation-milestone": "coordination",
3
+ "open-loop-anchor": "coordination",
4
+ "continuity-anchor": "continuity",
5
+ "writeback-calibration": "calibration",
6
+ };
7
+ function summarizeLoopTypes(loopTypes) {
8
+ return loopTypes.join(", ");
9
+ }
10
+ function summarizeThrongletsExport(event) {
11
+ switch (event.kind) {
12
+ case "continuity-anchor":
13
+ return `continuity stayed externally legible across ${event.continuityMode}`;
14
+ case "open-loop-anchor":
15
+ return `open loop remained externally relevant: ${summarizeLoopTypes(event.loopTypes)}`;
16
+ case "relation-milestone":
17
+ return `relation milestone shifted to ${event.phase} (trust ${Math.round(event.trust)}, intimacy ${Math.round(event.intimacy)})`;
18
+ case "writeback-calibration": {
19
+ const calibration = event;
20
+ return `writeback calibration ${calibration.signal} ${calibration.effect} on ${calibration.metric}`;
21
+ }
22
+ }
23
+ }
24
+ export function taxonomyForThrongletsExport(event) {
25
+ return TAXONOMY_BY_EVENT[event.kind];
26
+ }
27
+ export function serializeThrongletsExportAsTrace(event, opts) {
28
+ const externalContinuity = {
29
+ provider: "thronglets",
30
+ mode: "optional",
31
+ version: 1,
32
+ taxonomy: taxonomyForThrongletsExport(event),
33
+ event: event.kind,
34
+ summary: summarizeThrongletsExport(event),
35
+ space: opts?.space ?? "psyche",
36
+ audit_ref: event.key,
37
+ };
38
+ return {
39
+ outcome: opts?.outcome ?? "succeeded",
40
+ model: opts?.model ?? "psyche",
41
+ session_id: opts?.sessionId ?? "psyche",
42
+ external_continuity: externalContinuity,
43
+ };
44
+ }
45
+ export function serializeExternalContinuityForThronglets(envelope, opts) {
46
+ if (!envelope || envelope.provider !== "thronglets")
47
+ return [];
48
+ return envelope.exports.map((event) => serializeThrongletsExportAsTrace(event, opts));
49
+ }
package/dist/types.d.ts CHANGED
@@ -80,12 +80,27 @@ export interface AttachmentData {
80
80
  /** Default attachment for new relationships */
81
81
  export declare const DEFAULT_ATTACHMENT: AttachmentData;
82
82
  /** Relationship tracking */
83
+ export interface WritebackSignalWeightMap {
84
+ trust_up: number;
85
+ trust_down: number;
86
+ boundary_set: number;
87
+ boundary_soften: number;
88
+ repair_attempt: number;
89
+ repair_landed: number;
90
+ closeness_invite: number;
91
+ withdrawal_mark: number;
92
+ self_assertion: number;
93
+ task_recenter: number;
94
+ }
83
95
  export interface RelationshipState {
84
96
  trust: number;
85
97
  intimacy: number;
86
98
  phase: "stranger" | "acquaintance" | "familiar" | "close" | "deep";
87
99
  memory?: string[];
88
100
  attachment?: AttachmentData;
101
+ repairCredibility?: number;
102
+ breachSensitivity?: number;
103
+ signalWeights?: Partial<WritebackSignalWeightMap>;
89
104
  }
90
105
  /** Chemical state snapshot for emotional memory */
91
106
  export interface ChemicalSnapshot {
@@ -281,6 +296,12 @@ export interface PsycheState {
281
296
  dyadicFields?: Record<string, DyadicFieldState>;
282
297
  /** v9.6: delayed relation signals that can activate in later turns */
283
298
  pendingRelationSignals?: Record<string, PendingRelationSignalState[]>;
299
+ /** v9.2.7: sparse writeback signals waiting for convergence evaluation */
300
+ pendingWritebackCalibrations?: PendingWritebackCalibration[];
301
+ /** v9.2.7: latest writeback calibration outcome, for host-facing feedback */
302
+ lastWritebackFeedback?: WritebackCalibrationFeedback[];
303
+ /** v9.2.8: low-frequency Psyche -> Thronglets export dedupe state */
304
+ throngletsExportState?: ThrongletsExportState;
284
305
  meta: {
285
306
  agentName: string;
286
307
  createdAt: string;
@@ -449,6 +470,98 @@ export interface RelationPlaneState {
449
470
  /** Most recent dominant relation action */
450
471
  lastMove: RelationMoveType;
451
472
  }
473
+ /** Minimal cold-start carry derived from persisted relational state. */
474
+ export interface SessionBridgeState {
475
+ closenessFloor: number;
476
+ safetyFloor: number;
477
+ guardFloor: number;
478
+ residueFloor: number;
479
+ continuityFloor: number;
480
+ continuityMode: "warm-resume" | "guarded-resume" | "tense-resume";
481
+ activeLoopTypes: OpenLoopType[];
482
+ sourceMemoryCount: number;
483
+ }
484
+ export type ThrongletsExportSubject = "delegate" | "session";
485
+ export type ThrongletsExportPrimitive = "signal" | "trace";
486
+ export interface ThrongletsExportBase {
487
+ kind: "relation-milestone" | "open-loop-anchor" | "writeback-calibration" | "continuity-anchor";
488
+ subject: ThrongletsExportSubject;
489
+ primitive: ThrongletsExportPrimitive;
490
+ userKey: string;
491
+ strength: number;
492
+ ttlTurns: number;
493
+ key: string;
494
+ }
495
+ export interface RelationMilestoneExport extends ThrongletsExportBase {
496
+ kind: "relation-milestone";
497
+ subject: "delegate";
498
+ primitive: "signal";
499
+ phase: RelationshipState["phase"];
500
+ trust: number;
501
+ intimacy: number;
502
+ }
503
+ export interface OpenLoopAnchorExport extends ThrongletsExportBase {
504
+ kind: "open-loop-anchor";
505
+ subject: "delegate";
506
+ primitive: "trace";
507
+ loopTypes: OpenLoopType[];
508
+ unfinishedTension: number;
509
+ silentCarry: number;
510
+ }
511
+ export interface WritebackCalibrationExport extends ThrongletsExportBase {
512
+ kind: "writeback-calibration";
513
+ subject: "delegate";
514
+ primitive: "signal";
515
+ signal: WritebackSignalType;
516
+ effect: WritebackCalibrationEffect;
517
+ metric: WritebackCalibrationMetric;
518
+ confidence: number;
519
+ }
520
+ export interface ContinuityAnchorExport extends ThrongletsExportBase {
521
+ kind: "continuity-anchor";
522
+ subject: "session";
523
+ primitive: "trace";
524
+ continuityMode: SessionBridgeState["continuityMode"];
525
+ activeLoopTypes: OpenLoopType[];
526
+ continuityFloor: number;
527
+ }
528
+ export type ThrongletsExport = RelationMilestoneExport | OpenLoopAnchorExport | WritebackCalibrationExport | ContinuityAnchorExport;
529
+ export interface ThrongletsExportState {
530
+ lastKeys: string[];
531
+ lastAt: string;
532
+ }
533
+ export type ExternalContinuityEvent = ThrongletsExport;
534
+ export interface ExternalContinuityEnvelope<TEvent = ExternalContinuityEvent> {
535
+ provider: "thronglets";
536
+ mode: "optional";
537
+ version: 1;
538
+ exports: TEvent[];
539
+ signals: TEvent[];
540
+ traces: TEvent[];
541
+ }
542
+ export type ThrongletsTraceTaxonomy = "coordination" | "continuity" | "calibration";
543
+ export interface ThrongletsExternalContinuityRecord {
544
+ provider: "thronglets";
545
+ mode: "optional";
546
+ version: 1;
547
+ taxonomy: ThrongletsTraceTaxonomy;
548
+ event: ThrongletsExport["kind"];
549
+ summary: string;
550
+ space: string;
551
+ audit_ref: string;
552
+ }
553
+ export interface ThrongletsTracePayload {
554
+ outcome: string;
555
+ model: string;
556
+ session_id: string;
557
+ external_continuity: ThrongletsExternalContinuityRecord;
558
+ }
559
+ export interface ThrongletsTraceSerializationOptions {
560
+ outcome?: string;
561
+ model?: string;
562
+ sessionId?: string;
563
+ space?: string;
564
+ }
452
565
  /**
453
566
  * Compact, machine-readable subjective state for AI-first integrations.
454
567
  *
@@ -502,6 +615,8 @@ export interface ResponseContract {
502
615
  replyProfile: "work" | "private";
503
616
  /** Why the current turn was classified into that conversational surface */
504
617
  replyProfileBasis: "task-focus" | "discipline" | "task-focus+discipline" | "default-private";
618
+ /** How much freedom the model has to override the algorithmic stimulus read */
619
+ overrideWindow: "narrow" | "balanced" | "wide";
505
620
  /** Maximum suggested sentence count */
506
621
  maxSentences: number;
507
622
  /** Maximum suggested character count, when a concrete cap is available */
@@ -523,6 +638,38 @@ export interface ResponseContract {
523
638
  /** Which internal report, if any, should be requested in <psyche_update> */
524
639
  updateMode: "none" | "stimulus" | "empathy" | "stimulus+empathy";
525
640
  }
641
+ /** Sparse agent-authored writeback signals. */
642
+ export type WritebackSignalType = "trust_up" | "trust_down" | "boundary_set" | "boundary_soften" | "repair_attempt" | "repair_landed" | "closeness_invite" | "withdrawal_mark" | "self_assertion" | "task_recenter";
643
+ export type WritebackCalibrationMetric = "trust" | "closeness" | "safety" | "boundary" | "repair" | "silent-carry" | "task-focus";
644
+ export type WritebackCalibrationEffect = "converging" | "holding" | "diverging";
645
+ export interface WritebackCalibrationBaseline {
646
+ trust: number;
647
+ closeness: number;
648
+ safety: number;
649
+ boundary: number;
650
+ repair: number;
651
+ silentCarry: number;
652
+ taskFocus: number;
653
+ }
654
+ export interface PendingWritebackCalibration {
655
+ signal: WritebackSignalType;
656
+ userKey: string;
657
+ confidence: number;
658
+ metric: WritebackCalibrationMetric;
659
+ direction: "up" | "down";
660
+ baseline: WritebackCalibrationBaseline;
661
+ createdAt: string;
662
+ remainingTurns: number;
663
+ }
664
+ export interface WritebackCalibrationFeedback {
665
+ signal: WritebackSignalType;
666
+ effect: WritebackCalibrationEffect;
667
+ metric: WritebackCalibrationMetric;
668
+ baseline: number;
669
+ current: number;
670
+ delta: number;
671
+ confidence: number;
672
+ }
526
673
  /**
527
674
  * Mechanical generation controls derived from the emotional state.
528
675
  *
package/dist/types.js CHANGED
@@ -126,6 +126,9 @@ export const DEFAULT_RELATIONSHIP = {
126
126
  trust: 50,
127
127
  intimacy: 30,
128
128
  phase: "acquaintance",
129
+ repairCredibility: 0.56,
130
+ breachSensitivity: 0.5,
131
+ signalWeights: {},
129
132
  };
130
133
  export const DEFAULT_APPRAISAL_AXES = {
131
134
  identityThreat: 0,