@namzu/sdk 55.0.0 → 55.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/{manager/resident/learning-cycle.d.ts → learning/cycle.d.ts} +45 -36
- package/dist/learning/cycle.d.ts.map +1 -0
- package/dist/{manager/resident/learning-cycle.js → learning/cycle.js} +52 -20
- package/dist/learning/cycle.js.map +1 -0
- package/dist/learning/deprecated.d.ts +86 -0
- package/dist/learning/deprecated.d.ts.map +1 -0
- package/dist/learning/deprecated.js +22 -0
- package/dist/learning/deprecated.js.map +1 -0
- package/dist/learning/experience-store.d.ts +35 -0
- package/dist/learning/experience-store.d.ts.map +1 -0
- package/dist/learning/experience-store.js +143 -0
- package/dist/learning/experience-store.js.map +1 -0
- package/dist/learning/experience.d.ts +150 -0
- package/dist/learning/experience.d.ts.map +1 -0
- package/dist/learning/experience.js +146 -0
- package/dist/learning/experience.js.map +1 -0
- package/dist/learning/generator.d.ts +118 -0
- package/dist/learning/generator.d.ts.map +1 -0
- package/dist/learning/generator.js +275 -0
- package/dist/learning/generator.js.map +1 -0
- package/dist/learning/leak-tripwire.d.ts +66 -0
- package/dist/learning/leak-tripwire.d.ts.map +1 -0
- package/dist/learning/leak-tripwire.js +208 -0
- package/dist/learning/leak-tripwire.js.map +1 -0
- package/dist/{manager/resident/learning-observation.d.ts → learning/observation.d.ts} +4 -4
- package/dist/learning/observation.d.ts.map +1 -0
- package/dist/{manager/resident/learning-observation.js → learning/observation.js} +3 -3
- package/dist/learning/observation.js.map +1 -0
- package/dist/{manager/resident/learning.d.ts → learning/skill.d.ts} +29 -29
- package/dist/learning/skill.d.ts.map +1 -0
- package/dist/{manager/resident/learning.js → learning/skill.js} +27 -27
- package/dist/learning/skill.js.map +1 -0
- package/dist/{manager/resident/learning-store.d.ts → learning/store.d.ts} +38 -31
- package/dist/learning/store.d.ts.map +1 -0
- package/dist/{manager/resident/learning-store.js → learning/store.js} +52 -20
- package/dist/learning/store.js.map +1 -0
- package/dist/manager/resident/activity.d.ts +30 -6
- package/dist/manager/resident/activity.d.ts.map +1 -1
- package/dist/manager/resident/activity.js.map +1 -1
- package/dist/manager/resident/agenda.d.ts +42 -12
- package/dist/manager/resident/agenda.d.ts.map +1 -1
- package/dist/manager/resident/agenda.js +9 -7
- package/dist/manager/resident/agenda.js.map +1 -1
- package/dist/manager/resident/consumption.d.ts +27 -5
- package/dist/manager/resident/consumption.d.ts.map +1 -1
- package/dist/manager/resident/consumption.js +2 -0
- package/dist/manager/resident/consumption.js.map +1 -1
- package/dist/manager/resident/delivery-window.d.ts +7 -1
- package/dist/manager/resident/delivery-window.d.ts.map +1 -1
- package/dist/manager/resident/delivery-window.js +2 -0
- package/dist/manager/resident/delivery-window.js.map +1 -1
- package/dist/manager/resident/evidence-recall.d.ts +7 -1
- package/dist/manager/resident/evidence-recall.d.ts.map +1 -1
- package/dist/manager/resident/evidence-recall.js +2 -0
- package/dist/manager/resident/evidence-recall.js.map +1 -1
- package/dist/manager/resident/history.d.ts +45 -9
- package/dist/manager/resident/history.d.ts.map +1 -1
- package/dist/manager/resident/history.js.map +1 -1
- package/dist/manager/resident/host.d.ts +44 -10
- package/dist/manager/resident/host.d.ts.map +1 -1
- package/dist/manager/resident/host.js +4 -2
- package/dist/manager/resident/host.js.map +1 -1
- package/dist/manager/resident/initiative.d.ts +32 -6
- package/dist/manager/resident/initiative.d.ts.map +1 -1
- package/dist/manager/resident/initiative.js +2 -0
- package/dist/manager/resident/initiative.js.map +1 -1
- package/dist/manager/resident/loop.d.ts +22 -4
- package/dist/manager/resident/loop.d.ts.map +1 -1
- package/dist/manager/resident/loop.js +7 -1
- package/dist/manager/resident/loop.js.map +1 -1
- package/dist/manager/resident/outbox.d.ts +42 -8
- package/dist/manager/resident/outbox.d.ts.map +1 -1
- package/dist/manager/resident/outbox.js +2 -0
- package/dist/manager/resident/outbox.js.map +1 -1
- package/dist/manager/resident/proposal.d.ts +17 -3
- package/dist/manager/resident/proposal.d.ts.map +1 -1
- package/dist/manager/resident/proposal.js +2 -0
- package/dist/manager/resident/proposal.js.map +1 -1
- package/dist/manager/resident/store.d.ts +27 -5
- package/dist/manager/resident/store.d.ts.map +1 -1
- package/dist/manager/resident/store.js +7 -1
- package/dist/manager/resident/store.js.map +1 -1
- package/dist/manager/resident/tool-evidence.d.ts +45 -9
- package/dist/manager/resident/tool-evidence.d.ts.map +1 -1
- package/dist/manager/resident/tool-evidence.js +5 -1
- package/dist/manager/resident/tool-evidence.js.map +1 -1
- package/dist/prompt/resident-learning.d.ts +12 -2
- package/dist/prompt/resident-learning.d.ts.map +1 -1
- package/dist/prompt/resident-learning.js +6 -5
- package/dist/prompt/resident-learning.js.map +1 -1
- package/dist/prompt/resident-step.d.ts +10 -4
- package/dist/prompt/resident-step.d.ts.map +1 -1
- package/dist/prompt/resident-step.js +6 -4
- package/dist/prompt/resident-step.js.map +1 -1
- package/dist/public-runtime.d.ts +9 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +10 -3
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +9 -4
- package/dist/public-types.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/per-call-review.d.ts +9 -0
- package/dist/runtime/query/iteration/phases/per-call-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/per-call-review.js +19 -0
- package/dist/runtime/query/iteration/phases/per-call-review.js.map +1 -1
- package/dist/tools/resident-history.d.ts +2 -0
- package/dist/tools/resident-history.d.ts.map +1 -1
- package/dist/tools/resident-history.js +2 -0
- package/dist/tools/resident-history.js.map +1 -1
- package/dist/tools/resident-tool-evidence.d.ts +5 -1
- package/dist/tools/resident-tool-evidence.d.ts.map +1 -1
- package/dist/tools/resident-tool-evidence.js +5 -1
- package/dist/tools/resident-tool-evidence.js.map +1 -1
- package/package.json +1 -1
- package/src/{manager/resident/learning-cycle.ts → learning/cycle.ts} +130 -78
- package/src/learning/deprecated.ts +124 -0
- package/src/learning/experience-store.ts +202 -0
- package/src/learning/experience.ts +238 -0
- package/src/learning/generator.ts +388 -0
- package/src/learning/leak-tripwire.ts +280 -0
- package/src/{manager/resident/learning-observation.ts → learning/observation.ts} +5 -5
- package/src/{manager/resident/learning.ts → learning/skill.ts} +64 -67
- package/src/{manager/resident/learning-store.ts → learning/store.ts} +97 -67
- package/src/manager/resident/activity.ts +30 -6
- package/src/manager/resident/agenda.ts +63 -33
- package/src/manager/resident/consumption.ts +27 -5
- package/src/manager/resident/delivery-window.ts +7 -1
- package/src/manager/resident/evidence-recall.ts +7 -1
- package/src/manager/resident/history.ts +45 -9
- package/src/manager/resident/host.ts +45 -11
- package/src/manager/resident/initiative.ts +32 -6
- package/src/manager/resident/loop.ts +22 -4
- package/src/manager/resident/outbox.ts +42 -8
- package/src/manager/resident/proposal.ts +17 -3
- package/src/manager/resident/store.ts +27 -5
- package/src/manager/resident/tool-evidence.ts +45 -9
- package/src/prompt/resident-learning.ts +16 -7
- package/src/prompt/resident-step.ts +19 -13
- package/src/public-runtime.ts +35 -5
- package/src/public-types.ts +96 -34
- package/src/runtime/query/iteration/phases/per-call-review.ts +19 -0
- package/src/tools/resident-history.ts +2 -0
- package/src/tools/resident-tool-evidence.ts +5 -1
- package/dist/manager/resident/learning-cycle.d.ts.map +0 -1
- package/dist/manager/resident/learning-cycle.js.map +0 -1
- package/dist/manager/resident/learning-observation.d.ts.map +0 -1
- package/dist/manager/resident/learning-observation.js.map +0 -1
- package/dist/manager/resident/learning-store.d.ts.map +0 -1
- package/dist/manager/resident/learning-store.js.map +0 -1
- package/dist/manager/resident/learning.d.ts.map +0 -1
- package/dist/manager/resident/learning.js.map +0 -1
|
@@ -15,22 +15,22 @@ import { createRequire } from 'node:module'
|
|
|
15
15
|
import { dirname, join, resolve } from 'node:path'
|
|
16
16
|
import type { DatabaseSync } from 'node:sqlite'
|
|
17
17
|
import { z } from 'zod'
|
|
18
|
-
import type { ProjectId, TenantId } from '
|
|
19
|
-
import { asProjectId, asTenantId } from '
|
|
18
|
+
import type { ProjectId, TenantId } from '../types/ids/index.js'
|
|
19
|
+
import { asProjectId, asTenantId } from '../utils/id.js'
|
|
20
20
|
import {
|
|
21
|
-
type
|
|
22
|
-
type
|
|
23
|
-
type
|
|
24
|
-
|
|
25
|
-
} from './
|
|
21
|
+
type LearningCycleEvent,
|
|
22
|
+
type LearningCycleOptions,
|
|
23
|
+
type LearningCycleResult,
|
|
24
|
+
runLearningCycle,
|
|
25
|
+
} from './cycle.js'
|
|
26
26
|
import {
|
|
27
|
-
type
|
|
28
|
-
type
|
|
29
|
-
type
|
|
27
|
+
type LearningObservation,
|
|
28
|
+
type LearningObservationRecord,
|
|
29
|
+
type LearningTarget,
|
|
30
30
|
learningObservationSchema,
|
|
31
31
|
learningTargetSchema,
|
|
32
|
-
} from './
|
|
33
|
-
import {
|
|
32
|
+
} from './observation.js'
|
|
33
|
+
import { hashLearningSkill } from './skill.js'
|
|
34
34
|
|
|
35
35
|
const uuid = z
|
|
36
36
|
.string()
|
|
@@ -104,25 +104,25 @@ CREATE TABLE usage_receipts (
|
|
|
104
104
|
* and receipts by a turn id; a database at either (or any other version) is
|
|
105
105
|
* refused, never migrated — its rows name executions that no longer exist.
|
|
106
106
|
*/
|
|
107
|
-
export const
|
|
107
|
+
export const LEARNING_STORE_VERSION = 3
|
|
108
108
|
|
|
109
109
|
/** A learning database this version of the store does not read. */
|
|
110
|
-
export class
|
|
111
|
-
override readonly name = '
|
|
110
|
+
export class LearningStoreVersionError extends Error {
|
|
111
|
+
override readonly name = 'LearningStoreVersionError'
|
|
112
112
|
readonly found: number
|
|
113
113
|
readonly expected: number
|
|
114
114
|
|
|
115
115
|
constructor(databasePath: string, found: number) {
|
|
116
116
|
super(
|
|
117
|
-
`Learning database ${databasePath} is at schema version ${found}; this store reads version ${
|
|
117
|
+
`Learning database ${databasePath} is at schema version ${found}; this store reads version ${LEARNING_STORE_VERSION} only. Databases before version 3 are not read: move the file aside and start a new learning database.`,
|
|
118
118
|
)
|
|
119
119
|
this.found = found
|
|
120
|
-
this.expected =
|
|
120
|
+
this.expected = LEARNING_STORE_VERSION
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** @experimental Private parent directories and backup policy remain host responsibilities. */
|
|
125
|
-
export interface
|
|
125
|
+
export interface SqliteLearningStoreOptions {
|
|
126
126
|
readonly databasePath: string
|
|
127
127
|
readonly artifactsPath: string
|
|
128
128
|
readonly scope: {
|
|
@@ -134,14 +134,14 @@ export interface SqliteResidentLearningStoreOptions {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/** @experimental A content-addressed immutable JSON artifact, scoped through its owning cycle. */
|
|
137
|
-
export interface
|
|
137
|
+
export interface LearningArtifact {
|
|
138
138
|
readonly name: string
|
|
139
139
|
readonly hash: string
|
|
140
140
|
readonly bytes: number
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/** @experimental Recorded lower bounds; absence of a final result means completeness is unknown. */
|
|
144
|
-
export interface
|
|
144
|
+
export interface LearningRecordedUsage {
|
|
145
145
|
readonly tokens: number
|
|
146
146
|
readonly costUsd: number
|
|
147
147
|
readonly receipts: number
|
|
@@ -150,18 +150,18 @@ export interface ResidentLearningRecordedUsage {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/** @experimental Running/pending records require inspection; neither implies a live executor. */
|
|
153
|
-
export interface
|
|
153
|
+
export interface LearningCycleSummary {
|
|
154
154
|
readonly cycleId: string
|
|
155
155
|
readonly ordinal: number
|
|
156
156
|
readonly parentCycleId: string | null
|
|
157
157
|
readonly skillName: string | null
|
|
158
|
-
readonly status:
|
|
158
|
+
readonly status: LearningCycleResult['status'] | 'running' | 'activation-pending'
|
|
159
159
|
readonly sequence: number
|
|
160
160
|
readonly startedAt: number
|
|
161
161
|
readonly updatedAt: number
|
|
162
162
|
readonly candidateRevision: string | null
|
|
163
|
-
readonly result:
|
|
164
|
-
readonly recordedUsage:
|
|
163
|
+
readonly result: LearningCycleResult | null
|
|
164
|
+
readonly recordedUsage: LearningRecordedUsage
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
type CycleRow = {
|
|
@@ -172,7 +172,7 @@ type CycleRow = {
|
|
|
172
172
|
agent_key: string
|
|
173
173
|
parent_id: string | null
|
|
174
174
|
skill_name: string | null
|
|
175
|
-
status:
|
|
175
|
+
status: LearningCycleSummary['status']
|
|
176
176
|
sequence: number
|
|
177
177
|
started_at: number
|
|
178
178
|
updated_at: number
|
|
@@ -185,7 +185,7 @@ type CycleRow = {
|
|
|
185
185
|
unknown_costs: number
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
const summary = (row: CycleRow):
|
|
188
|
+
const summary = (row: CycleRow): LearningCycleSummary => ({
|
|
189
189
|
cycleId: row.id,
|
|
190
190
|
ordinal: row.ordinal,
|
|
191
191
|
parentCycleId: row.parent_id,
|
|
@@ -211,13 +211,13 @@ const summary = (row: CycleRow): ResidentLearningCycleSummary => ({
|
|
|
211
211
|
* No database transaction spans an await, model request or artifact write. JSONL
|
|
212
212
|
* exports are observations, never a second writable authority or a replay queue.
|
|
213
213
|
*/
|
|
214
|
-
export class
|
|
214
|
+
export class SqliteLearningStore {
|
|
215
215
|
readonly databasePath: string
|
|
216
216
|
readonly artifactsPath: string
|
|
217
|
-
private readonly scope:
|
|
217
|
+
private readonly scope: SqliteLearningStoreOptions['scope']
|
|
218
218
|
private readonly readOnly: boolean
|
|
219
219
|
|
|
220
|
-
constructor(options:
|
|
220
|
+
constructor(options: SqliteLearningStoreOptions) {
|
|
221
221
|
this.databasePath = resolve(options.databasePath)
|
|
222
222
|
this.artifactsPath = resolve(options.artifactsPath)
|
|
223
223
|
this.scope = Object.freeze({
|
|
@@ -238,7 +238,7 @@ export class SqliteResidentLearningStore {
|
|
|
238
238
|
Database = (createRequire(import.meta.url)('node:sqlite') as typeof import('node:sqlite'))
|
|
239
239
|
.DatabaseSync
|
|
240
240
|
} catch (error) {
|
|
241
|
-
throw new Error('
|
|
241
|
+
throw new Error('SqliteLearningStore requires Node.js 22.13 or newer.', {
|
|
242
242
|
cause: error,
|
|
243
243
|
})
|
|
244
244
|
}
|
|
@@ -260,12 +260,12 @@ export class SqliteResidentLearningStore {
|
|
|
260
260
|
)
|
|
261
261
|
throw new Error('Refusing to initialize a nonempty learning database.')
|
|
262
262
|
db.exec(
|
|
263
|
-
`${SCHEMA} ${OBSERVATIONS_SCHEMA} PRAGMA user_version = ${
|
|
263
|
+
`${SCHEMA} ${OBSERVATIONS_SCHEMA} PRAGMA user_version = ${LEARNING_STORE_VERSION};`,
|
|
264
264
|
)
|
|
265
265
|
} else if (version === 0)
|
|
266
266
|
throw new Error('Learning database is not initialized; open it for writing first.')
|
|
267
|
-
else if (version !==
|
|
268
|
-
throw new
|
|
267
|
+
else if (version !== LEARNING_STORE_VERSION)
|
|
268
|
+
throw new LearningStoreVersionError(this.databasePath, version)
|
|
269
269
|
const value = operation(db)
|
|
270
270
|
db.exec('COMMIT')
|
|
271
271
|
return value
|
|
@@ -291,7 +291,7 @@ export class SqliteResidentLearningStore {
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
/** Immutable, idempotent observations. Regrading requires a different evaluator revision. */
|
|
294
|
-
async observe(input:
|
|
294
|
+
async observe(input: LearningObservation): Promise<void> {
|
|
295
295
|
const value = learningObservationSchema.parse(input)
|
|
296
296
|
const body = JSON.stringify(value)
|
|
297
297
|
this.use(true, (db) => {
|
|
@@ -335,7 +335,7 @@ export class SqliteResidentLearningStore {
|
|
|
335
335
|
ordinal: number
|
|
336
336
|
body: string
|
|
337
337
|
attemptedCycleId: string | null
|
|
338
|
-
}):
|
|
338
|
+
}): LearningObservationRecord {
|
|
339
339
|
const value = learningObservationSchema.parse(JSON.parse(row.body))
|
|
340
340
|
return Object.freeze({
|
|
341
341
|
...value,
|
|
@@ -348,7 +348,7 @@ export class SqliteResidentLearningStore {
|
|
|
348
348
|
/** Ordered inspection; summaries are host observations, not inferred task completion. */
|
|
349
349
|
async observations(
|
|
350
350
|
options: { readonly after?: number; readonly limit?: number } = {},
|
|
351
|
-
): Promise<readonly
|
|
351
|
+
): Promise<readonly LearningObservationRecord[]> {
|
|
352
352
|
const after = z
|
|
353
353
|
.number()
|
|
354
354
|
.int()
|
|
@@ -375,10 +375,44 @@ export class SqliteResidentLearningStore {
|
|
|
375
375
|
})
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Drop unclaimed observations the host no longer wants to keep (retention). An
|
|
380
|
+
* observation a cycle has claimed is never dropped, so no experiment loses its
|
|
381
|
+
* source. Returns how many were removed; the store keeps no clock, so the host
|
|
382
|
+
* decides from the record (for example the age of its session).
|
|
383
|
+
*/
|
|
384
|
+
async pruneObservations(
|
|
385
|
+
shouldDrop: (record: LearningObservationRecord) => boolean,
|
|
386
|
+
): Promise<number> {
|
|
387
|
+
if (this.readOnly) throw new Error('Learning database is read-only.')
|
|
388
|
+
if (!existsSync(this.databasePath)) return 0
|
|
389
|
+
const doomed: number[] = []
|
|
390
|
+
for (let after = 0; ; ) {
|
|
391
|
+
const page = await this.observations({ after, limit: 100 })
|
|
392
|
+
if (page.length === 0) break
|
|
393
|
+
for (const record of page)
|
|
394
|
+
if (record.attemptedCycleId === null && shouldDrop(record)) doomed.push(record.ordinal)
|
|
395
|
+
after = page[page.length - 1]?.ordinal ?? after
|
|
396
|
+
}
|
|
397
|
+
if (doomed.length === 0) return 0
|
|
398
|
+
return this.use(true, (db) => {
|
|
399
|
+
const remove = db.prepare(
|
|
400
|
+
'DELETE FROM observations WHERE ordinal=? AND tenant_id=? AND project_id=? AND agent_key=?',
|
|
401
|
+
)
|
|
402
|
+
let removed = 0
|
|
403
|
+
for (const ordinal of doomed)
|
|
404
|
+
removed += Number(
|
|
405
|
+
remove.run(ordinal, this.scope.tenantId, this.scope.projectId, this.scope.agentKey)
|
|
406
|
+
.changes,
|
|
407
|
+
)
|
|
408
|
+
return removed
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
378
412
|
/** Oldest eligible unattempted task across current targets; no model call or claim is made. */
|
|
379
413
|
async selectObservation(
|
|
380
|
-
input: readonly
|
|
381
|
-
): Promise<
|
|
414
|
+
input: readonly LearningTarget[],
|
|
415
|
+
): Promise<LearningObservationRecord | null> {
|
|
382
416
|
const targets = z.array(learningTargetSchema).min(1).max(16).parse(input)
|
|
383
417
|
if (new Set(targets.map((t) => t.skillName)).size !== targets.length)
|
|
384
418
|
throw new Error('Learning selection requires one current evaluator per skill.')
|
|
@@ -410,7 +444,7 @@ export class SqliteResidentLearningStore {
|
|
|
410
444
|
})
|
|
411
445
|
}
|
|
412
446
|
|
|
413
|
-
private claimObservation(db: DatabaseSync, event:
|
|
447
|
+
private claimObservation(db: DatabaseSync, event: LearningCycleEvent): void {
|
|
414
448
|
if (event.kind !== 'started' || event.data.observation === undefined) return
|
|
415
449
|
const selected = z
|
|
416
450
|
.object({ ordinal: z.number().int().positive().safe() })
|
|
@@ -444,7 +478,7 @@ export class SqliteResidentLearningStore {
|
|
|
444
478
|
}
|
|
445
479
|
|
|
446
480
|
/** Identical event retries are idempotent. Different content at the same sequence is refused. */
|
|
447
|
-
async append(input:
|
|
481
|
+
async append(input: LearningCycleEvent): Promise<void> {
|
|
448
482
|
const event = z
|
|
449
483
|
.object({
|
|
450
484
|
cycleId: uuid,
|
|
@@ -557,7 +591,7 @@ export class SqliteResidentLearningStore {
|
|
|
557
591
|
.parse(event.data.candidateRevision)
|
|
558
592
|
if (event.kind === 'activation-requested') status = 'activation-pending'
|
|
559
593
|
if (event.kind === 'finished') {
|
|
560
|
-
const value = event.data.result as
|
|
594
|
+
const value = event.data.result as LearningCycleResult
|
|
561
595
|
if (!value || uuid.parse(value.cycleId) !== event.cycleId)
|
|
562
596
|
throw new Error('Learning result identity differs from its journal.')
|
|
563
597
|
status = z
|
|
@@ -593,7 +627,7 @@ export class SqliteResidentLearningStore {
|
|
|
593
627
|
})
|
|
594
628
|
}
|
|
595
629
|
|
|
596
|
-
async get(cycleId: string): Promise<
|
|
630
|
+
async get(cycleId: string): Promise<LearningCycleSummary | null> {
|
|
597
631
|
const id = uuid.parse(cycleId)
|
|
598
632
|
return this.use(false, (db) => {
|
|
599
633
|
const row = this.owned(db, id)
|
|
@@ -603,7 +637,7 @@ export class SqliteResidentLearningStore {
|
|
|
603
637
|
|
|
604
638
|
async list(
|
|
605
639
|
options: { readonly before?: number; readonly limit?: number } = {},
|
|
606
|
-
): Promise<readonly
|
|
640
|
+
): Promise<readonly LearningCycleSummary[]> {
|
|
607
641
|
const limit = z
|
|
608
642
|
.number()
|
|
609
643
|
.int()
|
|
@@ -636,7 +670,7 @@ export class SqliteResidentLearningStore {
|
|
|
636
670
|
async events(
|
|
637
671
|
cycleId: string,
|
|
638
672
|
options: { readonly after?: number; readonly limit?: number } = {},
|
|
639
|
-
): Promise<readonly
|
|
673
|
+
): Promise<readonly LearningCycleEvent[]> {
|
|
640
674
|
const id = uuid.parse(cycleId)
|
|
641
675
|
const after = z
|
|
642
676
|
.number()
|
|
@@ -661,22 +695,18 @@ export class SqliteResidentLearningStore {
|
|
|
661
695
|
})
|
|
662
696
|
}
|
|
663
697
|
|
|
664
|
-
async artifacts(cycleId: string): Promise<readonly
|
|
698
|
+
async artifacts(cycleId: string): Promise<readonly LearningArtifact[]> {
|
|
665
699
|
const id = uuid.parse(cycleId)
|
|
666
700
|
return this.use(false, (db) => {
|
|
667
701
|
if (!this.owned(db, id)) return []
|
|
668
702
|
return db
|
|
669
703
|
.prepare('SELECT name, hash, bytes FROM artifacts WHERE cycle_id = ? ORDER BY name')
|
|
670
|
-
.all(id) as unknown as
|
|
704
|
+
.all(id) as unknown as LearningArtifact[]
|
|
671
705
|
})
|
|
672
706
|
}
|
|
673
707
|
|
|
674
708
|
/** Complete immutable bytes precede the reference; an interrupted publication may leave an unreferenced blob. */
|
|
675
|
-
async putArtifact(
|
|
676
|
-
cycleId: string,
|
|
677
|
-
name: string,
|
|
678
|
-
value: unknown,
|
|
679
|
-
): Promise<ResidentLearningArtifact> {
|
|
709
|
+
async putArtifact(cycleId: string, name: string, value: unknown): Promise<LearningArtifact> {
|
|
680
710
|
if (this.readOnly) throw new Error('Learning database is read-only.')
|
|
681
711
|
const id = uuid.parse(cycleId)
|
|
682
712
|
z.string()
|
|
@@ -775,11 +805,11 @@ export class SqliteResidentLearningStore {
|
|
|
775
805
|
}
|
|
776
806
|
|
|
777
807
|
/** @experimental Supply normal host callbacks; the store retains journal events and full paired batches. */
|
|
778
|
-
export async function
|
|
779
|
-
store:
|
|
780
|
-
options: Omit<
|
|
781
|
-
): Promise<
|
|
782
|
-
return
|
|
808
|
+
export async function runStoredLearningCycle(
|
|
809
|
+
store: SqliteLearningStore,
|
|
810
|
+
options: Omit<LearningCycleOptions, 'record'>,
|
|
811
|
+
): Promise<LearningCycleResult> {
|
|
812
|
+
return runLearningCycle({
|
|
783
813
|
...options,
|
|
784
814
|
record: (event) => store.append(event),
|
|
785
815
|
evaluate: async (context) => {
|
|
@@ -791,15 +821,15 @@ export async function runStoredResidentLearningCycle(
|
|
|
791
821
|
}
|
|
792
822
|
|
|
793
823
|
/** @experimental Host authorizes evaluators; the SDK selects a retained failure against the active skill. */
|
|
794
|
-
export interface
|
|
795
|
-
extends Omit<
|
|
824
|
+
export interface LearningDiscoveryOptions
|
|
825
|
+
extends Omit<LearningCycleOptions, 'record' | 'failure' | 'skillName'> {
|
|
796
826
|
readonly evaluators: readonly { readonly skillName: string; readonly evaluatorRevision: string }[]
|
|
797
827
|
}
|
|
798
828
|
|
|
799
829
|
/** @experimental Null cycle means no eligible work. A failed claimed cycle is never silently replayed. */
|
|
800
|
-
export interface
|
|
801
|
-
readonly observation:
|
|
802
|
-
readonly cycle:
|
|
830
|
+
export interface LearningDiscoveryResult {
|
|
831
|
+
readonly observation: LearningObservationRecord | null
|
|
832
|
+
readonly cycle: LearningCycleResult | null
|
|
803
833
|
}
|
|
804
834
|
|
|
805
835
|
/**
|
|
@@ -808,22 +838,22 @@ export interface ResidentLearningDiscoveryResult {
|
|
|
808
838
|
* Claim and start are one SQLite transaction; concurrent selectors cannot run
|
|
809
839
|
* the same task/evaluator/baseline twice, even after a crash or reopened process.
|
|
810
840
|
*/
|
|
811
|
-
export async function
|
|
812
|
-
store:
|
|
813
|
-
options:
|
|
814
|
-
): Promise<
|
|
841
|
+
export async function runStoredLearningFromObservations(
|
|
842
|
+
store: SqliteLearningStore,
|
|
843
|
+
options: LearningDiscoveryOptions,
|
|
844
|
+
): Promise<LearningDiscoveryResult> {
|
|
815
845
|
options.signal.throwIfAborted()
|
|
816
846
|
const agenda = await options.agenda.read()
|
|
817
847
|
if (!agenda || agenda.paused || agenda.pursuits.some((p) => p.state.phase === 'running'))
|
|
818
848
|
throw new Error('Learning discovery requires an unpaused agenda without running pursuits.')
|
|
819
849
|
const targets = options.evaluators.map((target) => {
|
|
820
850
|
const skill = agenda.learning?.skills.find((s) => s.name === target.skillName)
|
|
821
|
-
return { ...target, baselineRevision: skill ?
|
|
851
|
+
return { ...target, baselineRevision: skill ? hashLearningSkill(skill) : 'none' }
|
|
822
852
|
})
|
|
823
853
|
const observation = await store.selectObservation(targets)
|
|
824
854
|
options.signal.throwIfAborted()
|
|
825
855
|
if (!observation) return { observation: null, cycle: null }
|
|
826
|
-
const cycle = await
|
|
856
|
+
const cycle = await runLearningCycle({
|
|
827
857
|
...options,
|
|
828
858
|
skillName: observation.skillName,
|
|
829
859
|
failure: { evidence: observation.evidence, trace: observation.trace },
|
|
@@ -2,14 +2,22 @@ import { z } from 'zod'
|
|
|
2
2
|
import type { ResidentAgendaState } from './agenda.js'
|
|
3
3
|
import { ResidentHistoryPageLimit, type ResidentHistoryReadBudget } from './history-disk.js'
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* @experimental An immutable upper boundary; new work requires a new source.
|
|
7
|
+
*
|
|
8
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
9
|
+
*/
|
|
6
10
|
export interface ResidentActivityScope {
|
|
7
11
|
readonly tenantId: string
|
|
8
12
|
readonly agentKey: string
|
|
9
13
|
readonly throughRevision: number
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* @experimental Admission is authority to inspect an attempt, not proof that it executed.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
20
|
+
*/
|
|
13
21
|
export interface ResidentAdmission {
|
|
14
22
|
readonly revision: number
|
|
15
23
|
readonly pursuitRevision: number
|
|
@@ -19,7 +27,11 @@ export interface ResidentAdmission {
|
|
|
19
27
|
readonly objective: string
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* @experimental Settlement is an agenda decision, not proof of verification or delivery.
|
|
32
|
+
*
|
|
33
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
34
|
+
*/
|
|
23
35
|
export interface ResidentSettlement {
|
|
24
36
|
readonly revision: number
|
|
25
37
|
readonly pursuitId: string
|
|
@@ -27,14 +39,22 @@ export interface ResidentSettlement {
|
|
|
27
39
|
readonly outcome: 'wait' | 'complete' | 'blocked'
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* @experimental Forward pages; cursor is the next revision to inspect, initially 1.
|
|
44
|
+
*
|
|
45
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
46
|
+
*/
|
|
31
47
|
export interface ResidentActivityOptions {
|
|
32
48
|
readonly cursor?: number
|
|
33
49
|
readonly maxRevisions?: number
|
|
34
50
|
readonly maxReadBytes?: number
|
|
35
51
|
}
|
|
36
52
|
|
|
37
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* @experimental Gaps stay explicit; counts cover only the scanned revision range.
|
|
55
|
+
*
|
|
56
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
57
|
+
*/
|
|
38
58
|
export interface ResidentActivityPage {
|
|
39
59
|
readonly scope: ResidentActivityScope
|
|
40
60
|
readonly fromRevision: number
|
|
@@ -47,7 +67,11 @@ export interface ResidentActivityPage {
|
|
|
47
67
|
readonly archivedPursuits: readonly string[]
|
|
48
68
|
}
|
|
49
69
|
|
|
50
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* @experimental A backend must enforce scope, cancellation and read bounds.
|
|
72
|
+
*
|
|
73
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
74
|
+
*/
|
|
51
75
|
export interface ResidentActivitySource {
|
|
52
76
|
readonly scope: ResidentActivityScope
|
|
53
77
|
read(options?: ResidentActivityOptions, signal?: AbortSignal): Promise<ResidentActivityPage>
|
|
@@ -20,6 +20,19 @@ import {
|
|
|
20
20
|
wakeResidentState,
|
|
21
21
|
} from './store.js'
|
|
22
22
|
|
|
23
|
+
import {
|
|
24
|
+
type LearningEvidence,
|
|
25
|
+
type LearningProfileUpdate,
|
|
26
|
+
type LearningSkillCandidate,
|
|
27
|
+
type LearningSkillEvaluation,
|
|
28
|
+
type LearningState,
|
|
29
|
+
freezeLearning,
|
|
30
|
+
learningEvidenceSchema,
|
|
31
|
+
learningSchema,
|
|
32
|
+
promoteLearningSkill,
|
|
33
|
+
restoreLearningSkill,
|
|
34
|
+
reviseLearningProfile,
|
|
35
|
+
} from '../../learning/skill.js'
|
|
23
36
|
import { type ResidentActivitySource, createResidentActivitySource } from './activity.js'
|
|
24
37
|
import { readResidentHistoryRecord } from './history-disk.js'
|
|
25
38
|
import { type ResidentHistorySource, createResidentHistorySource } from './history.js'
|
|
@@ -31,19 +44,6 @@ import {
|
|
|
31
44
|
residentFeedbackSchema,
|
|
32
45
|
residentObservationSchema,
|
|
33
46
|
} from './initiative.js'
|
|
34
|
-
import {
|
|
35
|
-
type ResidentLearningEvidence,
|
|
36
|
-
type ResidentLearningState,
|
|
37
|
-
type ResidentProfileUpdate,
|
|
38
|
-
type ResidentSkillCandidate,
|
|
39
|
-
type ResidentSkillEvaluation,
|
|
40
|
-
freezeResidentLearning,
|
|
41
|
-
promoteResidentSkill,
|
|
42
|
-
residentLearningEvidenceSchema,
|
|
43
|
-
residentLearningSchema,
|
|
44
|
-
restoreResidentSkill,
|
|
45
|
-
reviseResidentProfile,
|
|
46
|
-
} from './learning.js'
|
|
47
47
|
import {
|
|
48
48
|
type ResidentDeliveryOutcome,
|
|
49
49
|
type ResidentMessageInput,
|
|
@@ -74,7 +74,7 @@ const agendaSchema = z
|
|
|
74
74
|
paused: z.boolean(),
|
|
75
75
|
pauseGeneration: z.number().int().nonnegative().safe().optional(),
|
|
76
76
|
archiveHead: z.number().int().min(2).safe().optional(),
|
|
77
|
-
learning:
|
|
77
|
+
learning: learningSchema.optional(),
|
|
78
78
|
outbox: z.array(residentOutboxMessageSchema).max(128).optional(),
|
|
79
79
|
pursuits: z
|
|
80
80
|
.array(
|
|
@@ -136,7 +136,11 @@ const agendaSchema = z
|
|
|
136
136
|
})
|
|
137
137
|
})
|
|
138
138
|
|
|
139
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* @experimental One pursuit shares its agent's identity, but has its own lifecycle.
|
|
141
|
+
*
|
|
142
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
143
|
+
*/
|
|
140
144
|
export interface ResidentPursuit {
|
|
141
145
|
readonly id: string
|
|
142
146
|
readonly state: ResidentState
|
|
@@ -146,7 +150,11 @@ export interface ResidentPursuit {
|
|
|
146
150
|
readonly retiredChildren?: number
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* @experimental Bounded shared admission record; at most one pursuit may be running.
|
|
155
|
+
*
|
|
156
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
157
|
+
*/
|
|
150
158
|
export interface ResidentAgendaState {
|
|
151
159
|
readonly tenantId: string
|
|
152
160
|
readonly agentKey: string
|
|
@@ -158,29 +166,45 @@ export interface ResidentAgendaState {
|
|
|
158
166
|
readonly pursuits: readonly ResidentPursuit[]
|
|
159
167
|
readonly outbox?: readonly ResidentOutboxMessage[]
|
|
160
168
|
readonly archiveHead?: number
|
|
161
|
-
readonly learning?:
|
|
169
|
+
readonly learning?: LearningState
|
|
162
170
|
}
|
|
163
171
|
|
|
164
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* @experimental Explicit terminal entries to retire from active capacity together.
|
|
174
|
+
*
|
|
175
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
176
|
+
*/
|
|
165
177
|
export interface ResidentArchiveRequest {
|
|
166
178
|
readonly pursuitIds?: readonly string[]
|
|
167
179
|
readonly messageIds?: readonly string[]
|
|
168
180
|
}
|
|
169
181
|
|
|
170
|
-
/**
|
|
182
|
+
/**
|
|
183
|
+
* @experimental A committed removal, whose immutable predecessor preserves the full records.
|
|
184
|
+
*
|
|
185
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
186
|
+
*/
|
|
171
187
|
export interface ResidentArchiveEntry {
|
|
172
188
|
readonly revision: number
|
|
173
189
|
readonly pursuits: readonly ResidentPursuit[]
|
|
174
190
|
readonly messages: readonly ResidentOutboxMessage[]
|
|
175
191
|
}
|
|
176
192
|
|
|
177
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* @experimental Pages count archive events; each event contains at most 32 pursuits and 128 messages.
|
|
195
|
+
*
|
|
196
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
197
|
+
*/
|
|
178
198
|
export interface ResidentArchivePage {
|
|
179
199
|
readonly entries: readonly ResidentArchiveEntry[]
|
|
180
200
|
readonly nextBeforeRevision: number | null
|
|
181
201
|
}
|
|
182
202
|
|
|
183
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* @experimental The cursor is the next archive-event revision returned by a previous page.
|
|
205
|
+
*
|
|
206
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
207
|
+
*/
|
|
184
208
|
export interface ResidentArchiveListOptions {
|
|
185
209
|
readonly beforeRevision?: number
|
|
186
210
|
/** Number of archive events to inspect; defaults to 8 and cannot exceed 32. */
|
|
@@ -204,7 +228,11 @@ const archiveRequestSchema = z.object({
|
|
|
204
228
|
messageIds: z.array(z.string().uuid()).max(128).default([]),
|
|
205
229
|
})
|
|
206
230
|
|
|
207
|
-
/**
|
|
231
|
+
/**
|
|
232
|
+
* @experimental Atomic whole-agent admission plus independently addressable pursuits.
|
|
233
|
+
*
|
|
234
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
235
|
+
*/
|
|
208
236
|
export interface ResidentAgendaStore {
|
|
209
237
|
read(): Promise<ResidentAgendaState | null>
|
|
210
238
|
create(identity: string): Promise<ResidentAgendaState>
|
|
@@ -251,6 +279,8 @@ export interface ResidentAgendaStore {
|
|
|
251
279
|
* @experimental One immutable revision contains identity, pause state and all
|
|
252
280
|
* pursuits. Admission therefore serializes this agent even across processes
|
|
253
281
|
* choosing different pursuits. Trusted local filesystems only; no lease expiry.
|
|
282
|
+
*
|
|
283
|
+
* @deprecated Residents are deprecated and removed in the next major release. Learning (`runLearningCycle` and the other `Learning*` names) keeps working, but `runLearningCycle` still takes a resident agenda until learning gets its own activation target in the next major release; for long-running work use scheduled tasks (`LocalTaskScheduler`), session goals and background agents.
|
|
254
284
|
*/
|
|
255
285
|
export class DiskResidentAgenda implements ResidentAgendaStore {
|
|
256
286
|
private readonly records = new DiskRevisionRecordStore<ResidentAgendaState>(
|
|
@@ -284,7 +314,7 @@ export class DiskResidentAgenda implements ResidentAgendaStore {
|
|
|
284
314
|
throw new Error('Agenda does not match the bound tenant and agent.')
|
|
285
315
|
return Object.freeze({
|
|
286
316
|
...agenda,
|
|
287
|
-
...(agenda.learning ? { learning:
|
|
317
|
+
...(agenda.learning ? { learning: freezeLearning(agenda.learning) } : {}),
|
|
288
318
|
...(agenda.outbox
|
|
289
319
|
? { outbox: Object.freeze(agenda.outbox.map((message) => Object.freeze(message))) }
|
|
290
320
|
: {}),
|
|
@@ -596,7 +626,7 @@ export class DiskResidentAgenda implements ResidentAgendaStore {
|
|
|
596
626
|
|
|
597
627
|
private async learn(
|
|
598
628
|
expected: ResidentAgendaState,
|
|
599
|
-
learning:
|
|
629
|
+
learning: LearningState,
|
|
600
630
|
): Promise<ResidentAgendaState> {
|
|
601
631
|
return this.change(expected, (state) => {
|
|
602
632
|
if (state.pursuits.some((pursuit) => pursuit.state.phase === 'running'))
|
|
@@ -609,22 +639,22 @@ export class DiskResidentAgenda implements ResidentAgendaStore {
|
|
|
609
639
|
/** Append a host-evidenced correction only while pursuit admission is idle. */
|
|
610
640
|
async updateProfile(
|
|
611
641
|
expected: ResidentAgendaState,
|
|
612
|
-
input:
|
|
642
|
+
input: LearningProfileUpdate,
|
|
613
643
|
): Promise<ResidentAgendaState> {
|
|
614
644
|
const snapshot = this.checked(expected)
|
|
615
|
-
const learning =
|
|
645
|
+
const learning = reviseLearningProfile(snapshot.learning, input)
|
|
616
646
|
return this.learn(snapshot, learning)
|
|
617
647
|
}
|
|
618
648
|
|
|
619
649
|
/** Bind evaluated guidance to the current learning version and an idle agenda. */
|
|
620
650
|
async promoteSkill(
|
|
621
651
|
expected: ResidentAgendaState,
|
|
622
|
-
candidate:
|
|
623
|
-
evaluation:
|
|
624
|
-
evidence:
|
|
652
|
+
candidate: LearningSkillCandidate,
|
|
653
|
+
evaluation: LearningSkillEvaluation,
|
|
654
|
+
evidence: LearningEvidence,
|
|
625
655
|
): Promise<ResidentAgendaState> {
|
|
626
656
|
const snapshot = this.checked(expected)
|
|
627
|
-
const learning =
|
|
657
|
+
const learning = promoteLearningSkill(snapshot.learning, candidate, evaluation, evidence)
|
|
628
658
|
return this.learn(snapshot, learning)
|
|
629
659
|
}
|
|
630
660
|
|
|
@@ -633,17 +663,17 @@ export class DiskResidentAgenda implements ResidentAgendaStore {
|
|
|
633
663
|
expected: ResidentAgendaState,
|
|
634
664
|
name: string,
|
|
635
665
|
fromRevision: number,
|
|
636
|
-
evidence:
|
|
666
|
+
evidence: LearningEvidence,
|
|
637
667
|
): Promise<ResidentAgendaState> {
|
|
638
668
|
const snapshot = this.checked(expected)
|
|
639
|
-
const checkedEvidence =
|
|
669
|
+
const checkedEvidence = learningEvidenceSchema.parse(evidence)
|
|
640
670
|
z.number().int().positive().safe().max(snapshot.revision).parse(fromRevision)
|
|
641
671
|
z.string()
|
|
642
672
|
.regex(/^[a-z0-9][a-z0-9_-]{0,63}$/)
|
|
643
673
|
.parse(name)
|
|
644
674
|
const historical = await this.readRevision(fromRevision)
|
|
645
675
|
if (!historical) throw new Error('Resident skill rollback revision is missing.')
|
|
646
|
-
const learning =
|
|
676
|
+
const learning = restoreLearningSkill(
|
|
647
677
|
snapshot.learning,
|
|
648
678
|
historical.learning,
|
|
649
679
|
name,
|