@evomap/evolver-core 2.0.0-beta.2 → 2.0.0-beta.22
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/assets/gep/genes.jsonl +5 -5
- package/dist/algo/bans.d.ts +10 -1
- package/dist/algo/bans.js +56 -6
- package/dist/algo/candidateAssembly.d.ts +25 -2
- package/dist/algo/candidateAssembly.js +171 -26
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/conversationSniffer.js +25 -8
- package/dist/algo/cycleEngine.d.ts +63 -5
- package/dist/algo/cycleEngine.js +320 -42
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/evolutionEvent.d.ts +26 -0
- package/dist/algo/evolutionEvent.js +32 -0
- package/dist/algo/exploration.d.ts +7 -0
- package/dist/algo/exploration.js +16 -3
- package/dist/algo/geneHealth.d.ts +36 -3
- package/dist/algo/geneHealth.js +47 -4
- package/dist/algo/geneIntake.d.ts +46 -1
- package/dist/algo/geneIntake.js +121 -10
- package/dist/algo/geneSelection.d.ts +126 -6
- package/dist/algo/geneSelection.js +479 -36
- package/dist/algo/index.d.ts +6 -1
- package/dist/algo/index.js +6 -1
- package/dist/algo/kautoProjection.d.ts +41 -0
- package/dist/algo/kautoProjection.js +95 -0
- package/dist/algo/kautoValidator.d.ts +68 -0
- package/dist/algo/kautoValidator.js +256 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +17 -1
- package/dist/algo/orchestrator.js +30 -4
- package/dist/algo/publishEligibility.d.ts +34 -0
- package/dist/algo/publishEligibility.js +52 -0
- package/dist/algo/solidify.d.ts +11 -2
- package/dist/algo/solidify.js +37 -7
- package/dist/algo/ucb1.d.ts +53 -0
- package/dist/algo/ucb1.js +156 -0
- package/dist/assetrepair/hubRejection.d.ts +12 -0
- package/dist/assetrepair/hubRejection.js +109 -0
- package/dist/assetrepair/index.d.ts +2 -0
- package/dist/assetrepair/index.js +2 -0
- package/dist/assetrepair/repair.d.ts +33 -0
- package/dist/assetrepair/repair.js +155 -0
- package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
- package/dist/assetstore/assetSidecarRecords.js +384 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +81 -0
- package/dist/assetstore/assetStoreHealth.js +319 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +336 -0
- package/dist/assetstore/assetSyncLedger.d.ts +91 -1
- package/dist/assetstore/assetSyncLedger.js +718 -59
- package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
- package/dist/assetstore/foreignJsonlSource.js +150 -0
- package/dist/assetstore/index.d.ts +5 -0
- package/dist/assetstore/index.js +5 -0
- package/dist/assetstore/learningHistory.js +3 -3
- package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
- package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
- package/dist/assetstore/localJsonl.d.ts +12 -1
- package/dist/assetstore/localJsonl.js +251 -42
- package/dist/assetstore/provenance.d.ts +93 -4
- package/dist/assetstore/provenance.js +368 -84
- package/dist/assetstore/provider.d.ts +63 -0
- package/dist/assetstore/provider.js +97 -6
- package/dist/assetstore/reviewFilter.d.ts +19 -1
- package/dist/assetstore/reviewFilter.js +39 -1
- package/dist/assetstore/reviewLedger.d.ts +8 -2
- package/dist/assetstore/reviewLedger.js +71 -45
- package/dist/assetstore/unionReadStore.d.ts +25 -0
- package/dist/assetstore/unionReadStore.js +119 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +4 -3
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +4 -3
- package/dist/benchmark/index.d.ts +3 -1
- package/dist/benchmark/index.js +3 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +3 -1
- package/dist/bootstrap/index.js +3 -1
- package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
- package/dist/bootstrap/lifecycleBootstrap.js +433 -0
- package/dist/bootstrap/v1EnvCompat.d.ts +113 -0
- package/dist/bootstrap/v1EnvCompat.js +303 -0
- package/dist/events/eventArchive.d.ts +2 -0
- package/dist/events/eventArchive.js +13 -3
- package/dist/events/eventSchema.d.ts +7 -7
- package/dist/events/eventStore.d.ts +2 -0
- package/dist/events/eventStore.js +5 -1
- package/dist/events/ingest.d.ts +2 -1
- package/dist/events/ingest.js +15 -0
- package/dist/events/paths.d.ts +12 -10
- package/dist/events/paths.js +24 -20
- package/dist/events/public.d.ts +2 -2
- package/dist/events/public.js +2 -2
- package/dist/events/reports.d.ts +2 -0
- package/dist/events/reports.js +4 -0
- package/dist/exec/autoExec.d.ts +68 -4
- package/dist/exec/autoExec.js +392 -33
- package/dist/exec/autonomousCycle.d.ts +31 -4
- package/dist/exec/autonomousCycle.js +71 -13
- package/dist/exec/claudeBridge.d.ts +80 -15
- package/dist/exec/claudeBridge.js +845 -76
- package/dist/exec/executionBinding.d.ts +414 -0
- package/dist/exec/executionBinding.js +588 -0
- package/dist/exec/index.d.ts +1 -0
- package/dist/exec/index.js +1 -0
- package/dist/exec/openPrRegistry.d.ts +8 -2
- package/dist/exec/openPrRegistry.js +32 -22
- package/dist/exec/prompt.js +14 -1
- package/dist/exec/proofOfWork.d.ts +1 -1
- package/dist/exec/proofOfWork.js +2 -2
- package/dist/exec/runnerRegistry.d.ts +153 -36
- package/dist/exec/runnerRegistry.js +848 -65
- package/dist/exec/selfPr.js +1 -7
- package/dist/feedback/envelope.d.ts +61 -0
- package/dist/feedback/envelope.js +168 -0
- package/dist/feedback/index.d.ts +1 -0
- package/dist/feedback/index.js +1 -0
- package/dist/hooks/hooks.js +1 -0
- package/dist/hub/assetCallLog.d.ts +35 -1
- package/dist/hub/assetCallLog.js +124 -1
- package/dist/hub/bindings.d.ts +8 -1
- package/dist/hub/bindings.js +29 -8
- package/dist/hub/capability.d.ts +130 -4
- package/dist/hub/conversationDistiller.d.ts +19 -0
- package/dist/hub/conversationDistiller.js +115 -37
- package/dist/hub/fake.d.ts +3 -2
- package/dist/hub/fake.js +2 -1
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/questionGenerator.d.ts +5 -1
- package/dist/hub/questionGenerator.js +8 -6
- package/dist/hub/recipeCompose.d.ts +27 -0
- package/dist/hub/recipeCompose.js +90 -0
- package/dist/hub/sanitize.js +122 -7
- package/dist/index.d.ts +6 -1
- package/dist/index.js +7 -1
- package/dist/issueReporter/index.d.ts +156 -0
- package/dist/issueReporter/index.js +1688 -0
- package/dist/mailbox/dispatch.d.ts +1 -1
- package/dist/mailbox/dispatch.js +22 -6
- package/dist/mailbox/envelope.d.ts +7 -1
- package/dist/mailbox/envelope.js +9 -2
- package/dist/mailbox/ipcServer.d.ts +12 -2
- package/dist/mailbox/ipcServer.js +183 -13
- package/dist/mailbox/store.d.ts +89 -3
- package/dist/mailbox/store.js +895 -41
- package/dist/modelCompatibility.d.ts +164 -0
- package/dist/modelCompatibility.js +309 -0
- package/dist/observers/valueDigestObserver.d.ts +9 -0
- package/dist/observers/valueDigestObserver.js +35 -2
- package/dist/ops/cleanup.js +1 -1
- package/dist/ops/evolutionGraphProjection.d.ts +20 -0
- package/dist/ops/evolutionGraphProjection.js +315 -0
- package/dist/ops/index.d.ts +2 -1
- package/dist/ops/index.js +2 -1
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +18 -1
- package/dist/ops/selfUpdate.js +88 -23
- package/dist/ops/valueOutreach.d.ts +3 -1
- package/dist/ops/valueOutreach.js +5 -1
- package/dist/personality/schema.d.ts +24 -24
- package/dist/schema/evolutionGraph.d.ts +784 -0
- package/dist/schema/evolutionGraph.js +187 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/proofOfWork.d.ts +125 -6
- package/dist/schema/proofOfWork.js +102 -4
- package/dist/schema/signal.d.ts +3 -3
- package/dist/schema/signal.js +1 -1
- package/dist/shadow/shadowHub.js +1 -0
- package/dist/signals/curriculum.d.ts +55 -0
- package/dist/signals/curriculum.js +202 -0
- package/dist/signals/cycleHistoryFromEvents.js +17 -8
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +169 -1
- package/dist/signals/extractor.d.ts +2 -2
- package/dist/signals/extractor.js +31 -6
- package/dist/signals/index.d.ts +4 -1
- package/dist/signals/index.js +4 -1
- package/dist/signals/metaSignals.d.ts +4 -0
- package/dist/signals/metaSignals.js +42 -0
- package/dist/signals/scopeVocabulary.d.ts +75 -0
- package/dist/signals/scopeVocabulary.js +91 -0
- package/dist/signals/signalGate.js +1 -1
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/strategy/constraintAblation.d.ts +64 -0
- package/dist/strategy/constraintAblation.js +2820 -0
- package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
- package/dist/strategy/constraintAblationPredicates.js +339 -0
- package/dist/strategy/index.d.ts +2 -1
- package/dist/strategy/index.js +2 -1
- package/dist/trace/index.d.ts +3 -1
- package/dist/trace/index.js +3 -1
- package/dist/trace/learningTrace.d.ts +216 -0
- package/dist/trace/learningTrace.js +298 -0
- package/dist/trace/proxyTurns.d.ts +31 -0
- package/dist/trace/proxyTurns.js +137 -0
- package/dist/trace/trajectory.d.ts +8 -0
- package/dist/trace/trajectory.js +14 -2
- package/dist/util/fetchPort.d.ts +1 -0
- package/dist/util/fetchPort.js +11 -0
- package/dist/util/fileLock.d.ts +113 -7
- package/dist/util/fileLock.js +1035 -80
- package/dist/util/index.d.ts +3 -1
- package/dist/util/index.js +2 -1
- package/dist/verify/index.d.ts +2 -1
- package/dist/verify/index.js +1 -1
- package/dist/verify/sandboxRunner.d.ts +30 -0
- package/dist/verify/sandboxRunner.js +370 -27
- package/dist/verify/sandboxedValidation.d.ts +16 -2
- package/dist/verify/sandboxedValidation.js +200 -22
- package/dist/verify/validation.d.ts +35 -4
- package/dist/verify/validation.js +164 -16
- package/dist/wire/geneHints.d.ts +88 -16
- package/dist/wire/geneHints.js +124 -15
- package/dist/wire/index.d.ts +8 -3
- package/dist/wire/index.js +2 -2
- package/dist/wire/schemaGate.d.ts +21 -0
- package/dist/wire/schemaGate.js +119 -10
- package/dist/workflow/dsl.d.ts +24 -3
- package/dist/workflow/dsl.js +4 -0
- package/dist/workflow/engine.d.ts +5 -1
- package/dist/workflow/engine.js +3 -0
- package/dist/workflow/index.d.ts +3 -1
- package/dist/workflow/index.js +3 -1
- package/dist/workflow/runtime.d.ts +110 -0
- package/dist/workflow/runtime.js +1298 -0
- package/dist/workflow/stateStore.d.ts +172 -0
- package/dist/workflow/stateStore.js +1044 -0
- package/package.json +12 -4
package/dist/hub/capability.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface PublishReceipt {
|
|
|
16
16
|
assetIds?: string[];
|
|
17
17
|
/** 终态标记: true=不可重试(reject/quarantine/402), SyncEngine 不得 incrementRetry(money-safety risk). */
|
|
18
18
|
terminal?: boolean;
|
|
19
|
+
/** Adapter-owned structured rejection metadata; callers must not infer policy from free-form `reason`. */
|
|
20
|
+
rejection?: {
|
|
21
|
+
code: 'invalid_request' | 'credit_shortage' | 'node_unauthorized' | 'not_found' | 'duplicate' | 'invalid_payload' | 'cooldown' | 'hub_rejected';
|
|
22
|
+
retryAfterMs?: number;
|
|
23
|
+
};
|
|
19
24
|
/** M8-1: 公版经济侧只读回执(core 不解释经济语义, 仅透传供观测/UI). private hub 多为空. */
|
|
20
25
|
economic?: {
|
|
21
26
|
creditShortage?: boolean;
|
|
@@ -25,6 +30,10 @@ export interface PublishReceipt {
|
|
|
25
30
|
gdiScore?: number;
|
|
26
31
|
};
|
|
27
32
|
}
|
|
33
|
+
export interface PublishOptions {
|
|
34
|
+
/** Stable, non-blank per logical publish so adapters can make transport retries idempotent. */
|
|
35
|
+
idempotencyKey?: string;
|
|
36
|
+
}
|
|
28
37
|
/** 资产查询. 复用 assetstore SearchQuery, 不发明第二套查询 DSL. */
|
|
29
38
|
export type HubQuery = SearchQuery;
|
|
30
39
|
/** task 子系统事件(订阅流元素). 公版含经济上下文(bounty/credit), 私有仅 workflow. */
|
|
@@ -111,6 +120,75 @@ export interface ReuseResultReceipt {
|
|
|
111
120
|
reason?: string;
|
|
112
121
|
id?: string;
|
|
113
122
|
}
|
|
123
|
+
export type LearningAssetType = 'memory' | 'skill' | 'playbook' | 'eval';
|
|
124
|
+
export type LearningAssetStatus = 'pending_review' | 'active' | 'disabled' | 'stale' | 'archived';
|
|
125
|
+
export type LearningAssetEffectiveStatus = LearningAssetStatus | 'expired';
|
|
126
|
+
export type LearningAssetUsageOutcome = ReuseResultOutcome;
|
|
127
|
+
export interface LearningAssetOwner {
|
|
128
|
+
node_id?: string | null;
|
|
129
|
+
user_id?: string | null;
|
|
130
|
+
org_id?: string | null;
|
|
131
|
+
workspace_id?: string | null;
|
|
132
|
+
}
|
|
133
|
+
/** Hub-owned learning asset record. Core keeps it opaque; adapters own wire shape and auth. */
|
|
134
|
+
export interface LearningAssetRecord {
|
|
135
|
+
asset_id: string;
|
|
136
|
+
type: LearningAssetType;
|
|
137
|
+
source_packet_id?: string;
|
|
138
|
+
scope?: string[];
|
|
139
|
+
owner?: LearningAssetOwner;
|
|
140
|
+
title?: string;
|
|
141
|
+
summary?: string;
|
|
142
|
+
confidence?: number;
|
|
143
|
+
last_used_at?: string | null;
|
|
144
|
+
usage_count?: number;
|
|
145
|
+
success_count?: number;
|
|
146
|
+
success_rate?: number;
|
|
147
|
+
expires_at?: string | null;
|
|
148
|
+
conflicts_with?: string[];
|
|
149
|
+
status?: LearningAssetStatus;
|
|
150
|
+
effective_status?: LearningAssetEffectiveStatus;
|
|
151
|
+
status_reason?: string;
|
|
152
|
+
provenance?: Record<string, unknown>;
|
|
153
|
+
payload?: Record<string, unknown>;
|
|
154
|
+
created_at?: string | null;
|
|
155
|
+
updated_at?: string | null;
|
|
156
|
+
[k: string]: unknown;
|
|
157
|
+
}
|
|
158
|
+
export interface LearningAssetListOptions {
|
|
159
|
+
type?: LearningAssetType;
|
|
160
|
+
scope?: readonly string[];
|
|
161
|
+
status?: LearningAssetStatus | readonly LearningAssetStatus[];
|
|
162
|
+
includeExpired?: boolean;
|
|
163
|
+
includePayload?: boolean;
|
|
164
|
+
limit?: number;
|
|
165
|
+
}
|
|
166
|
+
export interface LearningAssetListResult {
|
|
167
|
+
assets: LearningAssetRecord[];
|
|
168
|
+
limit: number;
|
|
169
|
+
reason?: string;
|
|
170
|
+
}
|
|
171
|
+
export interface LearningAssetUsageReport {
|
|
172
|
+
assetId?: string;
|
|
173
|
+
usedAssetIds?: readonly string[];
|
|
174
|
+
outcome: LearningAssetUsageOutcome;
|
|
175
|
+
score?: number;
|
|
176
|
+
sourceEventId: string;
|
|
177
|
+
reason?: string;
|
|
178
|
+
}
|
|
179
|
+
export interface LearningAssetUsageResultRow {
|
|
180
|
+
asset_id: string;
|
|
181
|
+
recorded: boolean;
|
|
182
|
+
duplicated?: boolean;
|
|
183
|
+
error?: string;
|
|
184
|
+
[k: string]: unknown;
|
|
185
|
+
}
|
|
186
|
+
/** Learning-asset usage reporting is best-effort; failures must not break runtime solve paths. */
|
|
187
|
+
export interface LearningAssetUsageReceipt {
|
|
188
|
+
recorded: boolean;
|
|
189
|
+
reason?: string;
|
|
190
|
+
results: LearningAssetUsageResultRow[];
|
|
191
|
+
}
|
|
114
192
|
/**
|
|
115
193
|
* Pre-publish dry-run result. The hub runs the same hub-side quality + content-safety
|
|
116
194
|
* gate as publish but stores nothing and charges no credits, so an agent can check a
|
|
@@ -141,6 +219,10 @@ export interface RecipeCreateRequest {
|
|
|
141
219
|
pricePerExecution?: number;
|
|
142
220
|
currency?: string;
|
|
143
221
|
maxConcurrent?: number;
|
|
222
|
+
idempotencyKey?: string;
|
|
223
|
+
}
|
|
224
|
+
export interface RecipePublishOptions {
|
|
225
|
+
idempotencyKey?: string;
|
|
144
226
|
}
|
|
145
227
|
export interface RecipeReceipt {
|
|
146
228
|
recipeId?: string;
|
|
@@ -156,14 +238,29 @@ export interface RecipeExpressRequest {
|
|
|
156
238
|
export interface RecipeExpressionReceipt extends RecipeReceipt {
|
|
157
239
|
organismId?: string;
|
|
158
240
|
}
|
|
241
|
+
/** Search/list published recipes. Empty `q` is valid; adapters may fall through to list. */
|
|
242
|
+
export interface RecipeSearchRequest {
|
|
243
|
+
q?: string;
|
|
244
|
+
limit?: number;
|
|
245
|
+
cursor?: string;
|
|
246
|
+
sort?: string;
|
|
247
|
+
}
|
|
248
|
+
export interface RecipeSearchReceipt {
|
|
249
|
+
recipes: unknown[];
|
|
250
|
+
nextCursor?: string;
|
|
251
|
+
hasMore?: boolean;
|
|
252
|
+
raw: unknown;
|
|
253
|
+
}
|
|
159
254
|
/** Optional Hub recipe/DNA capability. Core stays wire-agnostic; adapters own REST shape. */
|
|
160
255
|
export interface RecipeCapability {
|
|
161
256
|
create(request: RecipeCreateRequest): Promise<RecipeReceipt>;
|
|
162
|
-
publish(recipeId: string): Promise<RecipeReceipt>;
|
|
257
|
+
publish(recipeId: string, options?: RecipePublishOptions): Promise<RecipeReceipt>;
|
|
163
258
|
get(recipeId: string): Promise<RecipeFetchReceipt>;
|
|
164
259
|
express(recipeId: string, request?: RecipeExpressRequest): Promise<RecipeExpressionReceipt>;
|
|
260
|
+
search(request?: RecipeSearchRequest): Promise<RecipeSearchReceipt>;
|
|
261
|
+
list(request?: RecipeSearchRequest): Promise<RecipeSearchReceipt>;
|
|
165
262
|
}
|
|
166
|
-
export type HubCapabilityName = 'publish' | 'fetch' | 'search' | 'task' | 'mailbox' | 'auth' | 'audit' | 'air_gap' | 'tenant_isolation' | 'marketplace' | 'economy' | 'questions' | 'recipes' | 'agent_directory';
|
|
263
|
+
export type HubCapabilityName = 'publish' | 'fetch' | 'search' | 'task' | 'mailbox' | 'auth' | 'audit' | 'air_gap' | 'tenant_isolation' | 'marketplace' | 'economy' | 'questions' | 'recipes' | 'agent_directory' | 'learning_assets';
|
|
167
264
|
/** hub 能力清单(可选). core 据此动态适配 UI/行为, "按需耦合". */
|
|
168
265
|
export interface HubManifest {
|
|
169
266
|
capabilities: HubCapabilityName[] | string[];
|
|
@@ -201,6 +298,7 @@ export interface HttpRequestLike {
|
|
|
201
298
|
method: string;
|
|
202
299
|
path: string;
|
|
203
300
|
body?: string;
|
|
301
|
+
signal?: AbortSignal;
|
|
204
302
|
}
|
|
205
303
|
/**
|
|
206
304
|
* Pluggable auth. Example implementations: public OAuth device token / Ed25519 keypair / enterprise SSO (OIDC/LDAP).
|
|
@@ -217,20 +315,48 @@ export interface AuthProvider {
|
|
|
217
315
|
/** 撤销凭证(机器丢失/泄露). */
|
|
218
316
|
revoke(credentialId: string): Promise<void>;
|
|
219
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* By-id fetch is content-addressed by default. Integrity-sensitive callers may
|
|
320
|
+
* explicitly opt in to receiving a schema-valid delivery whose declared
|
|
321
|
+
* asset_id matches the request while its current content hash does not.
|
|
322
|
+
*/
|
|
323
|
+
export interface FetchAssetByIdOptions {
|
|
324
|
+
allowUnverifiedExactIdentity?: boolean;
|
|
325
|
+
}
|
|
326
|
+
/** Why a by-id fetch produced no asset. `absent` is the ONLY one that means the hub does not have it. */
|
|
327
|
+
export type AssetDeliveryRejection = 'identity_mismatch' | 'revoked' | 'ambiguous' | 'unverified_not_allowed';
|
|
328
|
+
/**
|
|
329
|
+
* The outcome of a by-id fetch. `verified:false` means the delivery is bound to the requested id but its body
|
|
330
|
+
* hashes to something else — usable only under quarantine, never as canonical content.
|
|
331
|
+
*/
|
|
332
|
+
export type AssetDeliveryOutcome = {
|
|
333
|
+
status: 'delivered';
|
|
334
|
+
asset: AssetRecord;
|
|
335
|
+
verified: boolean;
|
|
336
|
+
} | {
|
|
337
|
+
status: 'absent';
|
|
338
|
+
} | {
|
|
339
|
+
status: 'rejected';
|
|
340
|
+
reason: AssetDeliveryRejection;
|
|
341
|
+
};
|
|
220
342
|
export interface HubCapability {
|
|
221
343
|
/**
|
|
222
344
|
* 异步发布. 公版 /a2a/publish 收 **bundle**[Gene,Capsule,(EvolutionEvent)](一个 cycle 的产物一起发, +GDI);
|
|
223
345
|
* 传单资产=[asset]。core 已 normalizeForPut(算/校验 asset_id), hub 做经济/治理/质量 gate。
|
|
224
346
|
*/
|
|
225
|
-
publish(bundle: AssetRecord[]): Promise<PublishReceipt>;
|
|
347
|
+
publish(bundle: AssetRecord[], options?: PublishOptions): Promise<PublishReceipt>;
|
|
226
348
|
/** 拉取资产. hub 侧排序/scope(公版 GDI, 私有 RBAC); core 不重排. */
|
|
227
349
|
fetch(query: HubQuery): Promise<AssetRecord[]>;
|
|
228
350
|
/** 搜索资产. 与 fetch 同 shape, 差异在 hub 侧召回策略. */
|
|
229
351
|
search(query: HubQuery): Promise<AssetRecord[]>;
|
|
230
352
|
/** 可选: 按 content-addressed asset_id 拉单个 full asset. private adapter/proxy 用它保证只 fetch 一个 winner. */
|
|
231
|
-
fetchAssetById?(assetId: string): Promise<AssetRecord | null>;
|
|
353
|
+
fetchAssetById?(assetId: string, options?: FetchAssetByIdOptions): Promise<AssetRecord | null>;
|
|
232
354
|
/** 可选: 报告某个资产被复用后的结果. PHub/enterprise adapter 实现; 不支持时 runtime 应明确降级. */
|
|
233
355
|
recordReuseResult?(report: ReuseResultReport): Promise<ReuseResultReceipt>;
|
|
356
|
+
/** 可选: 列出 hub 端 runtime learning assets. Missing means the adapter does not support this MVP surface. */
|
|
357
|
+
listLearningAssets?(options?: LearningAssetListOptions): Promise<LearningAssetListResult>;
|
|
358
|
+
/** 可选: 上报 learning asset 使用结果. Best-effort; failures must never break solve paths. */
|
|
359
|
+
recordLearningAssetUsage?(report: LearningAssetUsageReport): Promise<LearningAssetUsageReceipt>;
|
|
234
360
|
/**
|
|
235
361
|
* 可选: 发布前 dry-run 校验(公版 POST /a2a/validate). 跑与 publish 相同的 hub 端质量门禁 + 内容安全扫描,
|
|
236
362
|
* 但不落库、不计费; 经由 Proxy 暴露时调用方需先执行与 publish 相同的客户端脱敏/泄漏拦截.
|
|
@@ -43,6 +43,7 @@ interface NormalizedExecution {
|
|
|
43
43
|
files: number;
|
|
44
44
|
lines: number;
|
|
45
45
|
};
|
|
46
|
+
untrustedStatusClaim: boolean;
|
|
46
47
|
}
|
|
47
48
|
interface NormalizedConversation {
|
|
48
49
|
text: string;
|
|
@@ -65,6 +66,22 @@ export interface QualityGate {
|
|
|
65
66
|
export interface ConversationDistillOptions {
|
|
66
67
|
persist?: boolean;
|
|
67
68
|
store?: AssetStoreProvider;
|
|
69
|
+
/**
|
|
70
|
+
* 仅由受信任的宿主验证器注入。HTTP/MCP 请求体中的 execution 不能替代此证据。
|
|
71
|
+
*/
|
|
72
|
+
verifiedExecution?: ConversationDistillVerifiedExecution;
|
|
73
|
+
}
|
|
74
|
+
export interface ConversationDistillVerifiedExecution {
|
|
75
|
+
trace: ReadonlyArray<{
|
|
76
|
+
command: string;
|
|
77
|
+
exit: number;
|
|
78
|
+
summary?: string;
|
|
79
|
+
}>;
|
|
80
|
+
validation?: readonly string[];
|
|
81
|
+
blast_radius?: {
|
|
82
|
+
files?: number;
|
|
83
|
+
lines?: number;
|
|
84
|
+
};
|
|
68
85
|
}
|
|
69
86
|
export type ConversationDistillResult = {
|
|
70
87
|
ok: false;
|
|
@@ -80,6 +97,8 @@ export type ConversationDistillResult = {
|
|
|
80
97
|
signals: string[];
|
|
81
98
|
gene: AssetRecord;
|
|
82
99
|
capsule: AssetRecord;
|
|
100
|
+
/** 仅当质量闸门通过且草稿可以进入发布流程时为 true。 */
|
|
101
|
+
publishable: boolean;
|
|
83
102
|
};
|
|
84
103
|
export declare function inferSignals(text: string, providedSignals?: unknown): string[];
|
|
85
104
|
export declare function evaluateGate(input: ConversationDistillInput, normalized: NormalizedConversation): QualityGate;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { intakeGene } from '../algo/geneIntake.js';
|
|
3
|
+
import { redactDeep, redactString } from './sanitize.js';
|
|
4
|
+
import { SCHEMA_VERSION, computeAssetId, stripGeneHints, validateWireDeep } from '../wire/index.js';
|
|
4
5
|
const DEFAULT_SIGNALS = [
|
|
5
6
|
'conversation_distillation',
|
|
6
7
|
'reusable_capability',
|
|
@@ -16,6 +17,7 @@ const SIGNAL_RULES = [
|
|
|
16
17
|
{ signal: 'plugin_integration', re: /\b(plugin|codex|claude|cursor|antigravity|workbuddy|hook|notify)\b|插件|钩子/i },
|
|
17
18
|
{ signal: 'test_verified', re: /\b(test|build|verify|passed|green)\b|测试|验证|通过/i },
|
|
18
19
|
];
|
|
20
|
+
const BUNDLE_PERSISTENCE_UNSUPPORTED = 'bundle_persistence_unsupported';
|
|
19
21
|
function asRecord(v) {
|
|
20
22
|
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
21
23
|
}
|
|
@@ -74,37 +76,63 @@ function normalizePublishBlastRadius(value, artifactCount) {
|
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
function capsuleContent(normalized) {
|
|
77
|
-
return
|
|
79
|
+
return redactDeep({
|
|
78
80
|
platform: normalized.platform,
|
|
79
81
|
source_thread: normalized.source_thread || null,
|
|
80
82
|
artifacts: normalized.artifacts,
|
|
81
83
|
excerpt: normalized.text.slice(0, 1200),
|
|
82
|
-
})
|
|
84
|
+
});
|
|
83
85
|
}
|
|
84
86
|
function normalizeExecution(input) {
|
|
85
87
|
const execution = asRecord(input.execution);
|
|
86
88
|
const validation = normalizeList(input.validation ?? input.verification ?? execution['validation'], 8, 180);
|
|
89
|
+
const untrustedStatusClaim = execution['status'] !== undefined || execution['ok'] !== undefined;
|
|
90
|
+
let malformedTrace = false;
|
|
87
91
|
const trace = asArray(execution['trace']).map((item) => {
|
|
88
|
-
if (typeof item === 'string')
|
|
89
|
-
|
|
92
|
+
if (typeof item === 'string') {
|
|
93
|
+
malformedTrace = true;
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
90
96
|
const row = asRecord(item);
|
|
91
|
-
if (Object.keys(row).length === 0)
|
|
97
|
+
if (Object.keys(row).length === 0) {
|
|
98
|
+
malformedTrace = true;
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const command = trimText(row['command'] ?? row['cmd'] ?? row['name'] ?? '', 180);
|
|
102
|
+
if (!command) {
|
|
103
|
+
malformedTrace = true;
|
|
92
104
|
return null;
|
|
105
|
+
}
|
|
106
|
+
const rawExit = row['exit'];
|
|
107
|
+
const exit = Number.isInteger(rawExit)
|
|
108
|
+
? Number(rawExit)
|
|
109
|
+
: (typeof row['ok'] === 'boolean' ? (row['ok'] ? 0 : 1) : undefined);
|
|
110
|
+
if (exit === undefined) {
|
|
111
|
+
malformedTrace = true;
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
93
114
|
return {
|
|
94
|
-
command
|
|
95
|
-
exit
|
|
115
|
+
command,
|
|
116
|
+
exit,
|
|
96
117
|
summary: trimText(row['summary'] ?? row['output'] ?? '', 240),
|
|
97
118
|
};
|
|
98
119
|
}).filter((row) => row !== null);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
120
|
+
// 声明的验证命令只是计划,并不能证明命令已经执行。
|
|
121
|
+
// 保留它作为质量信号,但不能为未执行的声明伪造 exit-0 轨迹或成功结果。
|
|
122
|
+
// 只有显式结构化的退出码才可作为证据。调用方声明的 status/ok 字段只是元数据,
|
|
123
|
+
// 不能据此把资产晋级到发布流程。
|
|
124
|
+
const normalizedValidation = new Set(validation);
|
|
125
|
+
const covered = [...normalizedValidation].every((command) => trace.some((row) => row.command === command));
|
|
126
|
+
const ok = trace.length > 0
|
|
127
|
+
&& !malformedTrace
|
|
128
|
+
&& trace.every((t) => t.exit === 0)
|
|
129
|
+
&& covered;
|
|
103
130
|
return {
|
|
104
131
|
status: ok ? 'success' : 'failed',
|
|
105
132
|
trace,
|
|
106
133
|
validation,
|
|
107
134
|
blast_radius: normalizeBlastRadius(execution['blast_radius'] ?? input.blast_radius),
|
|
135
|
+
untrustedStatusClaim,
|
|
108
136
|
};
|
|
109
137
|
}
|
|
110
138
|
function buildStrategy(input) {
|
|
@@ -145,7 +173,9 @@ export function evaluateGate(input, normalized) {
|
|
|
145
173
|
reasons.push('explicit_distill_signal');
|
|
146
174
|
}
|
|
147
175
|
const rawThreshold = Number(input.min_score ?? input.minScore ?? 5);
|
|
148
|
-
|
|
176
|
+
// 调用方可以要求更严格的阈值,但不能把准入策略降为零,
|
|
177
|
+
// 也不能把未经确认的草稿变成可发布资产。
|
|
178
|
+
const threshold = Number.isFinite(rawThreshold) ? Math.max(5, rawThreshold) : 5;
|
|
149
179
|
if (score < threshold)
|
|
150
180
|
return { ok: false, score, threshold, reasons, reason: 'insufficient_reusable_signal' };
|
|
151
181
|
return { ok: true, score, threshold, reasons };
|
|
@@ -178,12 +208,17 @@ export function normalizeConversationInput(input) {
|
|
|
178
208
|
export async function distillConversation(input, opts = {}) {
|
|
179
209
|
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
180
210
|
return { ok: false, status: 'skipped', reason: 'input_object_required' };
|
|
181
|
-
const
|
|
211
|
+
const effectiveInput = opts.verifiedExecution
|
|
212
|
+
? {
|
|
213
|
+
...input,
|
|
214
|
+
execution: opts.verifiedExecution,
|
|
215
|
+
...(opts.verifiedExecution.validation ? { validation: opts.verifiedExecution.validation } : {}),
|
|
216
|
+
}
|
|
217
|
+
: input;
|
|
218
|
+
const normalized = normalizeConversationInput(effectiveInput);
|
|
182
219
|
if (!normalized.summary || normalized.summary.length < 20)
|
|
183
220
|
return { ok: false, status: 'skipped', reason: 'summary_required' };
|
|
184
221
|
const gate = evaluateGate(input, normalized);
|
|
185
|
-
if (!gate.ok)
|
|
186
|
-
return { ok: false, status: 'skipped', reason: gate.reason ?? 'insufficient_reusable_signal', quality: gate, signals: normalized.signals };
|
|
187
222
|
const slug = slugify(input.name ?? input.title ?? normalized.summary);
|
|
188
223
|
const fingerprint = hashInput({
|
|
189
224
|
summary: normalized.summary,
|
|
@@ -192,9 +227,13 @@ export async function distillConversation(input, opts = {}) {
|
|
|
192
227
|
artifacts: normalized.artifacts,
|
|
193
228
|
});
|
|
194
229
|
const category = inferCategory(normalized.signals, normalized.text);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
230
|
+
// 只有质量门禁与受信任宿主证据同时通过时,Capsule 才允许广播。
|
|
231
|
+
const publishable = gate.ok && normalized.execution.status === 'success' && opts.verifiedExecution !== undefined;
|
|
232
|
+
const declaredValidation = normalized.execution.validation;
|
|
233
|
+
// GEP Gene schema 要求非空 validation。调用方没有计划时保留旧版 Node 身份检查,
|
|
234
|
+
// 但它只用于形成可审阅草稿,绝不能产生 verifier 坐标或发布资格。
|
|
235
|
+
const validation = declaredValidation.length > 0 ? declaredValidation : ['node --version'];
|
|
236
|
+
const intake = intakeGene({
|
|
198
237
|
id: `gene_conversation_${slug}_${fingerprint}`,
|
|
199
238
|
summary: normalized.summary,
|
|
200
239
|
category,
|
|
@@ -204,18 +243,28 @@ export async function distillConversation(input, opts = {}) {
|
|
|
204
243
|
'The conversation includes enough evidence to reconstruct when and how to use it.',
|
|
205
244
|
],
|
|
206
245
|
strategy: normalized.strategy,
|
|
207
|
-
validation
|
|
246
|
+
validation,
|
|
208
247
|
constraints: { max_files: 20, forbidden_paths: ['.git', 'node_modules', '.env'] },
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
248
|
+
generation_meta: { source: 'distilled' },
|
|
249
|
+
model_name: normalized.model,
|
|
250
|
+
});
|
|
251
|
+
if (!intake.ok || !intake.gene) {
|
|
252
|
+
return {
|
|
253
|
+
ok: false,
|
|
254
|
+
status: 'skipped',
|
|
255
|
+
reason: 'gene_intake_failed',
|
|
213
256
|
quality: gate,
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
};
|
|
218
|
-
|
|
257
|
+
signals: normalized.signals,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const gene = { ...intake.gene };
|
|
261
|
+
// intakeGene 会从任何非空 validation 计划推导 verifier_profile。旧版身份检查并非
|
|
262
|
+
// 行为验证证据,因此必须移除该坐标并重新绑定内容寻址 ID,保持严格 K_auto fail-closed。
|
|
263
|
+
if (declaredValidation.length === 0) {
|
|
264
|
+
delete gene.verifier_profile;
|
|
265
|
+
gene.asset_id = '';
|
|
266
|
+
gene.asset_id = computeAssetId(gene) ?? '';
|
|
267
|
+
}
|
|
219
268
|
const capsule = {
|
|
220
269
|
type: 'Capsule',
|
|
221
270
|
schema_version: SCHEMA_VERSION,
|
|
@@ -226,13 +275,13 @@ export async function distillConversation(input, opts = {}) {
|
|
|
226
275
|
confidence: Math.min(0.95, 0.5 + gate.score / 20),
|
|
227
276
|
blast_radius: normalizePublishBlastRadius(normalized.execution.blast_radius, normalized.artifacts.length),
|
|
228
277
|
outcome: { status: normalized.execution.status, score: normalized.execution.status === 'success' ? 0.82 : 0.35 },
|
|
229
|
-
source_type: '
|
|
278
|
+
source_type: 'generated',
|
|
230
279
|
strategy: normalized.strategy,
|
|
231
280
|
execution_trace: normalized.execution.trace,
|
|
232
|
-
a2a: { eligible_to_broadcast:
|
|
281
|
+
a2a: { eligible_to_broadcast: publishable },
|
|
233
282
|
content: capsuleContent(normalized),
|
|
234
|
-
diff:
|
|
235
|
-
reused_asset_id:
|
|
283
|
+
diff: null,
|
|
284
|
+
reused_asset_id: null,
|
|
236
285
|
env_fingerprint: {
|
|
237
286
|
platform: normalized.platform,
|
|
238
287
|
source_thread: normalized.source_thread || null,
|
|
@@ -247,14 +296,43 @@ export async function distillConversation(input, opts = {}) {
|
|
|
247
296
|
asset_id: '',
|
|
248
297
|
};
|
|
249
298
|
capsule.asset_id = computeAssetId(capsule) ?? '';
|
|
250
|
-
|
|
299
|
+
// 质量准入可以保持宽松,但草稿仍必须是有效的 wire 记录。
|
|
300
|
+
// 在持久化或排队前捕获生产者与 schema 的漂移。
|
|
301
|
+
if (!validateWireDeep(stripGeneHints(gene)).ok || !validateWireDeep(capsule).ok) {
|
|
302
|
+
return {
|
|
303
|
+
ok: false,
|
|
304
|
+
status: 'skipped',
|
|
305
|
+
reason: 'wire_schema_invalid',
|
|
306
|
+
quality: gate,
|
|
307
|
+
signals: normalized.signals,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
// 只有受信任宿主验证器提供的成功 execution 才能解锁发布。
|
|
311
|
+
// 本地调用方显式要求 persist 时,可以保留没有成功证据的失败草稿供人工复核,
|
|
312
|
+
// 但请求体伪造的 exit-0 轨迹不能借此写入看似成功的资产。
|
|
313
|
+
const persistRequested = (opts.persist ?? input.persist) === true;
|
|
314
|
+
const failedDraftPersistence = !opts.verifiedExecution
|
|
315
|
+
&& normalized.execution.status === 'failed'
|
|
316
|
+
&& !normalized.execution.untrustedStatusClaim;
|
|
317
|
+
const persist = persistRequested && (publishable || (gate.ok && failedDraftPersistence));
|
|
251
318
|
if (persist && opts.store) {
|
|
252
|
-
|
|
253
|
-
|
|
319
|
+
// Gene/Capsule 是一个可发布单元。只提供单条写入的 provider 无法恢复
|
|
320
|
+
// 两次写入之间的崩溃窗口;不要用兼容回退制造孤儿 Gene。
|
|
321
|
+
if (typeof opts.store.putBundle !== 'function') {
|
|
322
|
+
return {
|
|
323
|
+
ok: false,
|
|
324
|
+
status: 'skipped',
|
|
325
|
+
reason: BUNDLE_PERSISTENCE_UNSUPPORTED,
|
|
326
|
+
quality: gate,
|
|
327
|
+
signals: normalized.signals,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
await opts.store.putBundle([gene, capsule]);
|
|
254
331
|
}
|
|
255
332
|
return {
|
|
256
333
|
ok: true,
|
|
257
334
|
status: persist && opts.store ? 'stored' : 'draft',
|
|
335
|
+
publishable,
|
|
258
336
|
distill_id: fingerprint,
|
|
259
337
|
quality: gate,
|
|
260
338
|
signals: normalized.signals,
|
package/dist/hub/fake.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HubCapability, PublishReceipt, AgentEvent, TaskEvent, AuthProvider, HubQuery, AssetRecord, TaskCompleteContext } from './capability.js';
|
|
1
|
+
import type { HubCapability, PublishReceipt, AgentEvent, TaskEvent, AuthProvider, HubQuery, AssetRecord, TaskCompleteContext, PublishOptions } from './capability.js';
|
|
2
2
|
export interface FakeHubOptions {
|
|
3
3
|
/** 脚本化 publish gate: 返回 reject/quarantine 以测 PublishReceipt 终态路径. */
|
|
4
4
|
publishGate?: (asset: AssetRecord) => Pick<PublishReceipt, 'status' | 'reason' | 'terminal'>;
|
|
@@ -24,11 +24,12 @@ export declare class FakeHubCapability implements HubCapability {
|
|
|
24
24
|
}>;
|
|
25
25
|
readonly auth: AuthProvider;
|
|
26
26
|
agentDirectory?: import('./agentDirectory.js').AgentDirectoryCapability;
|
|
27
|
+
recipes?: import('./capability.js').RecipeCapability;
|
|
27
28
|
nextPollAfterMs: number | undefined;
|
|
28
29
|
constructor(opts?: FakeHubOptions);
|
|
29
30
|
/** 测试注入: 排一条 inbound 事件供 poll 拉. */
|
|
30
31
|
seedInbound(e: AgentEvent): void;
|
|
31
|
-
publish(bundle: AssetRecord[]): Promise<PublishReceipt>;
|
|
32
|
+
publish(bundle: AssetRecord[], _options?: PublishOptions): Promise<PublishReceipt>;
|
|
32
33
|
fetch(query: HubQuery): Promise<AssetRecord[]>;
|
|
33
34
|
search(query: HubQuery): Promise<AssetRecord[]>;
|
|
34
35
|
task: {
|
package/dist/hub/fake.js
CHANGED
|
@@ -20,13 +20,14 @@ export class FakeHubCapability {
|
|
|
20
20
|
completed = [];
|
|
21
21
|
auth = fakeAuth;
|
|
22
22
|
agentDirectory;
|
|
23
|
+
recipes;
|
|
23
24
|
nextPollAfterMs;
|
|
24
25
|
constructor(opts = {}) {
|
|
25
26
|
this.opts = opts;
|
|
26
27
|
}
|
|
27
28
|
/** 测试注入: 排一条 inbound 事件供 poll 拉. */
|
|
28
29
|
seedInbound(e) { this.inbox.push(e); }
|
|
29
|
-
async publish(bundle) {
|
|
30
|
+
async publish(bundle, _options) {
|
|
30
31
|
const assetIds = bundle.map((a) => computeAssetId(a));
|
|
31
32
|
const gate = this.opts.publishGate?.(bundle[0] ?? {}) ?? { status: 'accepted' };
|
|
32
33
|
if (gate.status === 'accepted')
|
package/dist/hub/index.d.ts
CHANGED
package/dist/hub/index.js
CHANGED
|
@@ -54,6 +54,10 @@ export interface QuestionGenerationResult {
|
|
|
54
54
|
state: QuestionGeneratorState;
|
|
55
55
|
changed: boolean;
|
|
56
56
|
}
|
|
57
|
-
export
|
|
57
|
+
export interface TopicKeywordOptions {
|
|
58
|
+
minOccurrences?: number;
|
|
59
|
+
preserveSourceOrder?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export declare function extractTopicKeywords(transcript: string | undefined, memory: string | undefined, max?: number, opts?: TopicKeywordOptions): string[];
|
|
58
62
|
export declare function generateQuestions(input?: GenerateQuestionsInput): QuestionGenerationResult;
|
|
59
63
|
export declare function generateUrgentQuestions(input?: GenerateUrgentQuestionsInput): QuestionGenerationResult;
|
|
@@ -21,7 +21,7 @@ const EXPLORE_STOPWORDS = new Set([
|
|
|
21
21
|
'agent', 'about', 'into', 'then', 'than', 'they', 'them', 'their', 'there',
|
|
22
22
|
'here', 'will', 'would', 'could', 'should', 'been', 'were', 'using', 'used',
|
|
23
23
|
'cycle', 'evolution', 'error', 'errors', 'failed', 'failure', 'null', 'undefined',
|
|
24
|
-
'true', 'false', 'console', 'return', 'function', 'const', 'value', 'result',
|
|
24
|
+
'true', 'false', 'console', 'return', 'function', 'const', 'value', 'result', 'redacted',
|
|
25
25
|
]);
|
|
26
26
|
const SENSITIVE_TOPIC_RE = /secret|token|api[_-]?key|password|passwd|credential|bearer|authorization|cookie|session[_-]?id|private[_-]?key|oauth|refresh[_-]?token/i;
|
|
27
27
|
const LONG_OPAQUE_RE = /^[a-z0-9_-]{32,}$/i;
|
|
@@ -106,8 +106,8 @@ function safeTopicToken(token) {
|
|
|
106
106
|
return false;
|
|
107
107
|
return true;
|
|
108
108
|
}
|
|
109
|
-
export function extractTopicKeywords(transcript, memory, max = 5) {
|
|
110
|
-
const text = `${String(transcript ?? '')} ${String(memory ?? '')}
|
|
109
|
+
export function extractTopicKeywords(transcript, memory, max = 5, opts = {}) {
|
|
110
|
+
const text = redactString(`${String(transcript ?? '')} ${String(memory ?? '')}`).toLowerCase();
|
|
111
111
|
const words = text.match(/[a-z][a-z0-9_-]{4,}/g) ?? [];
|
|
112
112
|
const freq = new Map();
|
|
113
113
|
for (const word of words) {
|
|
@@ -115,9 +115,11 @@ export function extractTopicKeywords(transcript, memory, max = 5) {
|
|
|
115
115
|
continue;
|
|
116
116
|
freq.set(word, (freq.get(word) ?? 0) + 1);
|
|
117
117
|
}
|
|
118
|
-
|
|
119
|
-
.filter(([, count]) => count >= 2)
|
|
120
|
-
|
|
118
|
+
const entries = [...freq.entries()]
|
|
119
|
+
.filter(([, count]) => count >= Math.max(1, Math.trunc(opts.minOccurrences ?? 2)));
|
|
120
|
+
if (!opts.preserveSourceOrder)
|
|
121
|
+
entries.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
122
|
+
return entries
|
|
121
123
|
.map(([word]) => word)
|
|
122
124
|
.slice(0, max);
|
|
123
125
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AssetRecord, HubCapability } from './capability.js';
|
|
2
|
+
export declare const RECIPE_COMPOSE_FLAG = "compose_recipe";
|
|
3
|
+
export interface RecipeComposeInput {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
assets?: readonly unknown[];
|
|
7
|
+
source?: unknown;
|
|
8
|
+
[k: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface RecipeComposeResult {
|
|
11
|
+
attempted: boolean;
|
|
12
|
+
ok: boolean;
|
|
13
|
+
reason?: string;
|
|
14
|
+
recipeId?: string;
|
|
15
|
+
status?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function recipeComposeRequested(payload: RecipeComposeInput): boolean;
|
|
18
|
+
export declare function recipeAssetsFromPayload(payload: RecipeComposeInput): {
|
|
19
|
+
gene?: AssetRecord;
|
|
20
|
+
capsule?: AssetRecord;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* After a Gene/Capsule bundle is accepted by Hub, compose a Recipe as the
|
|
24
|
+
* preferred public artifact. Skill Store publish is not the default outbound.
|
|
25
|
+
* Missing recipe capability or missing Gene is a no-op, never a publish failure.
|
|
26
|
+
*/
|
|
27
|
+
export declare function composeRecipeAfterAssetPublish(hub: Pick<HubCapability, 'recipes'>, payload: RecipeComposeInput): Promise<RecipeComposeResult>;
|