@vincemakes/kiso-runtime 0.40.0 → 0.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.d.ts CHANGED
@@ -92,7 +92,12 @@ export declare class AgentRuntime {
92
92
  sessions(): import("./store.js").SessionMeta[];
93
93
  /** Release every held fd and writer lock (E group: the CLI closes on exit). */
94
94
  close(): void;
95
- /** Load an existing session from disk, or create a fresh one. */
95
+ /** Load an existing session from disk, or create a fresh one.
96
+ *
97
+ * `acceptDrift` is accepted and INERT — the CLI's historical
98
+ * `--accept-drift`, kept so the flag keeps parsing. Since the owner's
99
+ * ruling of 2026-09-21 a changed binding never needs an
100
+ * acknowledgement: the current configuration wins and is recorded. */
96
101
  session(options: {
97
102
  id: string;
98
103
  acceptDrift?: boolean;
package/dist/agent.js CHANGED
@@ -54,7 +54,12 @@ export class AgentRuntime {
54
54
  close() {
55
55
  this.#definition.store.closeAll();
56
56
  }
57
- /** Load an existing session from disk, or create a fresh one. */
57
+ /** Load an existing session from disk, or create a fresh one.
58
+ *
59
+ * `acceptDrift` is accepted and INERT — the CLI's historical
60
+ * `--accept-drift`, kept so the flag keeps parsing. Since the owner's
61
+ * ruling of 2026-09-21 a changed binding never needs an
62
+ * acknowledgement: the current configuration wins and is recorded. */
58
63
  async session(options) {
59
64
  const store = this.#definition.store;
60
65
  const records = store.load(options.id);
@@ -86,18 +91,26 @@ export class AgentRuntime {
86
91
  if (meta.kind === "ok") {
87
92
  const drift = assessProfileDrift(meta.profile, {
88
93
  provider: startupScope ?? null,
94
+ modelId: this.#definition.model,
89
95
  systemPromptDigest: candidate.systemPromptDigest,
90
96
  tools: candidate.tools,
91
97
  });
92
- if (drift.kind === "material" && options.acceptDrift !== true) {
93
- const listed = drift.reasons.map((r) => `- ${r}`).join("\n");
94
- throw new Error(`the recorded execution profile no longer matches this process:\n${listed}\nre-open with acceptDrift (the CLI's --accept-drift flag) to proceed under the CURRENT configuration — the acknowledgement is recorded as a new revision; silently rebuilding is forbidden`);
95
- }
96
98
  if (drift.kind === "material") {
97
- // acknowledged: the current configuration wins, DURABLY. The
98
- // reasoning resets to defaults (owner-ruled: the recorded effort
99
- // was a choice for the model that no longer answers) — and the
100
- // session says so, through `driftAcknowledgement`.
99
+ // 0.40.1 (the owner's ruling of 2026-09-21): a DIFFERENT BINDING
100
+ // never blocks. A person may simply have switched models, so the
101
+ // CURRENT configuration wins — DURABLY, as the next revision —
102
+ // and the session says so. It used to refuse without an explicit
103
+ // `acceptDrift`, which turned "I moved to another provider"
104
+ // into an error the resume could not pass at all.
105
+ //
106
+ // Nothing provider-specific crosses the change: every adapter
107
+ // withholds foreign reasoning/continuation (MG-1 A5), so a new
108
+ // binding loses cache state, never correctness. The reasoning
109
+ // resets to defaults (owner-ruled: the recorded effort was a
110
+ // choice for the model that no longer answers) — and the session
111
+ // says so through `driftAcknowledgement`. The field's NAME is
112
+ // history: nothing is acknowledged any more, the change is
113
+ // recorded and stated.
101
114
  driftAcknowledgement = { reasons: drift.reasons, reasoningReset: meta.profile.reasoning };
102
115
  writeProfile(store.root, options.id, {
103
116
  ...buildProfile({
package/dist/profile.d.ts CHANGED
@@ -109,8 +109,9 @@ export type ProfileDrift = {
109
109
  readonly kind: "compatible-additions";
110
110
  readonly added: readonly string[];
111
111
  }
112
- /** WHO ANSWERS changed — the one class that blocks without an
113
- * explicit acknowledgement. */
112
+ /** WHO ANSWERS changed — NAMED, and recorded as the next revision under
113
+ * the CURRENT configuration. Owner-ruled 2026-09-21: a changed binding
114
+ * never blocks a resume — the person may simply have switched models. */
114
115
  | {
115
116
  readonly kind: "material";
116
117
  readonly reasons: readonly string[];
@@ -119,10 +120,14 @@ export type ProfileDrift = {
119
120
  * never from digest inequality alone: every recorded tool present with
120
121
  * identical hashes plus new names = compatible additions (a one-line
121
122
  * notice); a missing name, a changed hash, a provider/model divergence,
122
- * or a system-prompt divergence = MATERIAL (explicit resolution; a
123
- * digest mismatch is never presented as restoration). */
123
+ * or a system-prompt divergence = MATERIAL (the change is NAMED and
124
+ * recorded as the next revision under the CURRENT configuration — it
125
+ * blocks nothing; a digest mismatch is never presented as restoration). */
124
126
  export declare function assessProfileDrift(recorded: ExecutionProfile, current: {
125
127
  readonly provider: ProfileModelRef | null;
128
+ /** The model THIS process would run — needed because an unscoped binding
129
+ * has no provider ref to carry it. */
130
+ readonly modelId: string;
126
131
  readonly systemPromptDigest: string;
127
132
  readonly tools: readonly ProfileToolRecord[];
128
133
  }): ProfileDrift;
package/dist/profile.js CHANGED
@@ -154,8 +154,9 @@ export function readProfile(root, sessionId) {
154
154
  * never from digest inequality alone: every recorded tool present with
155
155
  * identical hashes plus new names = compatible additions (a one-line
156
156
  * notice); a missing name, a changed hash, a provider/model divergence,
157
- * or a system-prompt divergence = MATERIAL (explicit resolution; a
158
- * digest mismatch is never presented as restoration). */
157
+ * or a system-prompt divergence = MATERIAL (the change is NAMED and
158
+ * recorded as the next revision under the CURRENT configuration — it
159
+ * blocks nothing; a digest mismatch is never presented as restoration). */
159
160
  export function assessProfileDrift(recorded, current) {
160
161
  const reasons = [];
161
162
  const notes = [];
@@ -164,8 +165,29 @@ export function assessProfileDrift(recorded, current) {
164
165
  if ((r === null) !== (c === null)) {
165
166
  reasons.push(`the recorded binding is ${r === null ? "unscoped" : `${r.providerId}/${r.modelId}`} but the current process serves ${c === null ? "an unscoped adapter" : `${c.providerId}/${c.modelId}`}`);
166
167
  }
167
- else if (r !== null && c !== null && r.providerId !== c.providerId) {
168
- reasons.push(`the recorded provider is ${r.providerId} but the current process serves ${c.providerId}`);
168
+ else if (r !== null && c !== null) {
169
+ // WHO ANSWERS is an identity, and `providerId` alone is not one:
170
+ // `custom` names a CLASS — two custom endpoints are two different
171
+ // places to spend — so an endpoint (or API flavour) that moved is a
172
+ // changed binding like any other. Found in review of this round.
173
+ if (r.providerId !== c.providerId)
174
+ reasons.push(`the recorded provider is ${r.providerId} but the current process serves ${c.providerId}`);
175
+ if (r.apiId !== c.apiId)
176
+ reasons.push(`the recorded API is ${r.apiId} but the current process serves ${c.apiId}`);
177
+ if ((r.endpoint ?? null) !== (c.endpoint ?? null))
178
+ reasons.push(`the recorded endpoint is ${r.endpoint ?? "(none)"} but the current process serves ${c.endpoint ?? "(none)"}`);
179
+ }
180
+ // THE MODEL TOO — the owner's ruling of 2026-09-21, taken on review: the
181
+ // CONFIGURATION wins, including a model switch inside one provider (`--model`
182
+ // and the config are never silently ignored on a resume). This is compared
183
+ // even when BOTH sides are unscoped, where there is no provider ref to carry
184
+ // it, and it covers the ref's own `modelId` as well (the same fact, stamped
185
+ // by the same builder).
186
+ if (r !== null && c !== null && (r.modelId !== c.modelId || recorded.modelId !== current.modelId)) {
187
+ reasons.push(`the recorded model is ${recorded.modelId} but the current process serves ${current.modelId}`);
188
+ }
189
+ else if (r === null && c === null && recorded.modelId !== current.modelId) {
190
+ reasons.push(`the recorded model is ${recorded.modelId} but the current process serves ${current.modelId} (both bindings are unscoped)`);
169
191
  }
170
192
  if (recorded.systemPromptDigest !== current.systemPromptDigest) {
171
193
  notes.push(`the composed system prompt differs from the recorded one (${recorded.systemPromptDigest.slice(0, 12)}… → ${current.systemPromptDigest.slice(0, 12)}…)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-runtime",
3
- "version": "0.40.0",
3
+ "version": "0.40.1",
4
4
  "description": "kiso runtime \u2014 durable multi-turn agent sessions: AgentDefinition, AgentRuntime, AgentSession, Run, append-only JSONL store.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,12 +25,12 @@
25
25
  "test": "vitest run"
26
26
  },
27
27
  "dependencies": {
28
- "@vincemakes/kiso-core": "0.40.0"
28
+ "@vincemakes/kiso-core": "0.40.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@vincemakes/kiso-provider-anthropic": "0.40.0",
32
- "@vincemakes/kiso-provider-openai": "0.40.0",
33
- "@vincemakes/kiso-provider-openai-responses": "0.40.0"
31
+ "@vincemakes/kiso-provider-anthropic": "0.40.1",
32
+ "@vincemakes/kiso-provider-openai": "0.40.1",
33
+ "@vincemakes/kiso-provider-openai-responses": "0.40.1"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@vincemakes/kiso-provider-anthropic": {
@@ -44,7 +44,7 @@
44
44
  }
45
45
  },
46
46
  "devDependencies": {
47
- "@vincemakes/kiso-evals": "0.40.0",
47
+ "@vincemakes/kiso-evals": "0.40.1",
48
48
  "@types/node": "^26.1.2",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^3.0.0"