open-multi-agent-kit 1.0.0 → 1.2.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 +6 -1
- package/README.md +2 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +1 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/coordination/awareness.d.ts +32 -0
- package/dist/coordination/awareness.d.ts.map +1 -0
- package/dist/coordination/awareness.js +55 -0
- package/dist/coordination/awareness.js.map +1 -0
- package/dist/coordination/broker.d.ts +79 -0
- package/dist/coordination/broker.d.ts.map +1 -0
- package/dist/coordination/broker.js +195 -0
- package/dist/coordination/broker.js.map +1 -0
- package/dist/coordination/index.d.ts +16 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +16 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/integration.d.ts +59 -0
- package/dist/coordination/integration.d.ts.map +1 -0
- package/dist/coordination/integration.js +126 -0
- package/dist/coordination/integration.js.map +1 -0
- package/dist/coordination/operation.d.ts +106 -0
- package/dist/coordination/operation.d.ts.map +1 -0
- package/dist/coordination/operation.js +179 -0
- package/dist/coordination/operation.js.map +1 -0
- package/dist/coordination/resource.d.ts +33 -0
- package/dist/coordination/resource.d.ts.map +1 -0
- package/dist/coordination/resource.js +89 -0
- package/dist/coordination/resource.js.map +1 -0
- package/dist/coordination/session.d.ts +74 -0
- package/dist/coordination/session.d.ts.map +1 -0
- package/dist/coordination/session.js +143 -0
- package/dist/coordination/session.js.map +1 -0
- package/dist/coordination/types.d.ts +68 -0
- package/dist/coordination/types.d.ts.map +1 -0
- package/dist/coordination/types.js +26 -0
- package/dist/coordination/types.js.map +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +28 -7
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/control-state.d.ts +41 -0
- package/dist/core/compaction/control-state.d.ts.map +1 -0
- package/dist/core/compaction/control-state.js +85 -0
- package/dist/core/compaction/control-state.js.map +1 -0
- package/dist/core/compaction/fallback.d.ts +60 -0
- package/dist/core/compaction/fallback.d.ts.map +1 -0
- package/dist/core/compaction/fallback.js +117 -0
- package/dist/core/compaction/fallback.js.map +1 -0
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/context-budget-headroom-candidates.d.ts +16 -1
- package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-candidates.js +31 -13
- package/dist/core/context-budget-headroom-candidates.js.map +1 -1
- package/dist/core/context-budget-headroom-types.d.ts +7 -1
- package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-types.js +0 -1
- package/dist/core/context-budget-headroom-types.js.map +1 -1
- package/dist/core/context-budget-headroom.d.ts +10 -0
- package/dist/core/context-budget-headroom.d.ts.map +1 -1
- package/dist/core/context-budget-headroom.js +11 -2
- package/dist/core/context-budget-headroom.js.map +1 -1
- package/dist/core/context-budget-v2-global-pass.d.ts +21 -0
- package/dist/core/context-budget-v2-global-pass.d.ts.map +1 -0
- package/dist/core/context-budget-v2-global-pass.js +203 -0
- package/dist/core/context-budget-v2-global-pass.js.map +1 -0
- package/dist/core/context-budget-v2-planned-items.d.ts +12 -0
- package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planned-items.js +21 -2
- package/dist/core/context-budget-v2-planned-items.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +18 -19
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +7 -1
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +3 -0
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +6 -2
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +6 -1
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +6 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/provider-default-models.d.ts +1 -0
- package/dist/core/provider-default-models.d.ts.map +1 -1
- package/dist/core/provider-default-models.js +1 -0
- package/dist/core/provider-default-models.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts +7 -0
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +21 -3
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +8 -5
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +8 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts +15 -0
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +17 -4
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/todo-runtime-state.d.ts +12 -0
- package/dist/core/todo-runtime-state.d.ts.map +1 -1
- package/dist/core/todo-runtime-state.js +23 -0
- package/dist/core/todo-runtime-state.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/metacognition/calibration-selective.d.ts +78 -0
- package/dist/metacognition/calibration-selective.d.ts.map +1 -0
- package/dist/metacognition/calibration-selective.js +161 -0
- package/dist/metacognition/calibration-selective.js.map +1 -0
- package/dist/metacognition/calibration.d.ts +62 -0
- package/dist/metacognition/calibration.d.ts.map +1 -0
- package/dist/metacognition/calibration.js +122 -0
- package/dist/metacognition/calibration.js.map +1 -0
- package/dist/metacognition/checkpoint.d.ts +60 -0
- package/dist/metacognition/checkpoint.d.ts.map +1 -0
- package/dist/metacognition/checkpoint.js +57 -0
- package/dist/metacognition/checkpoint.js.map +1 -0
- package/dist/metacognition/context7.d.ts +48 -0
- package/dist/metacognition/context7.d.ts.map +1 -0
- package/dist/metacognition/context7.js +154 -0
- package/dist/metacognition/context7.js.map +1 -0
- package/dist/metacognition/decision.d.ts +44 -0
- package/dist/metacognition/decision.d.ts.map +1 -0
- package/dist/metacognition/decision.js +111 -0
- package/dist/metacognition/decision.js.map +1 -0
- package/dist/metacognition/evaluation.d.ts +73 -0
- package/dist/metacognition/evaluation.d.ts.map +1 -0
- package/dist/metacognition/evaluation.js +97 -0
- package/dist/metacognition/evaluation.js.map +1 -0
- package/dist/metacognition/index.d.ts +31 -0
- package/dist/metacognition/index.d.ts.map +1 -0
- package/dist/metacognition/index.js +31 -0
- package/dist/metacognition/index.js.map +1 -0
- package/dist/metacognition/knowledge-action.d.ts +43 -0
- package/dist/metacognition/knowledge-action.d.ts.map +1 -0
- package/dist/metacognition/knowledge-action.js +60 -0
- package/dist/metacognition/knowledge-action.js.map +1 -0
- package/dist/metacognition/knowledge.d.ts +84 -0
- package/dist/metacognition/knowledge.d.ts.map +1 -0
- package/dist/metacognition/knowledge.js +165 -0
- package/dist/metacognition/knowledge.js.map +1 -0
- package/dist/metacognition/obligations.d.ts +82 -0
- package/dist/metacognition/obligations.d.ts.map +1 -0
- package/dist/metacognition/obligations.js +139 -0
- package/dist/metacognition/obligations.js.map +1 -0
- package/dist/metacognition/observation-validity.d.ts +83 -0
- package/dist/metacognition/observation-validity.d.ts.map +1 -0
- package/dist/metacognition/observation-validity.js +118 -0
- package/dist/metacognition/observation-validity.js.map +1 -0
- package/dist/metacognition/observe.d.ts +45 -0
- package/dist/metacognition/observe.d.ts.map +1 -0
- package/dist/metacognition/observe.js +59 -0
- package/dist/metacognition/observe.js.map +1 -0
- package/dist/metacognition/policy.d.ts +53 -0
- package/dist/metacognition/policy.d.ts.map +1 -0
- package/dist/metacognition/policy.js +155 -0
- package/dist/metacognition/policy.js.map +1 -0
- package/dist/metacognition/predictions.d.ts +78 -0
- package/dist/metacognition/predictions.d.ts.map +1 -0
- package/dist/metacognition/predictions.js +181 -0
- package/dist/metacognition/predictions.js.map +1 -0
- package/dist/metacognition/retrieval.d.ts +53 -0
- package/dist/metacognition/retrieval.d.ts.map +1 -0
- package/dist/metacognition/retrieval.js +170 -0
- package/dist/metacognition/retrieval.js.map +1 -0
- package/dist/metacognition/risk.d.ts +48 -0
- package/dist/metacognition/risk.d.ts.map +1 -0
- package/dist/metacognition/risk.js +165 -0
- package/dist/metacognition/risk.js.map +1 -0
- package/dist/metacognition/route-economics.d.ts +95 -0
- package/dist/metacognition/route-economics.d.ts.map +1 -0
- package/dist/metacognition/route-economics.js +110 -0
- package/dist/metacognition/route-economics.js.map +1 -0
- package/dist/metacognition/runtime-bridge.d.ts +54 -0
- package/dist/metacognition/runtime-bridge.d.ts.map +1 -0
- package/dist/metacognition/runtime-bridge.js +140 -0
- package/dist/metacognition/runtime-bridge.js.map +1 -0
- package/dist/metacognition/skills.d.ts +42 -0
- package/dist/metacognition/skills.d.ts.map +1 -0
- package/dist/metacognition/skills.js +220 -0
- package/dist/metacognition/skills.js.map +1 -0
- package/dist/metacognition/state.d.ts +110 -0
- package/dist/metacognition/state.d.ts.map +1 -0
- package/dist/metacognition/state.js +52 -0
- package/dist/metacognition/state.js.map +1 -0
- package/dist/metacognition/validation.d.ts +19 -0
- package/dist/metacognition/validation.d.ts.map +1 -0
- package/dist/metacognition/validation.js +58 -0
- package/dist/metacognition/validation.js.map +1 -0
- package/dist/metacognition/verification.d.ts +93 -0
- package/dist/metacognition/verification.d.ts.map +1 -0
- package/dist/metacognition/verification.js +132 -0
- package/dist/metacognition/verification.js.map +1 -0
- package/dist/metacognition/verifier.d.ts +49 -0
- package/dist/metacognition/verifier.d.ts.map +1 -0
- package/dist/metacognition/verifier.js +88 -0
- package/dist/metacognition/verifier.js.map +1 -0
- package/dist/observation/identity.d.ts +14 -0
- package/dist/observation/identity.d.ts.map +1 -0
- package/dist/observation/identity.js +29 -0
- package/dist/observation/identity.js.map +1 -0
- package/dist/observation/index.d.ts +13 -0
- package/dist/observation/index.d.ts.map +1 -0
- package/dist/observation/index.js +13 -0
- package/dist/observation/index.js.map +1 -0
- package/dist/observation/observe-mode.d.ts +46 -0
- package/dist/observation/observe-mode.d.ts.map +1 -0
- package/dist/observation/observe-mode.js +83 -0
- package/dist/observation/observe-mode.js.map +1 -0
- package/dist/observation/store.d.ts +53 -0
- package/dist/observation/store.d.ts.map +1 -0
- package/dist/observation/store.js +126 -0
- package/dist/observation/store.js.map +1 -0
- package/dist/observation/types.d.ts +72 -0
- package/dist/observation/types.d.ts.map +1 -0
- package/dist/observation/types.js +9 -0
- package/dist/observation/types.js.map +1 -0
- package/dist/observation/view.d.ts +39 -0
- package/dist/observation/view.d.ts.map +1 -0
- package/dist/observation/view.js +173 -0
- package/dist/observation/view.js.map +1 -0
- package/docs/metacognition.md +51 -0
- package/docs/model-catalog-refresh.md +59 -0
- package/docs/providers.md +53 -0
- package/docs/runtime-algorithms.md +107 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +6 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation kernel types — U1/U2 of the upgraded SoL-Pi design.
|
|
3
|
+
*
|
|
4
|
+
* Raw observations are host-owned execution artifacts. Model-facing views are
|
|
5
|
+
* derived projections and never replace the raw authority: `taskVerdict` is
|
|
6
|
+
* always `not-assessed` here because a view cannot prove completion.
|
|
7
|
+
*/
|
|
8
|
+
export type ObservationStatus = "exit" | "signal" | "partial" | "unavailable";
|
|
9
|
+
export type ObservationPrivacy = "raw-private" | "approved-sanitized";
|
|
10
|
+
export type ObservationKind = "log" | "test" | "command" | "file" | "dom" | "network" | "generic";
|
|
11
|
+
/**
|
|
12
|
+
* A stored execution artifact. `observationId` binds the run, operation and
|
|
13
|
+
* sequence to the content digest, so two identical byte outputs from different
|
|
14
|
+
* executions remain distinct events (never content-hash deduped into one).
|
|
15
|
+
*/
|
|
16
|
+
export interface RawObservation {
|
|
17
|
+
readonly observationId: string;
|
|
18
|
+
readonly sessionId: string;
|
|
19
|
+
readonly runId: string;
|
|
20
|
+
readonly operationId: string;
|
|
21
|
+
readonly sequence: number;
|
|
22
|
+
readonly rawDigest: string;
|
|
23
|
+
readonly byteLength: number;
|
|
24
|
+
readonly bytes: Uint8Array;
|
|
25
|
+
readonly status: ObservationStatus;
|
|
26
|
+
readonly kind: ObservationKind;
|
|
27
|
+
readonly privacy: ObservationPrivacy;
|
|
28
|
+
/** False when the capture itself was truncated upstream — never claim "full raw". */
|
|
29
|
+
readonly sourceComplete: boolean;
|
|
30
|
+
readonly toolCallId?: string;
|
|
31
|
+
}
|
|
32
|
+
export type ObservationViewKind = "full" | "excerpt" | "evidence" | "pointer";
|
|
33
|
+
export type ObservationCoverageStatus = "complete" | "partial" | "unknown";
|
|
34
|
+
/**
|
|
35
|
+
* A model-facing projection of a stored observation. `transformationDigest`
|
|
36
|
+
* binds the view to the deterministic transform that produced it, and
|
|
37
|
+
* `coverageStatus` records whether the view preserves the required fact atoms.
|
|
38
|
+
*/
|
|
39
|
+
export interface ObservationView {
|
|
40
|
+
readonly viewKind: ObservationViewKind;
|
|
41
|
+
readonly observationId: string;
|
|
42
|
+
readonly parentDigest: string;
|
|
43
|
+
readonly transformationDigest: string;
|
|
44
|
+
readonly text: string;
|
|
45
|
+
readonly estimatedTokens: number;
|
|
46
|
+
readonly coveredFactIds: readonly string[];
|
|
47
|
+
readonly missingRequiredFactIds: readonly string[];
|
|
48
|
+
readonly coverageStatus: ObservationCoverageStatus;
|
|
49
|
+
readonly taskVerdict: "not-assessed";
|
|
50
|
+
}
|
|
51
|
+
/** Result of a scoped, byte-bounded read against a stored observation. */
|
|
52
|
+
export interface ObservationRead {
|
|
53
|
+
readonly observationId: string;
|
|
54
|
+
readonly text: string;
|
|
55
|
+
readonly byteOffset: number;
|
|
56
|
+
readonly byteLength: number;
|
|
57
|
+
readonly nextOffset: number;
|
|
58
|
+
readonly eof: boolean;
|
|
59
|
+
readonly truncated: boolean;
|
|
60
|
+
readonly sourceComplete: boolean;
|
|
61
|
+
/** True when the requested byte range was snapped to UTF-8 boundaries. */
|
|
62
|
+
readonly normalized: boolean;
|
|
63
|
+
}
|
|
64
|
+
export type ObservationReadError = "observation-not-found" | "scope-mismatch" | "invalid-range" | "utf8-boundary" | "archive-unavailable";
|
|
65
|
+
export type ObservationReadResult = {
|
|
66
|
+
readonly ok: true;
|
|
67
|
+
readonly read: ObservationRead;
|
|
68
|
+
} | {
|
|
69
|
+
readonly ok: false;
|
|
70
|
+
readonly error: ObservationReadError;
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observation/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;AAC9E,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,oBAAoB,CAAC;AACtE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAElG;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,uFAAqF;IACrF,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAC9E,MAAM,MAAM,yBAAyB,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,sBAAsB,EAAE,SAAS,MAAM,EAAE,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;CACrC;AAED,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAC7B,uBAAuB,GACvB,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,qBAAqB,CAAC;AAEzB,MAAM,MAAM,qBAAqB,GAC9B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAAC","sourcesContent":["/**\n * Observation kernel types — U1/U2 of the upgraded SoL-Pi design.\n *\n * Raw observations are host-owned execution artifacts. Model-facing views are\n * derived projections and never replace the raw authority: `taskVerdict` is\n * always `not-assessed` here because a view cannot prove completion.\n */\n\nexport type ObservationStatus = \"exit\" | \"signal\" | \"partial\" | \"unavailable\";\nexport type ObservationPrivacy = \"raw-private\" | \"approved-sanitized\";\nexport type ObservationKind = \"log\" | \"test\" | \"command\" | \"file\" | \"dom\" | \"network\" | \"generic\";\n\n/**\n * A stored execution artifact. `observationId` binds the run, operation and\n * sequence to the content digest, so two identical byte outputs from different\n * executions remain distinct events (never content-hash deduped into one).\n */\nexport interface RawObservation {\n\treadonly observationId: string;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly operationId: string;\n\treadonly sequence: number;\n\treadonly rawDigest: string;\n\treadonly byteLength: number;\n\treadonly bytes: Uint8Array;\n\treadonly status: ObservationStatus;\n\treadonly kind: ObservationKind;\n\treadonly privacy: ObservationPrivacy;\n\t/** False when the capture itself was truncated upstream — never claim \"full raw\". */\n\treadonly sourceComplete: boolean;\n\treadonly toolCallId?: string;\n}\n\nexport type ObservationViewKind = \"full\" | \"excerpt\" | \"evidence\" | \"pointer\";\nexport type ObservationCoverageStatus = \"complete\" | \"partial\" | \"unknown\";\n\n/**\n * A model-facing projection of a stored observation. `transformationDigest`\n * binds the view to the deterministic transform that produced it, and\n * `coverageStatus` records whether the view preserves the required fact atoms.\n */\nexport interface ObservationView {\n\treadonly viewKind: ObservationViewKind;\n\treadonly observationId: string;\n\treadonly parentDigest: string;\n\treadonly transformationDigest: string;\n\treadonly text: string;\n\treadonly estimatedTokens: number;\n\treadonly coveredFactIds: readonly string[];\n\treadonly missingRequiredFactIds: readonly string[];\n\treadonly coverageStatus: ObservationCoverageStatus;\n\treadonly taskVerdict: \"not-assessed\";\n}\n\n/** Result of a scoped, byte-bounded read against a stored observation. */\nexport interface ObservationRead {\n\treadonly observationId: string;\n\treadonly text: string;\n\treadonly byteOffset: number;\n\treadonly byteLength: number;\n\treadonly nextOffset: number;\n\treadonly eof: boolean;\n\treadonly truncated: boolean;\n\treadonly sourceComplete: boolean;\n\t/** True when the requested byte range was snapped to UTF-8 boundaries. */\n\treadonly normalized: boolean;\n}\n\nexport type ObservationReadError =\n\t| \"observation-not-found\"\n\t| \"scope-mismatch\"\n\t| \"invalid-range\"\n\t| \"utf8-boundary\"\n\t| \"archive-unavailable\";\n\nexport type ObservationReadResult =\n\t| { readonly ok: true; readonly read: ObservationRead }\n\t| { readonly ok: false; readonly error: ObservationReadError };\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation kernel types — U1/U2 of the upgraded SoL-Pi design.
|
|
3
|
+
*
|
|
4
|
+
* Raw observations are host-owned execution artifacts. Model-facing views are
|
|
5
|
+
* derived projections and never replace the raw authority: `taskVerdict` is
|
|
6
|
+
* always `not-assessed` here because a view cannot prove completion.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/observation/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Observation kernel types — U1/U2 of the upgraded SoL-Pi design.\n *\n * Raw observations are host-owned execution artifacts. Model-facing views are\n * derived projections and never replace the raw authority: `taskVerdict` is\n * always `not-assessed` here because a view cannot prove completion.\n */\n\nexport type ObservationStatus = \"exit\" | \"signal\" | \"partial\" | \"unavailable\";\nexport type ObservationPrivacy = \"raw-private\" | \"approved-sanitized\";\nexport type ObservationKind = \"log\" | \"test\" | \"command\" | \"file\" | \"dom\" | \"network\" | \"generic\";\n\n/**\n * A stored execution artifact. `observationId` binds the run, operation and\n * sequence to the content digest, so two identical byte outputs from different\n * executions remain distinct events (never content-hash deduped into one).\n */\nexport interface RawObservation {\n\treadonly observationId: string;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly operationId: string;\n\treadonly sequence: number;\n\treadonly rawDigest: string;\n\treadonly byteLength: number;\n\treadonly bytes: Uint8Array;\n\treadonly status: ObservationStatus;\n\treadonly kind: ObservationKind;\n\treadonly privacy: ObservationPrivacy;\n\t/** False when the capture itself was truncated upstream — never claim \"full raw\". */\n\treadonly sourceComplete: boolean;\n\treadonly toolCallId?: string;\n}\n\nexport type ObservationViewKind = \"full\" | \"excerpt\" | \"evidence\" | \"pointer\";\nexport type ObservationCoverageStatus = \"complete\" | \"partial\" | \"unknown\";\n\n/**\n * A model-facing projection of a stored observation. `transformationDigest`\n * binds the view to the deterministic transform that produced it, and\n * `coverageStatus` records whether the view preserves the required fact atoms.\n */\nexport interface ObservationView {\n\treadonly viewKind: ObservationViewKind;\n\treadonly observationId: string;\n\treadonly parentDigest: string;\n\treadonly transformationDigest: string;\n\treadonly text: string;\n\treadonly estimatedTokens: number;\n\treadonly coveredFactIds: readonly string[];\n\treadonly missingRequiredFactIds: readonly string[];\n\treadonly coverageStatus: ObservationCoverageStatus;\n\treadonly taskVerdict: \"not-assessed\";\n}\n\n/** Result of a scoped, byte-bounded read against a stored observation. */\nexport interface ObservationRead {\n\treadonly observationId: string;\n\treadonly text: string;\n\treadonly byteOffset: number;\n\treadonly byteLength: number;\n\treadonly nextOffset: number;\n\treadonly eof: boolean;\n\treadonly truncated: boolean;\n\treadonly sourceComplete: boolean;\n\t/** True when the requested byte range was snapped to UTF-8 boundaries. */\n\treadonly normalized: boolean;\n}\n\nexport type ObservationReadError =\n\t| \"observation-not-found\"\n\t| \"scope-mismatch\"\n\t| \"invalid-range\"\n\t| \"utf8-boundary\"\n\t| \"archive-unavailable\";\n\nexport type ObservationReadResult =\n\t| { readonly ok: true; readonly read: ObservationRead }\n\t| { readonly ok: false; readonly error: ObservationReadError };\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic observation views with a coverage gate — U1/U3.
|
|
3
|
+
*
|
|
4
|
+
* A view is a projection of a stored raw observation, never a rewrite of it.
|
|
5
|
+
* `chooseView` refuses any candidate that drops a required fact atom: a cheap
|
|
6
|
+
* representation is admissible only if it preserves the decision-relevant
|
|
7
|
+
* facts the current obligations need. `coverageStatus` is `unknown` when the
|
|
8
|
+
* input carries no required fact set — never silently "covered".
|
|
9
|
+
*/
|
|
10
|
+
import type { ObservationView, RawObservation } from "./types.ts";
|
|
11
|
+
export declare function estimateViewTokens(text: string): number;
|
|
12
|
+
/** A host-verifiable fact atom extracted from raw bytes, e.g. exitCode=1. */
|
|
13
|
+
export interface FactAtom {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
/** The verbatim text that must appear in a view for the atom to count as covered. */
|
|
16
|
+
readonly evidence: string;
|
|
17
|
+
readonly byteOffset: number;
|
|
18
|
+
readonly byteLength: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract host-verifiable fact atoms from raw bytes. `requiredFactIds` limits
|
|
22
|
+
* extraction to the caller's obligation set; when omitted, all recognized
|
|
23
|
+
* atoms are returned so a view can advertise what it preserves.
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractFacts(raw: Uint8Array, requiredFactIds?: readonly string[]): FactAtom[];
|
|
26
|
+
/**
|
|
27
|
+
* Build the candidate views for one observation. Every view records which
|
|
28
|
+
* fact atoms it preserves and which required atoms it would drop, so the
|
|
29
|
+
* selector can gate on coverage rather than token density alone.
|
|
30
|
+
*/
|
|
31
|
+
export declare function makeViews(observation: RawObservation, requiredFactIds?: readonly string[]): readonly ObservationView[];
|
|
32
|
+
/**
|
|
33
|
+
* Coverage-gated deterministic selection: the smallest view that preserves
|
|
34
|
+
* every required fact within budget. Returns null (infeasible) rather than
|
|
35
|
+
* silently dropping a required atom — the caller must widen the budget or keep
|
|
36
|
+
* the raw observation.
|
|
37
|
+
*/
|
|
38
|
+
export declare function chooseView(views: readonly ObservationView[], budgetTokens: number, requiredFactIds?: readonly string[]): ObservationView | null;
|
|
39
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/observation/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAA6B,eAAe,EAAuB,cAAc,EAAE,MAAM,YAAY,CAAC;AAOlH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AASD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,EAAE,CAyB7F;AAwDD;;;;GAIG;AACH,wBAAgB,SAAS,CACxB,WAAW,EAAE,cAAc,EAC3B,eAAe,GAAE,SAAS,MAAM,EAAO,GACrC,SAAS,eAAe,EAAE,CAkC5B;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,YAAY,EAAE,MAAM,EACpB,eAAe,GAAE,SAAS,MAAM,EAAO,GACrC,eAAe,GAAG,IAAI,CAqBxB","sourcesContent":["/**\n * Deterministic observation views with a coverage gate — U1/U3.\n *\n * A view is a projection of a stored raw observation, never a rewrite of it.\n * `chooseView` refuses any candidate that drops a required fact atom: a cheap\n * representation is admissible only if it preserves the decision-relevant\n * facts the current obligations need. `coverageStatus` is `unknown` when the\n * input carries no required fact set — never silently \"covered\".\n */\n\nimport { ensure, integer, text } from \"../metacognition/validation.ts\";\nimport { viewDigestOf } from \"./identity.ts\";\nimport type { ObservationCoverageStatus, ObservationView, ObservationViewKind, RawObservation } from \"./types.ts\";\n\nconst CHARS_PER_TOKEN = 4;\n/** Per-atom-class occurrence cap. Four classes stay well under any global bound. */\nconst MAX_FACTS_PER_ID = 32;\nconst MAX_VIEW_TEXT = 32_768;\n\nexport function estimateViewTokens(text: string): number {\n\treturn Math.max(1, Math.ceil(text.length / CHARS_PER_TOKEN));\n}\n\n/** A host-verifiable fact atom extracted from raw bytes, e.g. exitCode=1. */\nexport interface FactAtom {\n\treadonly id: string;\n\t/** The verbatim text that must appear in a view for the atom to count as covered. */\n\treadonly evidence: string;\n\treadonly byteOffset: number;\n\treadonly byteLength: number;\n}\n\nconst FACT_PATTERNS: readonly { readonly id: string; readonly re: RegExp }[] = [\n\t{ id: \"exit-code\", re: /exit code[:\\s]+(-?\\d+)|exitCode\\s*[=:]\\s*(-?\\d+)/i },\n\t{ id: \"test-failure\", re: /FAIL[:\\s]+([A-Za-z0-9_.\\-/]+)|✗\\s*([A-Za-z0-9_.\\-/]+)/ },\n\t{ id: \"permission-denied\", re: /permission[ _-]?denied|EACCES/i },\n\t{ id: \"error-marker\", re: /(?:error|errno|exception|traceback)[:\\s]/i },\n];\n\n/**\n * Extract host-verifiable fact atoms from raw bytes. `requiredFactIds` limits\n * extraction to the caller's obligation set; when omitted, all recognized\n * atoms are returned so a view can advertise what it preserves.\n */\nexport function extractFacts(raw: Uint8Array, requiredFactIds?: readonly string[]): FactAtom[] {\n\tconst decoded = new TextDecoder(\"utf-8\", { fatal: false }).decode(raw);\n\tconst encoder = new TextEncoder();\n\tconst wanted = requiredFactIds === undefined ? undefined : new Set(requiredFactIds);\n\tconst facts: FactAtom[] = [];\n\tfor (const { id, re } of FACT_PATTERNS) {\n\t\tif (wanted !== undefined && !wanted.has(id)) continue;\n\t\t// Per-id cap, not a shared running total: a log that repeats one atom\n\t\t// thousands of times must not starve a later pattern out of extraction\n\t\t// entirely, or a required atom silently disappears from every view.\n\t\tlet perId = 0;\n\t\tfor (const match of decoded.matchAll(new RegExp(re.source, re.flags.includes(\"g\") ? re.flags : `${re.flags}g`))) {\n\t\t\tif (perId >= MAX_FACTS_PER_ID) break;\n\t\t\tconst evidence = match[0];\n\t\t\tconst byteOffset = encoder.encode(decoded.slice(0, match.index ?? 0)).length;\n\t\t\tfacts.push({\n\t\t\t\tid,\n\t\t\t\tevidence,\n\t\t\t\tbyteOffset,\n\t\t\t\tbyteLength: encoder.encode(evidence).length,\n\t\t\t});\n\t\t\tperId += 1;\n\t\t}\n\t}\n\treturn facts;\n}\n\n/**\n * Collapse repeated identical atoms into one line that keeps the occurrence\n * count. Without this the evidence view of a log that repeats one failure is\n * larger than the raw text it was supposed to shrink, and the selector\n * correctly but uselessly falls back to full text.\n */\nfunction dedupeFacts(facts: readonly FactAtom[]): readonly { readonly fact: FactAtom; readonly count: number }[] {\n\tconst byKey = new Map<string, { fact: FactAtom; count: number }>();\n\tfor (const fact of facts) {\n\t\tconst key = `${fact.id}\\u0000${fact.evidence}`;\n\t\tconst existing = byKey.get(key);\n\t\tif (existing === undefined) byKey.set(key, { fact, count: 1 });\n\t\telse existing.count += 1;\n\t}\n\treturn [...byKey.values()];\n}\n\nfunction viewText(raw: Uint8Array, facts: readonly FactAtom[], kind: ObservationViewKind): string {\n\tconst decoded = new TextDecoder(\"utf-8\", { fatal: false }).decode(raw);\n\tswitch (kind) {\n\t\tcase \"full\":\n\t\t\treturn decoded;\n\t\tcase \"excerpt\": {\n\t\t\tif (decoded.length <= MAX_VIEW_TEXT) return decoded;\n\t\t\tconst head = decoded.slice(0, Math.floor(MAX_VIEW_TEXT / 2));\n\t\t\tconst tail = decoded.slice(-Math.floor(MAX_VIEW_TEXT / 2));\n\t\t\treturn `${head}\\n…[omitted ${decoded.length - MAX_VIEW_TEXT} chars]…\\n${tail}`;\n\t\t}\n\t\tcase \"evidence\":\n\t\t\treturn facts.length === 0\n\t\t\t\t? \"\"\n\t\t\t\t: dedupeFacts(facts)\n\t\t\t\t\t\t.map(({ fact, count }) =>\n\t\t\t\t\t\t\tcount === 1\n\t\t\t\t\t\t\t\t? `${fact.id} @${fact.byteOffset}: ${fact.evidence}`\n\t\t\t\t\t\t\t\t: `${fact.id} @${fact.byteOffset} \\u00d7${count}: ${fact.evidence}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join(\"\\n\")\n\t\t\t\t\t\t.slice(0, MAX_VIEW_TEXT);\n\t\tcase \"pointer\":\n\t\t\treturn `[observation ${raw.length} bytes; digest-bound; read via handle]`;\n\t}\n}\n\nfunction coverageFor(\n\tcovered: readonly string[],\n\trequired: readonly string[],\n): { status: ObservationCoverageStatus; missing: readonly string[] } {\n\tif (required.length === 0) return { status: \"unknown\", missing: [] };\n\tconst coveredSet = new Set(covered);\n\tconst missing = required.filter((id) => !coveredSet.has(id));\n\treturn { status: missing.length === 0 ? \"complete\" : \"partial\", missing };\n}\n\n/**\n * Build the candidate views for one observation. Every view records which\n * fact atoms it preserves and which required atoms it would drop, so the\n * selector can gate on coverage rather than token density alone.\n */\nexport function makeViews(\n\tobservation: RawObservation,\n\trequiredFactIds: readonly string[] = [],\n): readonly ObservationView[] {\n\ttext(observation.observationId, \"observationId\", 128);\n\tfor (const id of requiredFactIds) text(id, \"requiredFactId\", 256);\n\tconst facts = extractFacts(observation.bytes);\n\tconst coveredByKind: Record<ObservationViewKind, readonly string[]> = {\n\t\tfull: facts.map((f) => f.id),\n\t\texcerpt: facts.map((f) => f.id), // excerpt keeps head+tail; see note\n\t\tevidence: facts.map((f) => f.id),\n\t\tpointer: [],\n\t};\n\tconst kinds: readonly ObservationViewKind[] = [\"full\", \"excerpt\", \"evidence\", \"pointer\"];\n\treturn kinds.map((kind) => {\n\t\tconst body = viewText(observation.bytes, facts, kind);\n\t\tconst covered = coveredByKind[kind].filter(\n\t\t\t(id) => body.includes(id) || kind !== \"evidence\" || facts.some((f) => f.id === id),\n\t\t);\n\t\tconst { status, missing } = coverageFor(covered, requiredFactIds);\n\t\treturn Object.freeze({\n\t\t\tviewKind: kind,\n\t\t\tobservationId: observation.observationId,\n\t\t\tparentDigest: observation.rawDigest,\n\t\t\ttransformationDigest: viewDigestOf({\n\t\t\t\tobservationId: observation.observationId,\n\t\t\t\tviewKind: kind,\n\t\t\t\tparams: `req:${[...requiredFactIds].sort().join(\",\")}`,\n\t\t\t}),\n\t\t\ttext: body,\n\t\t\testimatedTokens: estimateViewTokens(body),\n\t\t\tcoveredFactIds: covered,\n\t\t\tmissingRequiredFactIds: missing,\n\t\t\tcoverageStatus: status,\n\t\t\ttaskVerdict: \"not-assessed\" as const,\n\t\t});\n\t});\n}\n\n/**\n * Coverage-gated deterministic selection: the smallest view that preserves\n * every required fact within budget. Returns null (infeasible) rather than\n * silently dropping a required atom — the caller must widen the budget or keep\n * the raw observation.\n */\nexport function chooseView(\n\tviews: readonly ObservationView[],\n\tbudgetTokens: number,\n\trequiredFactIds: readonly string[] = [],\n): ObservationView | null {\n\tinteger(budgetTokens, \"budgetTokens\");\n\tensure(views.length > 0, \"views must be nonempty\");\n\tfor (const id of requiredFactIds) text(id, \"requiredFactId\", 256);\n\tconst admissible = views.filter(\n\t\t(v) => v.estimatedTokens <= budgetTokens && requiredFactIds.every((id) => v.coveredFactIds.includes(id)),\n\t);\n\tif (admissible.length === 0) return null;\n\t// Smallest tokens wins; break ties toward the higher-fidelity kind.\n\tconst rank: Record<ObservationViewKind, number> = { full: 0, excerpt: 1, evidence: 2, pointer: 3 };\n\tlet best: ObservationView | undefined;\n\tfor (const view of admissible) {\n\t\tif (\n\t\t\tbest === undefined ||\n\t\t\tview.estimatedTokens < best.estimatedTokens ||\n\t\t\t(view.estimatedTokens === best.estimatedTokens && rank[view.viewKind] < rank[best.viewKind])\n\t\t) {\n\t\t\tbest = view;\n\t\t}\n\t}\n\treturn best ?? null;\n}\n"]}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic observation views with a coverage gate — U1/U3.
|
|
3
|
+
*
|
|
4
|
+
* A view is a projection of a stored raw observation, never a rewrite of it.
|
|
5
|
+
* `chooseView` refuses any candidate that drops a required fact atom: a cheap
|
|
6
|
+
* representation is admissible only if it preserves the decision-relevant
|
|
7
|
+
* facts the current obligations need. `coverageStatus` is `unknown` when the
|
|
8
|
+
* input carries no required fact set — never silently "covered".
|
|
9
|
+
*/
|
|
10
|
+
import { ensure, integer, text } from "../metacognition/validation.js";
|
|
11
|
+
import { viewDigestOf } from "./identity.js";
|
|
12
|
+
const CHARS_PER_TOKEN = 4;
|
|
13
|
+
/** Per-atom-class occurrence cap. Four classes stay well under any global bound. */
|
|
14
|
+
const MAX_FACTS_PER_ID = 32;
|
|
15
|
+
const MAX_VIEW_TEXT = 32_768;
|
|
16
|
+
export function estimateViewTokens(text) {
|
|
17
|
+
return Math.max(1, Math.ceil(text.length / CHARS_PER_TOKEN));
|
|
18
|
+
}
|
|
19
|
+
const FACT_PATTERNS = [
|
|
20
|
+
{ id: "exit-code", re: /exit code[:\s]+(-?\d+)|exitCode\s*[=:]\s*(-?\d+)/i },
|
|
21
|
+
{ id: "test-failure", re: /FAIL[:\s]+([A-Za-z0-9_.\-/]+)|✗\s*([A-Za-z0-9_.\-/]+)/ },
|
|
22
|
+
{ id: "permission-denied", re: /permission[ _-]?denied|EACCES/i },
|
|
23
|
+
{ id: "error-marker", re: /(?:error|errno|exception|traceback)[:\s]/i },
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Extract host-verifiable fact atoms from raw bytes. `requiredFactIds` limits
|
|
27
|
+
* extraction to the caller's obligation set; when omitted, all recognized
|
|
28
|
+
* atoms are returned so a view can advertise what it preserves.
|
|
29
|
+
*/
|
|
30
|
+
export function extractFacts(raw, requiredFactIds) {
|
|
31
|
+
const decoded = new TextDecoder("utf-8", { fatal: false }).decode(raw);
|
|
32
|
+
const encoder = new TextEncoder();
|
|
33
|
+
const wanted = requiredFactIds === undefined ? undefined : new Set(requiredFactIds);
|
|
34
|
+
const facts = [];
|
|
35
|
+
for (const { id, re } of FACT_PATTERNS) {
|
|
36
|
+
if (wanted !== undefined && !wanted.has(id))
|
|
37
|
+
continue;
|
|
38
|
+
// Per-id cap, not a shared running total: a log that repeats one atom
|
|
39
|
+
// thousands of times must not starve a later pattern out of extraction
|
|
40
|
+
// entirely, or a required atom silently disappears from every view.
|
|
41
|
+
let perId = 0;
|
|
42
|
+
for (const match of decoded.matchAll(new RegExp(re.source, re.flags.includes("g") ? re.flags : `${re.flags}g`))) {
|
|
43
|
+
if (perId >= MAX_FACTS_PER_ID)
|
|
44
|
+
break;
|
|
45
|
+
const evidence = match[0];
|
|
46
|
+
const byteOffset = encoder.encode(decoded.slice(0, match.index ?? 0)).length;
|
|
47
|
+
facts.push({
|
|
48
|
+
id,
|
|
49
|
+
evidence,
|
|
50
|
+
byteOffset,
|
|
51
|
+
byteLength: encoder.encode(evidence).length,
|
|
52
|
+
});
|
|
53
|
+
perId += 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return facts;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Collapse repeated identical atoms into one line that keeps the occurrence
|
|
60
|
+
* count. Without this the evidence view of a log that repeats one failure is
|
|
61
|
+
* larger than the raw text it was supposed to shrink, and the selector
|
|
62
|
+
* correctly but uselessly falls back to full text.
|
|
63
|
+
*/
|
|
64
|
+
function dedupeFacts(facts) {
|
|
65
|
+
const byKey = new Map();
|
|
66
|
+
for (const fact of facts) {
|
|
67
|
+
const key = `${fact.id}\u0000${fact.evidence}`;
|
|
68
|
+
const existing = byKey.get(key);
|
|
69
|
+
if (existing === undefined)
|
|
70
|
+
byKey.set(key, { fact, count: 1 });
|
|
71
|
+
else
|
|
72
|
+
existing.count += 1;
|
|
73
|
+
}
|
|
74
|
+
return [...byKey.values()];
|
|
75
|
+
}
|
|
76
|
+
function viewText(raw, facts, kind) {
|
|
77
|
+
const decoded = new TextDecoder("utf-8", { fatal: false }).decode(raw);
|
|
78
|
+
switch (kind) {
|
|
79
|
+
case "full":
|
|
80
|
+
return decoded;
|
|
81
|
+
case "excerpt": {
|
|
82
|
+
if (decoded.length <= MAX_VIEW_TEXT)
|
|
83
|
+
return decoded;
|
|
84
|
+
const head = decoded.slice(0, Math.floor(MAX_VIEW_TEXT / 2));
|
|
85
|
+
const tail = decoded.slice(-Math.floor(MAX_VIEW_TEXT / 2));
|
|
86
|
+
return `${head}\n…[omitted ${decoded.length - MAX_VIEW_TEXT} chars]…\n${tail}`;
|
|
87
|
+
}
|
|
88
|
+
case "evidence":
|
|
89
|
+
return facts.length === 0
|
|
90
|
+
? ""
|
|
91
|
+
: dedupeFacts(facts)
|
|
92
|
+
.map(({ fact, count }) => count === 1
|
|
93
|
+
? `${fact.id} @${fact.byteOffset}: ${fact.evidence}`
|
|
94
|
+
: `${fact.id} @${fact.byteOffset} \u00d7${count}: ${fact.evidence}`)
|
|
95
|
+
.join("\n")
|
|
96
|
+
.slice(0, MAX_VIEW_TEXT);
|
|
97
|
+
case "pointer":
|
|
98
|
+
return `[observation ${raw.length} bytes; digest-bound; read via handle]`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function coverageFor(covered, required) {
|
|
102
|
+
if (required.length === 0)
|
|
103
|
+
return { status: "unknown", missing: [] };
|
|
104
|
+
const coveredSet = new Set(covered);
|
|
105
|
+
const missing = required.filter((id) => !coveredSet.has(id));
|
|
106
|
+
return { status: missing.length === 0 ? "complete" : "partial", missing };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Build the candidate views for one observation. Every view records which
|
|
110
|
+
* fact atoms it preserves and which required atoms it would drop, so the
|
|
111
|
+
* selector can gate on coverage rather than token density alone.
|
|
112
|
+
*/
|
|
113
|
+
export function makeViews(observation, requiredFactIds = []) {
|
|
114
|
+
text(observation.observationId, "observationId", 128);
|
|
115
|
+
for (const id of requiredFactIds)
|
|
116
|
+
text(id, "requiredFactId", 256);
|
|
117
|
+
const facts = extractFacts(observation.bytes);
|
|
118
|
+
const coveredByKind = {
|
|
119
|
+
full: facts.map((f) => f.id),
|
|
120
|
+
excerpt: facts.map((f) => f.id), // excerpt keeps head+tail; see note
|
|
121
|
+
evidence: facts.map((f) => f.id),
|
|
122
|
+
pointer: [],
|
|
123
|
+
};
|
|
124
|
+
const kinds = ["full", "excerpt", "evidence", "pointer"];
|
|
125
|
+
return kinds.map((kind) => {
|
|
126
|
+
const body = viewText(observation.bytes, facts, kind);
|
|
127
|
+
const covered = coveredByKind[kind].filter((id) => body.includes(id) || kind !== "evidence" || facts.some((f) => f.id === id));
|
|
128
|
+
const { status, missing } = coverageFor(covered, requiredFactIds);
|
|
129
|
+
return Object.freeze({
|
|
130
|
+
viewKind: kind,
|
|
131
|
+
observationId: observation.observationId,
|
|
132
|
+
parentDigest: observation.rawDigest,
|
|
133
|
+
transformationDigest: viewDigestOf({
|
|
134
|
+
observationId: observation.observationId,
|
|
135
|
+
viewKind: kind,
|
|
136
|
+
params: `req:${[...requiredFactIds].sort().join(",")}`,
|
|
137
|
+
}),
|
|
138
|
+
text: body,
|
|
139
|
+
estimatedTokens: estimateViewTokens(body),
|
|
140
|
+
coveredFactIds: covered,
|
|
141
|
+
missingRequiredFactIds: missing,
|
|
142
|
+
coverageStatus: status,
|
|
143
|
+
taskVerdict: "not-assessed",
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Coverage-gated deterministic selection: the smallest view that preserves
|
|
149
|
+
* every required fact within budget. Returns null (infeasible) rather than
|
|
150
|
+
* silently dropping a required atom — the caller must widen the budget or keep
|
|
151
|
+
* the raw observation.
|
|
152
|
+
*/
|
|
153
|
+
export function chooseView(views, budgetTokens, requiredFactIds = []) {
|
|
154
|
+
integer(budgetTokens, "budgetTokens");
|
|
155
|
+
ensure(views.length > 0, "views must be nonempty");
|
|
156
|
+
for (const id of requiredFactIds)
|
|
157
|
+
text(id, "requiredFactId", 256);
|
|
158
|
+
const admissible = views.filter((v) => v.estimatedTokens <= budgetTokens && requiredFactIds.every((id) => v.coveredFactIds.includes(id)));
|
|
159
|
+
if (admissible.length === 0)
|
|
160
|
+
return null;
|
|
161
|
+
// Smallest tokens wins; break ties toward the higher-fidelity kind.
|
|
162
|
+
const rank = { full: 0, excerpt: 1, evidence: 2, pointer: 3 };
|
|
163
|
+
let best;
|
|
164
|
+
for (const view of admissible) {
|
|
165
|
+
if (best === undefined ||
|
|
166
|
+
view.estimatedTokens < best.estimatedTokens ||
|
|
167
|
+
(view.estimatedTokens === best.estimatedTokens && rank[view.viewKind] < rank[best.viewKind])) {
|
|
168
|
+
best = view;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return best ?? null;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/observation/view.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Deterministic observation views with a coverage gate — U1/U3.\n *\n * A view is a projection of a stored raw observation, never a rewrite of it.\n * `chooseView` refuses any candidate that drops a required fact atom: a cheap\n * representation is admissible only if it preserves the decision-relevant\n * facts the current obligations need. `coverageStatus` is `unknown` when the\n * input carries no required fact set — never silently \"covered\".\n */\n\nimport { ensure, integer, text } from \"../metacognition/validation.ts\";\nimport { viewDigestOf } from \"./identity.ts\";\nimport type { ObservationCoverageStatus, ObservationView, ObservationViewKind, RawObservation } from \"./types.ts\";\n\nconst CHARS_PER_TOKEN = 4;\n/** Per-atom-class occurrence cap. Four classes stay well under any global bound. */\nconst MAX_FACTS_PER_ID = 32;\nconst MAX_VIEW_TEXT = 32_768;\n\nexport function estimateViewTokens(text: string): number {\n\treturn Math.max(1, Math.ceil(text.length / CHARS_PER_TOKEN));\n}\n\n/** A host-verifiable fact atom extracted from raw bytes, e.g. exitCode=1. */\nexport interface FactAtom {\n\treadonly id: string;\n\t/** The verbatim text that must appear in a view for the atom to count as covered. */\n\treadonly evidence: string;\n\treadonly byteOffset: number;\n\treadonly byteLength: number;\n}\n\nconst FACT_PATTERNS: readonly { readonly id: string; readonly re: RegExp }[] = [\n\t{ id: \"exit-code\", re: /exit code[:\\s]+(-?\\d+)|exitCode\\s*[=:]\\s*(-?\\d+)/i },\n\t{ id: \"test-failure\", re: /FAIL[:\\s]+([A-Za-z0-9_.\\-/]+)|✗\\s*([A-Za-z0-9_.\\-/]+)/ },\n\t{ id: \"permission-denied\", re: /permission[ _-]?denied|EACCES/i },\n\t{ id: \"error-marker\", re: /(?:error|errno|exception|traceback)[:\\s]/i },\n];\n\n/**\n * Extract host-verifiable fact atoms from raw bytes. `requiredFactIds` limits\n * extraction to the caller's obligation set; when omitted, all recognized\n * atoms are returned so a view can advertise what it preserves.\n */\nexport function extractFacts(raw: Uint8Array, requiredFactIds?: readonly string[]): FactAtom[] {\n\tconst decoded = new TextDecoder(\"utf-8\", { fatal: false }).decode(raw);\n\tconst encoder = new TextEncoder();\n\tconst wanted = requiredFactIds === undefined ? undefined : new Set(requiredFactIds);\n\tconst facts: FactAtom[] = [];\n\tfor (const { id, re } of FACT_PATTERNS) {\n\t\tif (wanted !== undefined && !wanted.has(id)) continue;\n\t\t// Per-id cap, not a shared running total: a log that repeats one atom\n\t\t// thousands of times must not starve a later pattern out of extraction\n\t\t// entirely, or a required atom silently disappears from every view.\n\t\tlet perId = 0;\n\t\tfor (const match of decoded.matchAll(new RegExp(re.source, re.flags.includes(\"g\") ? re.flags : `${re.flags}g`))) {\n\t\t\tif (perId >= MAX_FACTS_PER_ID) break;\n\t\t\tconst evidence = match[0];\n\t\t\tconst byteOffset = encoder.encode(decoded.slice(0, match.index ?? 0)).length;\n\t\t\tfacts.push({\n\t\t\t\tid,\n\t\t\t\tevidence,\n\t\t\t\tbyteOffset,\n\t\t\t\tbyteLength: encoder.encode(evidence).length,\n\t\t\t});\n\t\t\tperId += 1;\n\t\t}\n\t}\n\treturn facts;\n}\n\n/**\n * Collapse repeated identical atoms into one line that keeps the occurrence\n * count. Without this the evidence view of a log that repeats one failure is\n * larger than the raw text it was supposed to shrink, and the selector\n * correctly but uselessly falls back to full text.\n */\nfunction dedupeFacts(facts: readonly FactAtom[]): readonly { readonly fact: FactAtom; readonly count: number }[] {\n\tconst byKey = new Map<string, { fact: FactAtom; count: number }>();\n\tfor (const fact of facts) {\n\t\tconst key = `${fact.id}\\u0000${fact.evidence}`;\n\t\tconst existing = byKey.get(key);\n\t\tif (existing === undefined) byKey.set(key, { fact, count: 1 });\n\t\telse existing.count += 1;\n\t}\n\treturn [...byKey.values()];\n}\n\nfunction viewText(raw: Uint8Array, facts: readonly FactAtom[], kind: ObservationViewKind): string {\n\tconst decoded = new TextDecoder(\"utf-8\", { fatal: false }).decode(raw);\n\tswitch (kind) {\n\t\tcase \"full\":\n\t\t\treturn decoded;\n\t\tcase \"excerpt\": {\n\t\t\tif (decoded.length <= MAX_VIEW_TEXT) return decoded;\n\t\t\tconst head = decoded.slice(0, Math.floor(MAX_VIEW_TEXT / 2));\n\t\t\tconst tail = decoded.slice(-Math.floor(MAX_VIEW_TEXT / 2));\n\t\t\treturn `${head}\\n…[omitted ${decoded.length - MAX_VIEW_TEXT} chars]…\\n${tail}`;\n\t\t}\n\t\tcase \"evidence\":\n\t\t\treturn facts.length === 0\n\t\t\t\t? \"\"\n\t\t\t\t: dedupeFacts(facts)\n\t\t\t\t\t\t.map(({ fact, count }) =>\n\t\t\t\t\t\t\tcount === 1\n\t\t\t\t\t\t\t\t? `${fact.id} @${fact.byteOffset}: ${fact.evidence}`\n\t\t\t\t\t\t\t\t: `${fact.id} @${fact.byteOffset} \\u00d7${count}: ${fact.evidence}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join(\"\\n\")\n\t\t\t\t\t\t.slice(0, MAX_VIEW_TEXT);\n\t\tcase \"pointer\":\n\t\t\treturn `[observation ${raw.length} bytes; digest-bound; read via handle]`;\n\t}\n}\n\nfunction coverageFor(\n\tcovered: readonly string[],\n\trequired: readonly string[],\n): { status: ObservationCoverageStatus; missing: readonly string[] } {\n\tif (required.length === 0) return { status: \"unknown\", missing: [] };\n\tconst coveredSet = new Set(covered);\n\tconst missing = required.filter((id) => !coveredSet.has(id));\n\treturn { status: missing.length === 0 ? \"complete\" : \"partial\", missing };\n}\n\n/**\n * Build the candidate views for one observation. Every view records which\n * fact atoms it preserves and which required atoms it would drop, so the\n * selector can gate on coverage rather than token density alone.\n */\nexport function makeViews(\n\tobservation: RawObservation,\n\trequiredFactIds: readonly string[] = [],\n): readonly ObservationView[] {\n\ttext(observation.observationId, \"observationId\", 128);\n\tfor (const id of requiredFactIds) text(id, \"requiredFactId\", 256);\n\tconst facts = extractFacts(observation.bytes);\n\tconst coveredByKind: Record<ObservationViewKind, readonly string[]> = {\n\t\tfull: facts.map((f) => f.id),\n\t\texcerpt: facts.map((f) => f.id), // excerpt keeps head+tail; see note\n\t\tevidence: facts.map((f) => f.id),\n\t\tpointer: [],\n\t};\n\tconst kinds: readonly ObservationViewKind[] = [\"full\", \"excerpt\", \"evidence\", \"pointer\"];\n\treturn kinds.map((kind) => {\n\t\tconst body = viewText(observation.bytes, facts, kind);\n\t\tconst covered = coveredByKind[kind].filter(\n\t\t\t(id) => body.includes(id) || kind !== \"evidence\" || facts.some((f) => f.id === id),\n\t\t);\n\t\tconst { status, missing } = coverageFor(covered, requiredFactIds);\n\t\treturn Object.freeze({\n\t\t\tviewKind: kind,\n\t\t\tobservationId: observation.observationId,\n\t\t\tparentDigest: observation.rawDigest,\n\t\t\ttransformationDigest: viewDigestOf({\n\t\t\t\tobservationId: observation.observationId,\n\t\t\t\tviewKind: kind,\n\t\t\t\tparams: `req:${[...requiredFactIds].sort().join(\",\")}`,\n\t\t\t}),\n\t\t\ttext: body,\n\t\t\testimatedTokens: estimateViewTokens(body),\n\t\t\tcoveredFactIds: covered,\n\t\t\tmissingRequiredFactIds: missing,\n\t\t\tcoverageStatus: status,\n\t\t\ttaskVerdict: \"not-assessed\" as const,\n\t\t});\n\t});\n}\n\n/**\n * Coverage-gated deterministic selection: the smallest view that preserves\n * every required fact within budget. Returns null (infeasible) rather than\n * silently dropping a required atom — the caller must widen the budget or keep\n * the raw observation.\n */\nexport function chooseView(\n\tviews: readonly ObservationView[],\n\tbudgetTokens: number,\n\trequiredFactIds: readonly string[] = [],\n): ObservationView | null {\n\tinteger(budgetTokens, \"budgetTokens\");\n\tensure(views.length > 0, \"views must be nonempty\");\n\tfor (const id of requiredFactIds) text(id, \"requiredFactId\", 256);\n\tconst admissible = views.filter(\n\t\t(v) => v.estimatedTokens <= budgetTokens && requiredFactIds.every((id) => v.coveredFactIds.includes(id)),\n\t);\n\tif (admissible.length === 0) return null;\n\t// Smallest tokens wins; break ties toward the higher-fidelity kind.\n\tconst rank: Record<ObservationViewKind, number> = { full: 0, excerpt: 1, evidence: 2, pointer: 3 };\n\tlet best: ObservationView | undefined;\n\tfor (const view of admissible) {\n\t\tif (\n\t\t\tbest === undefined ||\n\t\t\tview.estimatedTokens < best.estimatedTokens ||\n\t\t\t(view.estimatedTokens === best.estimatedTokens && rank[view.viewKind] < rank[best.viewKind])\n\t\t) {\n\t\t\tbest = view;\n\t\t}\n\t}\n\treturn best ?? null;\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Metacognitive Control Kernel
|
|
2
|
+
|
|
3
|
+
`src/metacognition/` implements the observation / control / evaluation loop from
|
|
4
|
+
`docs/OMK_metacognitive_control_algorithms_2026-09-19.md`, on top of the
|
|
5
|
+
skill-and-knowledge control kernel from `docs/OMK_skill_knowledge_control_2026-09-19.zip`.
|
|
6
|
+
|
|
7
|
+
This is a decision-rules library, not a performance claim. It manages what the
|
|
8
|
+
agent *expects*, which *obligations* remain, whether *checks* can actually
|
|
9
|
+
detect the defects they cover, and when a *strategy* should switch — all as
|
|
10
|
+
host-owned structured state, never as model self-report.
|
|
11
|
+
|
|
12
|
+
## Modules
|
|
13
|
+
|
|
14
|
+
| Module | Spec | Purpose |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `knowledge.ts` | §13 core | Claim/evidence gap inspection (`inspectKnowledge`) |
|
|
17
|
+
| `knowledge-action.ts` | §13 core | Bounded next action (`nextKnowledgeAction`) |
|
|
18
|
+
| `skills.ts` | §13 core | Capability-coverage skill planning (`planSkills`) |
|
|
19
|
+
| `retrieval.ts` | §13 core | Local BM25 (`searchCorpus`), owned-promise `AcquisitionPool` |
|
|
20
|
+
| `context7.ts` | §13 core | Approved-egress Context7 GET adapter (`Context7Client`) |
|
|
21
|
+
| `runtime-bridge.ts` | §13 attach | ClaimGraph/ObservationNode → kernel inputs (`toMetaState`) |
|
|
22
|
+
| `evaluation.ts` | §11, §15 | DR offline estimator, experience records, completion metrics |
|
|
23
|
+
| `observe.ts` | §13 observe | Observation-mode diagnostics (`attachMetaDiagnostics`) |
|
|
24
|
+
| `obligations.ts` | A / §4 | Change-atom rules → candidate vs required obligations |
|
|
25
|
+
| `predictions.ts` | B / §5 | Pre-registered prediction ledger, Brier/surprise scoring |
|
|
26
|
+
| `decision.ts` | C / §6 | Finite Bayes risk + one-step VOI (`experimentValue`) |
|
|
27
|
+
| `verifier.ts` | D / §7 | Obligation-scoped negative-control evaluation (`evaluateVerifier`) |
|
|
28
|
+
| `calibration.ts` | E+G / §8, §10 | Condition-bucket Beta records + drift demotion |
|
|
29
|
+
| `state.ts` | §3, §9.5 | `MetaState` tuple and the three finish states |
|
|
30
|
+
| `policy.ts` | F / §9, §14 | Feasibility gating + priority-table action selection |
|
|
31
|
+
| `checkpoint.ts` | §9.4 | One ordered checkpoint evaluation (`checkpoint`) |
|
|
32
|
+
|
|
33
|
+
## Invariants enforced
|
|
34
|
+
|
|
35
|
+
- Required approvals and required checks are hard constraints, not optimization
|
|
36
|
+
inputs.
|
|
37
|
+
- Predictions are registered before outcomes and never overwritten; edits append.
|
|
38
|
+
- Model-produced obligations stay candidates until host facts promote them.
|
|
39
|
+
- Mutant counts exclude compile-broken, environment-failed, and equivalent
|
|
40
|
+
mutants; an empty denominator reports `unknown`, never a score.
|
|
41
|
+
- `max VOI <= 0` never implies verified completion; receipts must bind to the
|
|
42
|
+
current candidate hash.
|
|
43
|
+
- Environment failures are recorded separately from code failures — neither
|
|
44
|
+
inflates nor silently discards the other.
|
|
45
|
+
|
|
46
|
+
## Tests
|
|
47
|
+
|
|
48
|
+
`test/metacognition-*.test.ts` — 94 tests, including the 13 numerical checks
|
|
49
|
+
ported from `check_examples.py` (Brier 0.9025 at p=0.95 failure, VOI 0.84,
|
|
50
|
+
XOR two-bit synergy 0.40, probability-vector rejection) and the reference
|
|
51
|
+
kernel's contract tests.
|
|
@@ -3,6 +3,65 @@
|
|
|
3
3
|
확인일: 2026-09-09. 생성기와 공급자 어댑터를 수정한 뒤 `npm run models:refresh`로
|
|
4
4
|
두 카탈로그를 재생성했다. 생성 파일을 손으로 수정하지 않았다.
|
|
5
5
|
|
|
6
|
+
## 2026-09-19 갱신: 라이브 재생성과 생성기 결함 3건 교정
|
|
7
|
+
|
|
8
|
+
`npm run models:refresh`를 종료0으로 재생성했다(전 소스 응답, `--allow-partial` 미사용,
|
|
9
|
+
키 없는 Zyloo는 정적 6개 유지). 결과는 **39 providers, 1,795→1,799 모델**, 추가 4·제거 0·
|
|
10
|
+
변경 22(가격 20, OpenRouter 선언 thinking 2), 이미지 카탈로그 54개 변화 없음.
|
|
11
|
+
|
|
12
|
+
첫 재생성에서는 제거 4·변경 220이 나왔고, 그중 상류 변화가 아닌 항목이 셋이었다.
|
|
13
|
+
각각 실패하는 검사를 먼저 쓰고(11개 RED) 생성기를 고친 뒤 다시 생성했다.
|
|
14
|
+
|
|
15
|
+
| 결함 | 원인 | 조치 |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `kimi-coding` 공급자 4개 전부 소실 | models.dev가 `kimi-for-coding` 키를 `kimi-code-plan-global`(api.kimi.ai)·`kimi-code-plan-cn`(api.kimi.com)으로 분리. 생성기는 옛 키만 읽어 조용히 빈 결과 | 세 키를 순서대로 조회. OMK endpoint(`api.kimi.com/coding`)·헤더·thinking 맵은 그대로. `kimi-coding-catalog.test.ts` |
|
|
18
|
+
| cursor 143·devin 55개 고정-노력 레인에 `xhigh/max` 추가 | 직전 커밋은 `--cursor-only`로 가족 단위 pass를 우회했지만 전체 재생성은 `applyModelMetadata`(Fable→xhigh/max, Opus 5→전체 사다리 등)를 정적 레인에도 적용 | devin/cursor 항목을 pass 이후에 붙여 fast path와 동일하게 유지. `fixed-effort-lanes.test.ts`가 정적 카탈로그와 생성 결과의 동일성을 검사 |
|
|
19
|
+
| OpenCode Zen `deepseek-v4.1-flash`가 구형 V4 맵(`high`, `xhigh→max`)만 받음 | V4.1 계약 보정 조건이 `opencode-go`만 인식 | [Zen 문서](https://opencode.ai/docs/zen/)가 같은 `chat/completions` gateway를 명시하므로 `opencode`도 `off/low/high/max`·`max_tokens`·`supportsReasoningEffort` 적용. `deepseek-v41-native.test.ts` route에 추가 |
|
|
20
|
+
|
|
21
|
+
두 번째 결함은 cursor/devin 항목이 정적 카탈로그와 다르게 저장될 때 즉시 실패하므로,
|
|
22
|
+
앞으로 fast path와 전체 재생성이 갈라지면 검사에서 드러난다.
|
|
23
|
+
|
|
24
|
+
### 추가된 항목
|
|
25
|
+
|
|
26
|
+
| 공급자 | 요청 ID | thinking | 가격(1M) | 근거 |
|
|
27
|
+
| --- | --- | --- | --- | --- |
|
|
28
|
+
| `opencode` | `deepseek-v4.1-flash` | `off/low/high/max`, `thinking.type`+`reasoning_effort`, `max_tokens` | $0.30/$1.20, cache $0.006 | Zen 문서 endpoint·가격표 |
|
|
29
|
+
| `opencode` | `qwen3.8-flash` | Messages 예산 경로(기존 Zen Qwen과 동일) | $0.15/$0.47, cache read $0.016·write $0.20 | Zen 문서 |
|
|
30
|
+
| `openrouter` | `z-ai/glm-5.3-flashx` | mandatory, `low/high/max` (route 선언) | $0.37/$1.25, cache $0.075 | OpenRouter `created` 09-18 |
|
|
31
|
+
| `openrouter` | `prism-ml/ternary-bonsai-2-27b` | optional off, `medium/xhigh` (route 선언) | $0.075/$0.50 | OpenRouter `created` 09-18 |
|
|
32
|
+
|
|
33
|
+
### 상류 변경(가격·선언)
|
|
34
|
+
|
|
35
|
+
- OpenCode Zen·Vercel의 `gpt-5.6-sol`은 "50% Off" 표시가 끝나 $4/$20(cache $0.40/$5)로 복귀. Vercel `gpt-5.6-sol-fast`는 $8/$40.
|
|
36
|
+
- OpenRouter DeepSeek 계열 인하: `deepseek-v4.1-flash` $0.15/$0.60, `deepseek-v4-pro` $0.54/$1.09, `-latest` 별칭 3개 동반 조정.
|
|
37
|
+
목록 값이며 DeepSeek 직접 API의 시간대별 가격과 다르다.
|
|
38
|
+
- OpenRouter `moonshotai/kimi-k3`·`~moonshotai/kimi-latest` $1.70/$8.50, `z-ai/glm-5.3` $0.91/$2.86, `meta/muse-glimmer-30b` $0.35/$1.50, Nemotron 3 Ultra·3.5 Lightning 출력 상한 상향.
|
|
39
|
+
- `upstage/solar-pro-3`(`off/minimal~high`)·`solar-pro4`(`off/minimal~max`)가 route 선언을 얻어 thinking 맵이 생겼다.
|
|
40
|
+
|
|
41
|
+
### 조사했으나 넣지 않은 항목
|
|
42
|
+
|
|
43
|
+
- **Amazon Bedrock Kimi K3** (09-18 GA). [모델 카드](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-moonshot-ai-kimi-k3.html)
|
|
44
|
+
기준 ID `global.moonshotai.kimi-k3`(Global $3/$15, cache read $0.30·write $3.75) ·
|
|
45
|
+
`us.moonshotai.kimi-k3`(US $3.30/$16.50), in-region 없음, 1M context, 이미지 입력, Converse·도구·스트리밍 지원.
|
|
46
|
+
같은 카드가 "Converse는 이전 턴의 reasoning content가 포함되면 `InternalServerException`"을 명시하는데,
|
|
47
|
+
OMK `amazon-bedrock`은 non-Claude 모델의 thinking을 `reasoningContent`로 그대로 replay한다(`convertMessages`).
|
|
48
|
+
카탈로그만 넣으면 두 번째 턴부터 실패하는 경로를 광고하므로, 공급자에서 이전 턴 reasoning을 제거하는
|
|
49
|
+
수정과 유료 실검증을 묶은 후속 단위로 미룬다. models.dev bedrock 목록에도 아직 없다.
|
|
50
|
+
- **Qwen3.8-Omni-Flash** (Alibaba, 09-18): OpenRouter·Vercel·models.dev의 tool 지원 목록에 없다. Model Studio 직접 경로는 OMK 내장 공급자가 아니다.
|
|
51
|
+
- **Gemini 3.8 Live / Live Extended Thinking** (09-15~16): 오디오 네이티브 경로로 코딩 카탈로그 소스에 없다.
|
|
52
|
+
- **GPT-6 Astra Law** (`gpt-6-astra-law`): OpenAI가 "coming soon"으로만 공지, API 미제공.
|
|
53
|
+
- **Union Alpha**: `stealth/union-alpha`는 09-18 갱신에서 이미 빠졌고, 정식 `unbiased/pareto`($2.50/$7.50, cache $0.25, thinking 미선언)가 HEAD에 있다. 이번 갱신에서 변화 없음.
|
|
54
|
+
|
|
55
|
+
### 검증과 한계
|
|
56
|
+
|
|
57
|
+
표적 vitest 13파일 **149개 통과**(신규 `fixed-effort-lanes`·`kimi-coding-catalog`, 확장한
|
|
58
|
+
`deepseek-v41-native` 포함), 전체 `tsgo --noEmit`, 변경 파일 Biome, module-size·import-cycles
|
|
59
|
+
baseline, `git diff --check` 모두 종료0. 공급자 추론, 전체 `npm run check`, build/install,
|
|
60
|
+
commit/push는 실행하지 않았다. 계정별 사용 가능 여부와 실제 청구액은 검증 범위 밖이다.
|
|
61
|
+
|
|
62
|
+
변경 단위: `packages/ai/scripts/{generate-models,catalog-thinking}.ts`, 생성 카탈로그, 검사 3파일, 본 문서.
|
|
63
|
+
제안 메시지: `fix(ai): 모델 카탈로그 09-19 갱신과 생성기 결함 교정 (kimi-coding 소실·고정 레인 확장·Zen V4.1 계약)`.
|
|
64
|
+
|
|
6
65
|
## 2026-09-17 후속: OpenCode Go DeepSeek V4.1 ID 변경
|
|
7
66
|
|
|
8
67
|
[OpenCode Go 공식 endpoint 목록](https://opencode.ai/docs/go/)의 현재 ID는
|
package/docs/providers.md
CHANGED
|
@@ -271,6 +271,7 @@ omk
|
|
|
271
271
|
| Fireworks | `FIREWORKS_API_KEY` | `fireworks` |
|
|
272
272
|
| Together AI | `TOGETHER_API_KEY` | `together` |
|
|
273
273
|
| Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
|
|
274
|
+
| WorkBuddy (CodeBuddy) | `WORKBUDDY_API_KEY` | `workbuddy` |
|
|
274
275
|
| Meta Model API | `META_API_KEY` (or `META_MODEL_API_KEY`, `MODEL_API_KEY`) | `meta` |
|
|
275
276
|
| MiniMax | `MINIMAX_API_KEY` | `minimax` |
|
|
276
277
|
| MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
|
|
@@ -282,6 +283,58 @@ omk
|
|
|
282
283
|
|
|
283
284
|
Reference for environment variables and `auth.json` keys: [`const envMap`](https://github.com/dmae97/omk/blob/main/packages/ai/src/env-api-keys.ts) in [`packages/ai/src/env-api-keys.ts`](https://github.com/dmae97/omk/blob/main/packages/ai/src/env-api-keys.ts).
|
|
284
285
|
|
|
286
|
+
#### WorkBuddy (Tencent CodeBuddy)
|
|
287
|
+
|
|
288
|
+
The cloud inference behind Tencent's CodeBuddy / WorkBuddy agents. Plan keys start
|
|
289
|
+
with `ck_` and are issued by the CodeBuddy login flow:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
export WORKBUDDY_API_KEY=ck_...
|
|
293
|
+
omk --provider workbuddy --model glm-5.3
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Endpoint and limits, verified against the live service on 2026-09-19:
|
|
297
|
+
|
|
298
|
+
- Chat requests go to `https://www.workbuddy.ai/v2/chat/completions` and must
|
|
299
|
+
stream; a non-streaming request is rejected. The same key is accepted by
|
|
300
|
+
`www.codebuddy.ai`, not by the `*.cn` hosts.
|
|
301
|
+
- The first message must be a `system` message. OMK sends the system prompt in
|
|
302
|
+
that position and prepends an empty one when a session has no system prompt.
|
|
303
|
+
- `max_tokens` carries the output cap; `max_completion_tokens` is ignored
|
|
304
|
+
upstream.
|
|
305
|
+
- Images are sent as data URIs, which is the only form the endpoint accepts.
|
|
306
|
+
- Thinking levels expose only the effort values the provider declares for that
|
|
307
|
+
model (`glm-5.3`: low/high/max, `glm-5.2`: high/xhigh, `gpt-5.6-*`:
|
|
308
|
+
low/medium/high/xhigh, …). The endpoint accepts `reasoning_effort`, but its
|
|
309
|
+
effect on reasoning volume is not verified, and no `off` value is offered
|
|
310
|
+
because none was verified. Thinking can therefore not be disabled per request.
|
|
311
|
+
- Model entitlement is per plan: the built-in catalog lists the 27 lanes verified
|
|
312
|
+
for one account, including eight the CLI's bundled product JSON never declares
|
|
313
|
+
(`claude-opus-5`, `claude-opus-4.6`, `claude-sonnet-4.6`,
|
|
314
|
+
`deepseek-v4.1-flash`, `gemini-3.8-flash`, `gpt-6-astra`, `grok-4.6`,
|
|
315
|
+
`hy4-preview`) which a cross-sweep of this repository's own model ids found.
|
|
316
|
+
`glm-5.0` answered `429` while its siblings answered `200`, so it is not
|
|
317
|
+
listed; the CLI's role aliases (`fast-model`, `balanced-model`,
|
|
318
|
+
`primary-model`, `deep-model`) resolve server-side to targets this catalog
|
|
319
|
+
cannot declare and are not listed either.
|
|
320
|
+
- Billing is metered in the provider's own credit unit, which OMK reports as
|
|
321
|
+
zero cost rather than inventing a USD rate. Measured per-call charges on one
|
|
322
|
+
account (small prompts): `claude-opus-5` 0.26, `claude-opus-4.6` 0.20,
|
|
323
|
+
`claude-sonnet-4.6` 0.12, `grok-4.6` 0.06–0.08, `gpt-5.6-sol` 0.04,
|
|
324
|
+
`gemini-3.8-flash` 0.02–0.06, `glm-5.3` 0.01, and 0 credits on `hy3`,
|
|
325
|
+
`deepseek-v3-0324`, `deepseek-v4.1-flash`, `glm-5.2`, `kimi-k2.5/k2.6` and
|
|
326
|
+
`minimax-m3`. A charge scales with tokens, so these are magnitudes, not
|
|
327
|
+
tariffs.
|
|
328
|
+
- Plan allowances (provider documentation, 2026-09-19): Free 100 credits/month,
|
|
329
|
+
Pro $10/month or $96/year for 2,000 credits/month, plus a limited-time
|
|
330
|
+
activity bonus of 30 credits/day on Free and 50/day on Pro. Credits are issued
|
|
331
|
+
monthly, do not carry over, and new accounts get 250 credits valid for 14 days;
|
|
332
|
+
Pro has a 7-day trial of 500 credits. Check the provider console for the
|
|
333
|
+
account's own balance: at the measured rates, the Free plan's 100 credits is
|
|
334
|
+
roughly 380 calls at `claude-opus-5` size, ~830 at `claude-sonnet-4.6`, and
|
|
335
|
+
1,600-5,000 at `gemini-3.8-flash`, while the 0-credit lanes above did not draw
|
|
336
|
+
on the allowance at all in these probes.
|
|
337
|
+
|
|
285
338
|
#### NVIDIA NIM
|
|
286
339
|
|
|
287
340
|
Set `NVIDIA_API_KEY` and select a currently listed NVIDIA model with `/model`.
|