@jinn-network/plugin 0.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/dist/eligibility.d.ts +12 -0
- package/dist/eligibility.js +12 -0
- package/dist/history.d.ts +35 -0
- package/dist/history.js +140 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +15 -0
- package/dist/outcome.d.ts +26 -0
- package/dist/outcome.js +23 -0
- package/dist/pickup.d.ts +101 -0
- package/dist/pickup.js +354 -0
- package/dist/plugin.d.ts +157 -0
- package/dist/plugin.js +586 -0
- package/dist/ports/contribution-port.d.ts +53 -0
- package/dist/ports/contribution-port.js +14 -0
- package/dist/ports/corpus-port.d.ts +63 -0
- package/dist/ports/corpus-port.js +1 -0
- package/dist/ports/evidence-port.d.ts +17 -0
- package/dist/ports/evidence-port.js +1 -0
- package/dist/ports/local-learning-port.d.ts +22 -0
- package/dist/ports/local-learning-port.js +1 -0
- package/dist/ports/skills-port.d.ts +12 -0
- package/dist/ports/skills-port.js +1 -0
- package/dist/schemas/contribution-candidate.d.ts +116 -0
- package/dist/schemas/contribution-candidate.js +63 -0
- package/dist/schemas/eligibility-verdict.d.ts +8 -0
- package/dist/schemas/eligibility-verdict.js +7 -0
- package/dist/schemas/episode.d.ts +432 -0
- package/dist/schemas/episode.js +452 -0
- package/dist/schemas/history-entry.d.ts +40 -0
- package/dist/schemas/history-entry.js +30 -0
- package/dist/schemas/knowledge-hit.d.ts +27 -0
- package/dist/schemas/knowledge-hit.js +23 -0
- package/dist/schemas/knowledge-packet.d.ts +79 -0
- package/dist/schemas/knowledge-packet.js +213 -0
- package/dist/schemas/pickup-config.d.ts +20 -0
- package/dist/schemas/pickup-config.js +34 -0
- package/dist/schemas/session-summary.d.ts +17 -0
- package/dist/schemas/session-summary.js +19 -0
- package/dist/testing/contract-kits.d.ts +12 -0
- package/dist/testing/contract-kits.js +201 -0
- package/dist/testing/in-memory-contribution.d.ts +93 -0
- package/dist/testing/in-memory-contribution.js +104 -0
- package/dist/testing/in-memory-corpus.d.ts +47 -0
- package/dist/testing/in-memory-corpus.js +54 -0
- package/dist/testing/in-memory-evidence.d.ts +335 -0
- package/dist/testing/in-memory-evidence.js +23 -0
- package/dist/testing/in-memory-local-learning.d.ts +25 -0
- package/dist/testing/in-memory-local-learning.js +30 -0
- package/dist/testing/in-memory-skills.d.ts +9 -0
- package/dist/testing/in-memory-skills.js +16 -0
- package/dist/testing.d.ts +6 -0
- package/dist/testing.js +8 -0
- package/dist/visibility.d.ts +7 -0
- package/dist/visibility.js +9 -0
- package/package.json +48 -0
- package/process-contract.json +8 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EpisodeV1 — the complete-trajectory evidence record (architecture spec §5).
|
|
3
|
+
* Superset of `packages/core/src/captured-task.ts`'s CapturedTask:
|
|
4
|
+
* the full trajectory as one ordered `kind`-discriminated span sequence, a
|
|
5
|
+
* skills loadout, token + USD cost, a per-record retention field, and optional
|
|
6
|
+
* lineage hooks. Strict at every level (unknown fields rejected), following the
|
|
7
|
+
* capture.ts / envelope.ts convention.
|
|
8
|
+
*
|
|
9
|
+
* Deviation from CapturedTask, noted per plan (#1658): `task.distributionTags`
|
|
10
|
+
* defaults to `[]` rather than requiring `.min(1)` — Stage 1 has no tagging
|
|
11
|
+
* policy yet (S1-F2). `trajectory` is one ordered span sequence (`.min(1)`; a
|
|
12
|
+
* zero-tool-call session still has ≥1 `jinn.agent_turn` step). `cost.usdEstimate`
|
|
13
|
+
* is restored (optional) so EpisodeV1 stays a true CapturedTask superset.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { EligibilityVerdictSchema } from './eligibility-verdict.js';
|
|
17
|
+
import { ContributionCandidateV1ReadSchema, ContributionCandidateV1Schema, } from './contribution-candidate.js';
|
|
18
|
+
export const EPISODE_SCHEMA_VERSION = 'jinn.episode.v1';
|
|
19
|
+
export const EPISODE_PROVENANCES = [
|
|
20
|
+
'contributed',
|
|
21
|
+
'imported',
|
|
22
|
+
'derived-from-history',
|
|
23
|
+
];
|
|
24
|
+
export const EpisodeProvenanceSchema = z.enum(EPISODE_PROVENANCES);
|
|
25
|
+
const UnixNanoSchema = z.string().regex(/^\d+$/, 'unix-nanosecond digit string');
|
|
26
|
+
/**
|
|
27
|
+
* `kind` tracks the DR-2026-07-14 §6 working names: `jinn.agent_turn` carries a
|
|
28
|
+
* `role: user|assistant` in `attributes`; `jinn.tool_call` is a tool invocation.
|
|
29
|
+
* Re-declared inline (rather than imported) because #1473 is still open and arch
|
|
30
|
+
* §6 forbids the plugin package importing from `client/src/**`.
|
|
31
|
+
*/
|
|
32
|
+
const StepShape = {
|
|
33
|
+
spanId: z.string().min(1),
|
|
34
|
+
parentSpanId: z.string().min(1).nullable(),
|
|
35
|
+
kind: z.enum(['jinn.agent_turn', 'jinn.tool_call']),
|
|
36
|
+
name: z.string().min(1),
|
|
37
|
+
startTimeUnixNano: UnixNanoSchema,
|
|
38
|
+
endTimeUnixNano: UnixNanoSchema,
|
|
39
|
+
attributes: z.record(z.string(), z.unknown()),
|
|
40
|
+
redactedKeys: z.array(z.string().min(1)).default([]),
|
|
41
|
+
/** Public scrub projection receipt; absent on ordinary local episodes. */
|
|
42
|
+
truncatedKeys: z.array(z.string().min(1)).optional(),
|
|
43
|
+
/** Canonical OTLP observations are additive for read compatibility. */
|
|
44
|
+
events: z.array(z.strictObject({
|
|
45
|
+
timeUnixNano: UnixNanoSchema,
|
|
46
|
+
name: z.string().min(1),
|
|
47
|
+
attributes: z.record(z.string(), z.unknown()).optional(),
|
|
48
|
+
})).optional(),
|
|
49
|
+
status: z.strictObject({
|
|
50
|
+
code: z.enum(['UNSET', 'OK', 'ERROR']),
|
|
51
|
+
message: z.string().min(1).optional(),
|
|
52
|
+
}).optional(),
|
|
53
|
+
};
|
|
54
|
+
const StepWriteSchema = z.strictObject(StepShape);
|
|
55
|
+
const StepReadSchema = z.looseObject(StepShape);
|
|
56
|
+
/**
|
|
57
|
+
* Rescope (2026-07-16): `searchedTerms`/`providedRefs` are the current
|
|
58
|
+
* evidence-first pickup facts. The pre-rescope `surfacedRefs`/`fetchedRefs`/
|
|
59
|
+
* `installedSkillRefs` trio remains in the schema — defaulted, so existing
|
|
60
|
+
* local episode files (and hosts that have not yet migrated) still parse —
|
|
61
|
+
* but is no longer the primary signal a new pickup writes.
|
|
62
|
+
*/
|
|
63
|
+
const LegacyActivityShape = {
|
|
64
|
+
searchedTerms: z.array(z.string().min(1)).default([]),
|
|
65
|
+
providedRefs: z.array(z.string().min(1)).default([]),
|
|
66
|
+
/** @deprecated rescope — retained for read-compat with pre-rescope episode files. */
|
|
67
|
+
surfacedRefs: z.array(z.string().min(1)).default([]),
|
|
68
|
+
/** @deprecated rescope — retained for read-compat; still recorded as an
|
|
69
|
+
* internal fetch-attempt detail by the current pickup (rescope §3.6). */
|
|
70
|
+
fetchedRefs: z.array(z.string().min(1)).default([]),
|
|
71
|
+
/** @deprecated rescope — the skill adopt/install path no longer exists in pickup. */
|
|
72
|
+
installedSkillRefs: z.array(z.string().min(1)).default([]),
|
|
73
|
+
};
|
|
74
|
+
const DeliveryActivityShape = {
|
|
75
|
+
retrievalFired: z.boolean(),
|
|
76
|
+
eligibleRefs: z.array(z.string().min(1)),
|
|
77
|
+
deliveredRefs: z.array(z.string().min(1)),
|
|
78
|
+
deliveryMode: z.enum(['delivered', 'disabled', 'degraded', 'withheld']),
|
|
79
|
+
deliveredContentHash: z.string().regex(/^sha256:[0-9a-f]{64}$/).optional(),
|
|
80
|
+
};
|
|
81
|
+
export const SessionActivityFactsWriteSchema = z.strictObject({
|
|
82
|
+
...LegacyActivityShape,
|
|
83
|
+
...DeliveryActivityShape,
|
|
84
|
+
}).superRefine((activity, context) => {
|
|
85
|
+
if ((activity.deliveryMode === 'delivered' || activity.deliveredRefs.length > 0)
|
|
86
|
+
&& activity.deliveredContentHash === undefined) {
|
|
87
|
+
context.addIssue({
|
|
88
|
+
code: 'custom',
|
|
89
|
+
path: ['deliveredContentHash'],
|
|
90
|
+
message: 'delivered evidence requires the exact sha256 content hash',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const SessionShape = {
|
|
95
|
+
sessionId: z.string().min(1).max(128),
|
|
96
|
+
capturedAt: z.iso.datetime(),
|
|
97
|
+
kind: z.enum(['user', 'host-internal']),
|
|
98
|
+
parentSessionId: z.string().min(1).max(128).optional(),
|
|
99
|
+
};
|
|
100
|
+
const TaskShape = {
|
|
101
|
+
summary: z.string().min(1),
|
|
102
|
+
distributionTags: z.array(z.string().min(1)).default([]),
|
|
103
|
+
repositorySlug: z.string().min(1).optional(),
|
|
104
|
+
/** Post-training tuple join/freshness fields (#1827/#1842). */
|
|
105
|
+
baseCommit: z.string().min(1).optional(),
|
|
106
|
+
createdAt: z.number().int().nonnegative().optional(),
|
|
107
|
+
instanceId: z.string().min(1).optional(),
|
|
108
|
+
};
|
|
109
|
+
export const VERIFICATION_STRENGTHS = [
|
|
110
|
+
'user-accepted',
|
|
111
|
+
'tests-passed',
|
|
112
|
+
'evaluator-verified',
|
|
113
|
+
];
|
|
114
|
+
export const VerificationStrengthSchema = z.enum(VERIFICATION_STRENGTHS);
|
|
115
|
+
const OutcomeShape = {
|
|
116
|
+
status: z.enum(['completed', 'failed', 'abandoned']),
|
|
117
|
+
/** The one outcome-verification axis used by new local and public records.
|
|
118
|
+
* `verifiabilityTier` is normalized into this field on compatible reads and
|
|
119
|
+
* writes; the outer execution envelope's evidenceTier remains transport /
|
|
120
|
+
* attestation assurance and is not misrepresented as outcome correctness. */
|
|
121
|
+
verificationStrength: VerificationStrengthSchema,
|
|
122
|
+
summary: z.string().min(1).optional(),
|
|
123
|
+
acceptedDiff: z.boolean().optional(),
|
|
124
|
+
testRuns: z.strictObject({
|
|
125
|
+
passed: z.number().int().nonnegative(),
|
|
126
|
+
failed: z.number().int().nonnegative(),
|
|
127
|
+
}).optional(),
|
|
128
|
+
};
|
|
129
|
+
function normalizeOutcomeCompatibility(value) {
|
|
130
|
+
const raw = asRecord(value);
|
|
131
|
+
if (!raw)
|
|
132
|
+
return value;
|
|
133
|
+
const normalized = { ...raw };
|
|
134
|
+
const legacy = normalized['verifiabilityTier'];
|
|
135
|
+
const canonical = normalized['verificationStrength'];
|
|
136
|
+
if (legacy !== undefined) {
|
|
137
|
+
// A disagreement is made deliberately unparseable instead of silently
|
|
138
|
+
// choosing one axis.
|
|
139
|
+
normalized['verificationStrength'] =
|
|
140
|
+
canonical !== undefined && canonical !== legacy
|
|
141
|
+
? [canonical, legacy]
|
|
142
|
+
: legacy;
|
|
143
|
+
delete normalized['verifiabilityTier'];
|
|
144
|
+
}
|
|
145
|
+
return normalized;
|
|
146
|
+
}
|
|
147
|
+
const OutcomeWriteSchema = z.preprocess(normalizeOutcomeCompatibility, z.strictObject(OutcomeShape));
|
|
148
|
+
const GeneratorModelShape = {
|
|
149
|
+
id: z.string().min(1),
|
|
150
|
+
provider: z.string().min(1).optional(),
|
|
151
|
+
openWeights: z.boolean().optional(),
|
|
152
|
+
source: z.enum(['stream', 'config']),
|
|
153
|
+
};
|
|
154
|
+
const GeneratorModelWriteSchema = z.strictObject(GeneratorModelShape);
|
|
155
|
+
const GeneratorModelReadSchema = z.looseObject(GeneratorModelShape);
|
|
156
|
+
const F2pP2pVerifierShape = {
|
|
157
|
+
type: z.literal('f2p-p2p'),
|
|
158
|
+
failToPass: z.array(z.string().min(1)),
|
|
159
|
+
passToPass: z.array(z.string().min(1)),
|
|
160
|
+
evalSemanticsVersion: z.string().min(1),
|
|
161
|
+
};
|
|
162
|
+
const OtherVerifierShape = {
|
|
163
|
+
type: z.enum(['command', 'none']),
|
|
164
|
+
failToPass: z.array(z.string().min(1)).default([]),
|
|
165
|
+
passToPass: z.array(z.string().min(1)).default([]),
|
|
166
|
+
evalSemanticsVersion: z.string().min(1).optional(),
|
|
167
|
+
};
|
|
168
|
+
const VerifierWriteSchema = z.discriminatedUnion('type', [
|
|
169
|
+
z.strictObject(F2pP2pVerifierShape),
|
|
170
|
+
z.strictObject(OtherVerifierShape),
|
|
171
|
+
]);
|
|
172
|
+
const VerifierReadSchema = z.discriminatedUnion('type', [
|
|
173
|
+
z.looseObject(F2pP2pVerifierShape),
|
|
174
|
+
z.looseObject(OtherVerifierShape),
|
|
175
|
+
]);
|
|
176
|
+
const AttemptGroupShape = {
|
|
177
|
+
groupId: z.string().min(1),
|
|
178
|
+
attemptId: z.string().min(1),
|
|
179
|
+
relatedAttemptRefs: z.array(z.string().min(1)).default([]),
|
|
180
|
+
groupSize: z.number().int().positive().optional(),
|
|
181
|
+
nPass: z.number().int().nonnegative().optional(),
|
|
182
|
+
nFail: z.number().int().nonnegative().optional(),
|
|
183
|
+
};
|
|
184
|
+
function attemptGroupCountsMatch(group) {
|
|
185
|
+
return !(group.groupSize !== undefined
|
|
186
|
+
&& group.nPass !== undefined
|
|
187
|
+
&& group.nFail !== undefined
|
|
188
|
+
&& group.groupSize !== group.nPass + group.nFail);
|
|
189
|
+
}
|
|
190
|
+
const AttemptGroupWriteSchema = z.strictObject(AttemptGroupShape).superRefine((group, context) => {
|
|
191
|
+
if (!attemptGroupCountsMatch(group)) {
|
|
192
|
+
context.addIssue({
|
|
193
|
+
code: 'custom',
|
|
194
|
+
path: ['groupSize'],
|
|
195
|
+
message: 'groupSize must equal nPass + nFail when all counts are materialized',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
const AttemptGroupReadSchema = z.looseObject(AttemptGroupShape).superRefine((group, context) => {
|
|
200
|
+
if (!attemptGroupCountsMatch(group)) {
|
|
201
|
+
context.addIssue({
|
|
202
|
+
code: 'custom',
|
|
203
|
+
path: ['groupSize'],
|
|
204
|
+
message: 'groupSize must equal nPass + nFail when all counts are materialized',
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const CostShape = {
|
|
209
|
+
durationMs: z.number().int().nonnegative(),
|
|
210
|
+
tokens: z.strictObject({
|
|
211
|
+
input: z.number().int().nonnegative(),
|
|
212
|
+
output: z.number().int().nonnegative(),
|
|
213
|
+
}).optional(),
|
|
214
|
+
usdEstimate: z.string().regex(/^\d+(\.\d+)?$/).optional(),
|
|
215
|
+
};
|
|
216
|
+
const OriginStampSchema = z.strictObject({
|
|
217
|
+
writer: z.string().min(1),
|
|
218
|
+
build: z.string().min(1),
|
|
219
|
+
});
|
|
220
|
+
const OriginStampReadSchema = z.looseObject({
|
|
221
|
+
writer: z.string().min(1),
|
|
222
|
+
build: z.string().min(1),
|
|
223
|
+
});
|
|
224
|
+
const RetentionShape = {
|
|
225
|
+
policy: z.enum(['local-private', 'contribution-eligible']),
|
|
226
|
+
};
|
|
227
|
+
const LineageShape = {
|
|
228
|
+
episodeId: z.string().min(1),
|
|
229
|
+
mintRef: z.string().min(1).optional(),
|
|
230
|
+
};
|
|
231
|
+
function validateContributionAttachment(episode, context) {
|
|
232
|
+
const candidate = episode.contributionCandidate;
|
|
233
|
+
if (!candidate)
|
|
234
|
+
return;
|
|
235
|
+
if (episode.session.kind === 'host-internal') {
|
|
236
|
+
context.addIssue({
|
|
237
|
+
code: 'custom',
|
|
238
|
+
path: ['contributionCandidate'],
|
|
239
|
+
message: 'host-internal episodes cannot carry a contribution candidate',
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (candidate.sourceId !== episode.episodeId) {
|
|
243
|
+
context.addIssue({
|
|
244
|
+
code: 'custom',
|
|
245
|
+
path: ['contributionCandidate', 'sourceId'],
|
|
246
|
+
message: 'contribution candidate sourceId must match episodeId',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export const EpisodeV1WriteSchema = z.strictObject({
|
|
251
|
+
schemaVersion: z.literal(EPISODE_SCHEMA_VERSION),
|
|
252
|
+
episodeId: z.string().min(1),
|
|
253
|
+
/** W2 allowlist decision recorded in canonical content. The legacy
|
|
254
|
+
* `retrieval:visible.v1` distribution tag remains read-compatible. */
|
|
255
|
+
retrievalVisible: z.boolean().default(false),
|
|
256
|
+
session: z.strictObject(SessionShape),
|
|
257
|
+
origin: OriginStampSchema,
|
|
258
|
+
task: z.strictObject(TaskShape),
|
|
259
|
+
trajectory: z.array(StepWriteSchema).min(1),
|
|
260
|
+
environment: z.strictObject({
|
|
261
|
+
harness: z.strictObject({ name: z.string().min(1), version: z.string().min(1) }),
|
|
262
|
+
model: z.string().min(1),
|
|
263
|
+
tools: z.array(z.string().min(1)),
|
|
264
|
+
skillsLoadout: z.array(z.string().min(1)),
|
|
265
|
+
generatorModel: GeneratorModelWriteSchema.optional(),
|
|
266
|
+
distributionClass: z.enum(['open', 'restricted-tos', 'unknown']).optional(),
|
|
267
|
+
verifier: VerifierWriteSchema.optional(),
|
|
268
|
+
}),
|
|
269
|
+
outcome: OutcomeWriteSchema,
|
|
270
|
+
cost: z.strictObject(CostShape),
|
|
271
|
+
retention: z.strictObject(RetentionShape),
|
|
272
|
+
provenance: EpisodeProvenanceSchema.default('contributed'),
|
|
273
|
+
lineage: z.strictObject(LineageShape).optional(),
|
|
274
|
+
attemptGroup: AttemptGroupWriteSchema.optional(),
|
|
275
|
+
activity: SessionActivityFactsWriteSchema.optional(),
|
|
276
|
+
eligibility: EligibilityVerdictSchema.optional(),
|
|
277
|
+
/** Private local mining facts. Publication projections must omit this field. */
|
|
278
|
+
contributionCandidate: ContributionCandidateV1Schema.optional(),
|
|
279
|
+
}).superRefine(validateContributionAttachment);
|
|
280
|
+
function asRecord(value) {
|
|
281
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
282
|
+
? value
|
|
283
|
+
: undefined;
|
|
284
|
+
}
|
|
285
|
+
function withoutNulls(value, optionalKeys) {
|
|
286
|
+
const record = asRecord(value);
|
|
287
|
+
if (!record)
|
|
288
|
+
return value;
|
|
289
|
+
const normalized = { ...record };
|
|
290
|
+
for (const key of optionalKeys) {
|
|
291
|
+
if (normalized[key] === null)
|
|
292
|
+
delete normalized[key];
|
|
293
|
+
}
|
|
294
|
+
return normalized;
|
|
295
|
+
}
|
|
296
|
+
/** Additive v1 reader normalization. Writers never use this path. */
|
|
297
|
+
function normalizeEpisodeRead(value) {
|
|
298
|
+
const raw = asRecord(value);
|
|
299
|
+
if (!raw)
|
|
300
|
+
return value;
|
|
301
|
+
const normalized = { ...raw };
|
|
302
|
+
const session = asRecord(withoutNulls(raw['session'], ['parentSessionId']));
|
|
303
|
+
if (session)
|
|
304
|
+
normalized['session'] = { kind: 'user', ...session };
|
|
305
|
+
if (raw['origin'] === undefined) {
|
|
306
|
+
normalized['origin'] = 'legacy-unstamped';
|
|
307
|
+
}
|
|
308
|
+
normalized['task'] = withoutNulls(raw['task'], ['repositorySlug', 'baseCommit', 'createdAt', 'instanceId']);
|
|
309
|
+
if (Array.isArray(raw['trajectory'])) {
|
|
310
|
+
normalized['trajectory'] = raw['trajectory'].map((step) => withoutNulls(step, ['truncatedKeys']));
|
|
311
|
+
}
|
|
312
|
+
const environment = asRecord(withoutNulls(raw['environment'], ['generatorModel', 'distributionClass', 'verifier']));
|
|
313
|
+
if (environment) {
|
|
314
|
+
const cleanEnvironment = { ...environment };
|
|
315
|
+
const generatorModel = asRecord(withoutNulls(environment['generatorModel'], ['provider', 'openWeights']));
|
|
316
|
+
if (generatorModel)
|
|
317
|
+
cleanEnvironment['generatorModel'] = generatorModel;
|
|
318
|
+
const verifier = asRecord(withoutNulls(environment['verifier'], ['evalSemanticsVersion']));
|
|
319
|
+
if (verifier)
|
|
320
|
+
cleanEnvironment['verifier'] = verifier;
|
|
321
|
+
normalized['environment'] = cleanEnvironment;
|
|
322
|
+
}
|
|
323
|
+
normalized['outcome'] = normalizeOutcomeCompatibility(withoutNulls(raw['outcome'], ['summary', 'acceptedDiff', 'testRuns']));
|
|
324
|
+
normalized['cost'] = withoutNulls(raw['cost'], ['tokens', 'usdEstimate']);
|
|
325
|
+
for (const key of [
|
|
326
|
+
'lineage',
|
|
327
|
+
'attemptGroup',
|
|
328
|
+
'activity',
|
|
329
|
+
'eligibility',
|
|
330
|
+
'contributionCandidate',
|
|
331
|
+
]) {
|
|
332
|
+
if (normalized[key] === null)
|
|
333
|
+
delete normalized[key];
|
|
334
|
+
}
|
|
335
|
+
const lineage = asRecord(normalized['lineage']);
|
|
336
|
+
if (lineage)
|
|
337
|
+
normalized['lineage'] = withoutNulls(lineage, ['mintRef']);
|
|
338
|
+
const attemptGroup = asRecord(normalized['attemptGroup']);
|
|
339
|
+
if (attemptGroup) {
|
|
340
|
+
normalized['attemptGroup'] = withoutNulls(attemptGroup, ['groupSize', 'nPass', 'nFail']);
|
|
341
|
+
}
|
|
342
|
+
const activity = asRecord(normalized['activity']);
|
|
343
|
+
if (activity) {
|
|
344
|
+
const clean = asRecord(withoutNulls(activity, ['deliveredContentHash'])) ?? {};
|
|
345
|
+
const searchedTerms = clean['searchedTerms'] === undefined ? [] : clean['searchedTerms'];
|
|
346
|
+
const legacyProvided = clean['providedRefs'];
|
|
347
|
+
const deliveredRefs = clean['deliveredRefs'] === undefined
|
|
348
|
+
? legacyProvided === undefined ? [] : legacyProvided
|
|
349
|
+
: clean['deliveredRefs'];
|
|
350
|
+
const eligibleRefs = clean['eligibleRefs'] === undefined
|
|
351
|
+
? deliveredRefs
|
|
352
|
+
: clean['eligibleRefs'];
|
|
353
|
+
const retrievalFired = clean['retrievalFired'] !== undefined
|
|
354
|
+
? clean['retrievalFired']
|
|
355
|
+
: (Array.isArray(searchedTerms) && searchedTerms.length > 0)
|
|
356
|
+
|| (Array.isArray(deliveredRefs) && deliveredRefs.length > 0);
|
|
357
|
+
normalized['activity'] = {
|
|
358
|
+
...clean,
|
|
359
|
+
searchedTerms,
|
|
360
|
+
providedRefs: legacyProvided === undefined ? deliveredRefs : legacyProvided,
|
|
361
|
+
surfacedRefs: clean['surfacedRefs'] === undefined ? [] : clean['surfacedRefs'],
|
|
362
|
+
fetchedRefs: clean['fetchedRefs'] === undefined ? [] : clean['fetchedRefs'],
|
|
363
|
+
installedSkillRefs: clean['installedSkillRefs'] === undefined
|
|
364
|
+
? []
|
|
365
|
+
: clean['installedSkillRefs'],
|
|
366
|
+
retrievalFired,
|
|
367
|
+
eligibleRefs,
|
|
368
|
+
deliveredRefs,
|
|
369
|
+
deliveryMode: clean['deliveryMode'] === undefined
|
|
370
|
+
? (retrievalFired === true ? 'delivered' : 'disabled')
|
|
371
|
+
: clean['deliveryMode'],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
return normalized;
|
|
375
|
+
}
|
|
376
|
+
const SessionActivityFactsReadSchema = z.looseObject({
|
|
377
|
+
...LegacyActivityShape,
|
|
378
|
+
...DeliveryActivityShape,
|
|
379
|
+
});
|
|
380
|
+
export const SessionActivityFactsSchema = z.preprocess((value) => {
|
|
381
|
+
const wrapper = normalizeEpisodeRead({
|
|
382
|
+
schemaVersion: EPISODE_SCHEMA_VERSION,
|
|
383
|
+
episodeId: 'activity-reader',
|
|
384
|
+
session: { sessionId: 'activity-reader', capturedAt: '1970-01-01T00:00:00.000Z' },
|
|
385
|
+
task: { summary: 'activity reader', distributionTags: [] },
|
|
386
|
+
trajectory: [{
|
|
387
|
+
spanId: 'activity-reader',
|
|
388
|
+
parentSpanId: null,
|
|
389
|
+
kind: 'jinn.agent_turn',
|
|
390
|
+
name: 'activity-reader',
|
|
391
|
+
startTimeUnixNano: '0',
|
|
392
|
+
endTimeUnixNano: '0',
|
|
393
|
+
attributes: {},
|
|
394
|
+
redactedKeys: [],
|
|
395
|
+
}],
|
|
396
|
+
environment: {
|
|
397
|
+
harness: { name: 'activity-reader', version: '1' },
|
|
398
|
+
model: 'activity-reader',
|
|
399
|
+
tools: [],
|
|
400
|
+
skillsLoadout: [],
|
|
401
|
+
},
|
|
402
|
+
outcome: { status: 'completed', verificationStrength: 'user-accepted' },
|
|
403
|
+
cost: { durationMs: 0 },
|
|
404
|
+
retention: { policy: 'local-private' },
|
|
405
|
+
activity: value,
|
|
406
|
+
});
|
|
407
|
+
return wrapper['activity'];
|
|
408
|
+
}, SessionActivityFactsReadSchema);
|
|
409
|
+
const EpisodeV1ReadObjectSchema = z.looseObject({
|
|
410
|
+
schemaVersion: z.literal(EPISODE_SCHEMA_VERSION),
|
|
411
|
+
episodeId: z.string().min(1),
|
|
412
|
+
retrievalVisible: z.boolean().default(false),
|
|
413
|
+
session: z.looseObject(SessionShape),
|
|
414
|
+
origin: z.union([OriginStampReadSchema, z.literal('legacy-unstamped')]),
|
|
415
|
+
task: z.looseObject(TaskShape),
|
|
416
|
+
trajectory: z.array(StepReadSchema).min(1),
|
|
417
|
+
environment: z.looseObject({
|
|
418
|
+
harness: z.looseObject({ name: z.string().min(1), version: z.string().min(1) }),
|
|
419
|
+
model: z.string().min(1),
|
|
420
|
+
tools: z.array(z.string().min(1)),
|
|
421
|
+
skillsLoadout: z.array(z.string().min(1)),
|
|
422
|
+
generatorModel: GeneratorModelReadSchema.optional(),
|
|
423
|
+
distributionClass: z.enum(['open', 'restricted-tos', 'unknown']).optional(),
|
|
424
|
+
verifier: VerifierReadSchema.optional(),
|
|
425
|
+
}),
|
|
426
|
+
outcome: z.looseObject({
|
|
427
|
+
...OutcomeShape,
|
|
428
|
+
testRuns: z.looseObject({
|
|
429
|
+
passed: z.number().int().nonnegative(),
|
|
430
|
+
failed: z.number().int().nonnegative(),
|
|
431
|
+
}).optional(),
|
|
432
|
+
}),
|
|
433
|
+
cost: z.looseObject({
|
|
434
|
+
...CostShape,
|
|
435
|
+
tokens: z.looseObject({
|
|
436
|
+
input: z.number().int().nonnegative(),
|
|
437
|
+
output: z.number().int().nonnegative(),
|
|
438
|
+
}).optional(),
|
|
439
|
+
}),
|
|
440
|
+
retention: z.looseObject(RetentionShape),
|
|
441
|
+
provenance: EpisodeProvenanceSchema.default('contributed'),
|
|
442
|
+
lineage: z.looseObject(LineageShape).optional(),
|
|
443
|
+
attemptGroup: AttemptGroupReadSchema.optional(),
|
|
444
|
+
activity: SessionActivityFactsReadSchema.optional(),
|
|
445
|
+
eligibility: z.looseObject({
|
|
446
|
+
eligible: z.boolean(),
|
|
447
|
+
reason: z.string().min(1),
|
|
448
|
+
checkedAt: z.iso.datetime(),
|
|
449
|
+
}).optional(),
|
|
450
|
+
contributionCandidate: ContributionCandidateV1ReadSchema.optional(),
|
|
451
|
+
}).superRefine(validateContributionAttachment);
|
|
452
|
+
export const EpisodeV1Schema = z.preprocess(normalizeEpisodeRead, EpisodeV1ReadObjectSchema);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** One derived-view row (product design §4.5). Owns no facts — computed from Evidence + Contribution + LocalLearning. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const HistoryEntrySchema: z.ZodObject<{
|
|
4
|
+
sessionId: z.ZodString;
|
|
5
|
+
capturedAt: z.ZodISODateTime;
|
|
6
|
+
taskSummary: z.ZodString;
|
|
7
|
+
knowledgeSurfaced: z.ZodNullable<z.ZodNumber>;
|
|
8
|
+
knowledgeUsed: z.ZodNullable<z.ZodNumber>;
|
|
9
|
+
captureStatus: z.ZodEnum<{
|
|
10
|
+
captured: "captured";
|
|
11
|
+
"not-captured": "not-captured";
|
|
12
|
+
}>;
|
|
13
|
+
eligibility: z.ZodNullable<z.ZodObject<{
|
|
14
|
+
eligible: z.ZodBoolean;
|
|
15
|
+
reason: z.ZodString;
|
|
16
|
+
checkedAt: z.ZodISODateTime;
|
|
17
|
+
}, z.core.$strict>>;
|
|
18
|
+
contributionState: z.ZodObject<{
|
|
19
|
+
status: z.ZodEnum<{
|
|
20
|
+
unavailable: "unavailable";
|
|
21
|
+
recorded: "recorded";
|
|
22
|
+
minted: "minted";
|
|
23
|
+
rejected: "rejected";
|
|
24
|
+
"preview-required": "preview-required";
|
|
25
|
+
queued: "queued";
|
|
26
|
+
published: "published";
|
|
27
|
+
vetoed: "vetoed";
|
|
28
|
+
none: "none";
|
|
29
|
+
}>;
|
|
30
|
+
anchorRef: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
distilledSkills: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
33
|
+
ref: z.ZodString;
|
|
34
|
+
state: z.ZodEnum<{
|
|
35
|
+
staged: "staged";
|
|
36
|
+
installed: "installed";
|
|
37
|
+
}>;
|
|
38
|
+
}, z.core.$strict>>>;
|
|
39
|
+
}, z.core.$strict>;
|
|
40
|
+
export type HistoryEntry = z.infer<typeof HistoryEntrySchema>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** One derived-view row (product design §4.5). Owns no facts — computed from Evidence + Contribution + LocalLearning. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { EligibilityVerdictSchema } from './eligibility-verdict.js';
|
|
4
|
+
export const HistoryEntrySchema = z.strictObject({
|
|
5
|
+
sessionId: z.string().min(1),
|
|
6
|
+
capturedAt: z.iso.datetime(),
|
|
7
|
+
taskSummary: z.string().min(1),
|
|
8
|
+
knowledgeSurfaced: z.number().int().nonnegative().nullable(),
|
|
9
|
+
knowledgeUsed: z.number().int().nonnegative().nullable(),
|
|
10
|
+
captureStatus: z.enum(['captured', 'not-captured']),
|
|
11
|
+
eligibility: EligibilityVerdictSchema.nullable(),
|
|
12
|
+
contributionState: z.strictObject({
|
|
13
|
+
status: z.enum([
|
|
14
|
+
'none',
|
|
15
|
+
'recorded',
|
|
16
|
+
'minted',
|
|
17
|
+
'rejected',
|
|
18
|
+
'preview-required',
|
|
19
|
+
'queued',
|
|
20
|
+
'published',
|
|
21
|
+
'vetoed',
|
|
22
|
+
'unavailable',
|
|
23
|
+
]),
|
|
24
|
+
anchorRef: z.string().min(1).optional(),
|
|
25
|
+
}),
|
|
26
|
+
distilledSkills: z.array(z.strictObject({
|
|
27
|
+
ref: z.string().min(1),
|
|
28
|
+
state: z.enum(['staged', 'installed']),
|
|
29
|
+
})).nullable(),
|
|
30
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Evidence-first corpus search metadata (Stage 1 rescope §§3.1, 3.3). */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const KnowledgeHitSchema: z.ZodObject<{
|
|
4
|
+
ref: z.ZodString;
|
|
5
|
+
kind: z.ZodEnum<{
|
|
6
|
+
seed: "seed";
|
|
7
|
+
trace: "trace";
|
|
8
|
+
skill: "skill";
|
|
9
|
+
}>;
|
|
10
|
+
title: z.ZodOptional<z.ZodString>;
|
|
11
|
+
snippet: z.ZodOptional<z.ZodString>;
|
|
12
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
13
|
+
tier: z.ZodOptional<z.ZodEnum<{
|
|
14
|
+
"user-accepted": "user-accepted";
|
|
15
|
+
"tests-passed": "tests-passed";
|
|
16
|
+
"evaluator-verified": "evaluator-verified";
|
|
17
|
+
}>>;
|
|
18
|
+
payloadKind: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
unknown: "unknown";
|
|
20
|
+
skill: "skill";
|
|
21
|
+
}>>;
|
|
22
|
+
tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
23
|
+
origin: z.ZodOptional<z.ZodString>;
|
|
24
|
+
publishedAt: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
retrievalVisible: z.ZodOptional<z.ZodBoolean>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type KnowledgeHit = z.infer<typeof KnowledgeHitSchema>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Evidence-first corpus search metadata (Stage 1 rescope §§3.1, 3.3). */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { TIER_ORDER } from './pickup-config.js';
|
|
4
|
+
export const KnowledgeHitSchema = z.strictObject({
|
|
5
|
+
ref: z.string().min(1),
|
|
6
|
+
kind: z.enum(['seed', 'trace', 'skill']),
|
|
7
|
+
title: z.string().min(1).optional(),
|
|
8
|
+
snippet: z.string().min(1).optional(),
|
|
9
|
+
score: z.number().min(0).max(1).optional(),
|
|
10
|
+
tier: z.enum(TIER_ORDER).optional(),
|
|
11
|
+
payloadKind: z.enum(['skill', 'unknown']).optional(),
|
|
12
|
+
/** Distribution tags — scored alongside `snippet` by the evidence-first selection policy (rescope §3.3). */
|
|
13
|
+
tags: z.array(z.string().min(1)).default([]),
|
|
14
|
+
/** Trustworthy content-dedup identity: on-chain agentId when known, otherwise
|
|
15
|
+
* the record ref. Never a manifest-supplied safeAddress. */
|
|
16
|
+
origin: z.string().min(1).optional(),
|
|
17
|
+
/** Unix-ms publish time — the selection policy's recency tiebreaker (rescope §3.3). */
|
|
18
|
+
publishedAt: z.number().int().nonnegative().optional(),
|
|
19
|
+
/** Computed by the adapter from the wire hit's tags (issue #1824) — presence
|
|
20
|
+
* of RETRIEVAL_VISIBLE_TAG. Absent = treat as not visible (fail-closed at
|
|
21
|
+
* ranking). */
|
|
22
|
+
retrievalVisible: z.boolean().optional(),
|
|
23
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `jinn.knowledge-packet.v1` — the unit of evidence supplied to the agent
|
|
3
|
+
* (rescope design §3.2). A versioned, pure, deterministic projection of a
|
|
4
|
+
* `CorpusRecord`: presentation-only, re-derivable at any time, never stored
|
|
5
|
+
* as new truth.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { CorpusRecord } from '../ports/corpus-port.js';
|
|
9
|
+
export declare const KNOWLEDGE_PACKET_SCHEMA_VERSION: "jinn.knowledge-packet.v1";
|
|
10
|
+
export declare const KnowledgePacketExcerptSchema: z.ZodObject<{
|
|
11
|
+
label: z.ZodEnum<{
|
|
12
|
+
command: "command";
|
|
13
|
+
failure: "failure";
|
|
14
|
+
fix: "fix";
|
|
15
|
+
diff: "diff";
|
|
16
|
+
note: "note";
|
|
17
|
+
}>;
|
|
18
|
+
text: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export declare const KnowledgePacketSchema: z.ZodObject<{
|
|
21
|
+
schemaVersion: z.ZodLiteral<"jinn.knowledge-packet.v1">;
|
|
22
|
+
ref: z.ZodString;
|
|
23
|
+
task: z.ZodObject<{
|
|
24
|
+
summary: z.ZodString;
|
|
25
|
+
repositorySlug: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
outcome: z.ZodObject<{
|
|
28
|
+
status: z.ZodEnum<{
|
|
29
|
+
completed: "completed";
|
|
30
|
+
failed: "failed";
|
|
31
|
+
abandoned: "abandoned";
|
|
32
|
+
}>;
|
|
33
|
+
verifiabilityTier: z.ZodEnum<{
|
|
34
|
+
"user-accepted": "user-accepted";
|
|
35
|
+
"tests-passed": "tests-passed";
|
|
36
|
+
"evaluator-verified": "evaluator-verified";
|
|
37
|
+
}>;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
synthesis: z.ZodOptional<z.ZodString>;
|
|
40
|
+
excerpts: z.ZodArray<z.ZodObject<{
|
|
41
|
+
label: z.ZodEnum<{
|
|
42
|
+
command: "command";
|
|
43
|
+
failure: "failure";
|
|
44
|
+
fix: "fix";
|
|
45
|
+
diff: "diff";
|
|
46
|
+
note: "note";
|
|
47
|
+
}>;
|
|
48
|
+
text: z.ZodString;
|
|
49
|
+
}, z.core.$strict>>;
|
|
50
|
+
attribution: z.ZodObject<{
|
|
51
|
+
provenance: z.ZodEnum<{
|
|
52
|
+
contributed: "contributed";
|
|
53
|
+
imported: "imported";
|
|
54
|
+
"derived-from-history": "derived-from-history";
|
|
55
|
+
}>;
|
|
56
|
+
capturedAt: z.ZodISODateTime;
|
|
57
|
+
origin: z.ZodString;
|
|
58
|
+
}, z.core.$strict>;
|
|
59
|
+
}, z.core.$strict>;
|
|
60
|
+
export type KnowledgePacket = z.infer<typeof KnowledgePacketSchema>;
|
|
61
|
+
export type KnowledgePacketExcerpt = z.infer<typeof KnowledgePacketExcerptSchema>;
|
|
62
|
+
export declare const DEFAULT_PACKET_CHAR_BUDGET = 3500;
|
|
63
|
+
export interface KnowledgePacketBudget {
|
|
64
|
+
/** Max combined chars across synthesis + excerpt text. Default 3,500 (rescope §3.5). */
|
|
65
|
+
maxChars?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Line-boundary-aware truncation ending with an explicit, pointer-bearing
|
|
69
|
+
* tail. Returns an empty string when the budget cannot fit both meaningful
|
|
70
|
+
* source text and the complete tail.
|
|
71
|
+
*/
|
|
72
|
+
export declare function truncateLineBoundary(text: string, maxChars: number, ref: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Pure deterministic projection of a `CorpusRecord` into a `KnowledgePacket`
|
|
75
|
+
* (rescope §3.2). Selects and truncates; never paraphrases. Enforces the
|
|
76
|
+
* combined synthesis+excerpts char budget (default 3,500 — two packets at the
|
|
77
|
+
* default budget total 7,000, satisfying §3.5's combined ceiling).
|
|
78
|
+
*/
|
|
79
|
+
export declare function projectKnowledgePacket(record: CorpusRecord, budget?: KnowledgePacketBudget): KnowledgePacket;
|