@deepstrike/sdk 0.2.39 → 0.2.40
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/README.md +61 -31
- package/dist/collaboration/contract.d.ts +2 -2
- package/dist/collaboration/contract.js +2 -2
- package/dist/collaboration/handoff.d.ts +2 -14
- package/dist/collaboration/handoff.js +1 -17
- package/dist/collaboration/harness.d.ts +16 -47
- package/dist/collaboration/harness.js +57 -158
- package/dist/collaboration/index.d.ts +2 -2
- package/dist/collaboration/index.js +1 -2
- package/dist/collaboration/modes/creator-verifier.js +42 -6
- package/dist/collaboration/pool.d.ts +8 -0
- package/dist/collaboration/pool.js +56 -3
- package/dist/harness/harness.d.ts +97 -97
- package/dist/harness/harness.js +190 -144
- package/dist/harness/judge.d.ts +3 -2
- package/dist/harness/judge.js +7 -3
- package/dist/harness/public.d.ts +5 -3
- package/dist/harness/public.js +3 -2
- package/dist/index.d.ts +22 -7
- package/dist/index.js +8 -1
- package/dist/kernel.d.ts +12 -39
- package/dist/memory/agent.d.ts +8 -41
- package/dist/memory/agent.js +34 -117
- package/dist/memory/extraction.d.ts +4 -0
- package/dist/memory/extraction.js +79 -0
- package/dist/memory/in-memory-store.d.ts +28 -15
- package/dist/memory/in-memory-store.js +74 -25
- package/dist/memory/protocols.d.ts +56 -56
- package/dist/memory/protocols.js +1 -0
- package/dist/memory/public.d.ts +3 -1
- package/dist/memory/public.js +1 -0
- package/dist/memory/ranking.d.ts +33 -0
- package/dist/memory/ranking.js +77 -0
- package/dist/memory/retention.d.ts +17 -0
- package/dist/memory/retention.js +54 -0
- package/dist/os/public.d.ts +3 -3
- package/dist/os/public.js +1 -1
- package/dist/providers/base.d.ts +8 -0
- package/dist/providers/base.js +0 -0
- package/dist/providers/gemini.js +12 -0
- package/dist/providers/ollama.js +3 -1
- package/dist/providers/openai-responses.js +9 -2
- package/dist/providers/profiles.d.ts +5 -3
- package/dist/providers/profiles.js +3 -3
- package/dist/runtime/context-policy.d.ts +35 -0
- package/dist/runtime/context-policy.js +66 -0
- package/dist/runtime/eval.d.ts +6 -2
- package/dist/runtime/eval.js +2 -2
- package/dist/runtime/event-stream.d.ts +9 -0
- package/dist/runtime/event-stream.js +25 -11
- package/dist/runtime/execution-plane.d.ts +5 -1
- package/dist/runtime/execution-plane.js +9 -3
- package/dist/runtime/facade.js +2 -1
- package/dist/runtime/kernel-event-log.d.ts +0 -2
- package/dist/runtime/kernel-event-log.js +61 -13
- package/dist/runtime/kernel-primitives-dashboard.js +1 -1
- package/dist/runtime/kernel-rebuild.d.ts +13 -0
- package/dist/runtime/kernel-rebuild.js +75 -0
- package/dist/runtime/kernel-step.d.ts +157 -8
- package/dist/runtime/kernel-step.js +220 -7
- package/dist/runtime/kernel-transaction-log.d.ts +61 -0
- package/dist/runtime/kernel-transaction-log.js +149 -0
- package/dist/runtime/large-result-spool.d.ts +3 -1
- package/dist/runtime/large-result-spool.js +24 -5
- package/dist/runtime/loop-driver.d.ts +1 -1
- package/dist/runtime/loop-driver.js +2 -7
- package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
- package/dist/runtime/mcp-proxy-plane.js +23 -6
- package/dist/runtime/os-profile.d.ts +9 -10
- package/dist/runtime/os-profile.js +14 -10
- package/dist/runtime/os-snapshot.d.ts +19 -0
- package/dist/runtime/os-snapshot.js +33 -3
- package/dist/runtime/process-sandbox-plane.js +16 -11
- package/dist/runtime/reaction-checkpoint.d.ts +51 -0
- package/dist/runtime/reaction-checkpoint.js +83 -0
- package/dist/runtime/reactive-session.d.ts +9 -3
- package/dist/runtime/reactive-session.js +44 -14
- package/dist/runtime/reliability.d.ts +48 -0
- package/dist/runtime/reliability.js +86 -0
- package/dist/runtime/remote-vpc-plane.js +4 -3
- package/dist/runtime/run-group.d.ts +38 -35
- package/dist/runtime/run-group.js +97 -54
- package/dist/runtime/runner.d.ts +117 -78
- package/dist/runtime/runner.js +1516 -1197
- package/dist/runtime/session-log.d.ts +71 -12
- package/dist/runtime/session-log.js +192 -32
- package/dist/runtime/session-repair.d.ts +11 -7
- package/dist/runtime/session-repair.js +11 -8
- package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
- package/dist/runtime/sub-agent-orchestrator.js +45 -18
- package/dist/signals/gateway.d.ts +23 -10
- package/dist/signals/gateway.js +81 -17
- package/dist/signals/scheduled.js +0 -1
- package/dist/signals/types.d.ts +21 -13
- package/dist/skills/loader.js +12 -2
- package/dist/tools/index.d.ts +2 -0
- package/dist/types/agent.d.ts +40 -1
- package/dist/types/agent.js +61 -1
- package/dist/types.d.ts +6 -1
- package/dist/workflow/public.d.ts +2 -3
- package/dist/workflow/public.js +0 -1
- package/package.json +2 -2
|
@@ -19,67 +19,73 @@ export interface SessionData {
|
|
|
19
19
|
createdAtMs: number;
|
|
20
20
|
updatedAtMs: number;
|
|
21
21
|
}
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
insightsProcessed: number;
|
|
29
|
-
duplicatesRemoved: number;
|
|
30
|
-
conflictsResolved: number;
|
|
31
|
-
entriesAdded: number;
|
|
32
|
-
}
|
|
33
|
-
export interface CurationResult {
|
|
34
|
-
toAdd: MemoryEntry[];
|
|
35
|
-
/** Indices into the `existingMemories` array passed to `DreamStore.loadMemories`. */
|
|
36
|
-
toRemoveIndices: number[];
|
|
37
|
-
stats: CurationStats;
|
|
22
|
+
export type MemoryKind = "user" | "feedback" | "project" | "reference";
|
|
23
|
+
export type MemoryAuthor = "model" | "host" | "extraction";
|
|
24
|
+
export type MemoryTrustLevel = "untrusted" | "user_asserted" | "host_verified";
|
|
25
|
+
export interface MemoryScope {
|
|
26
|
+
tenant_id: string;
|
|
27
|
+
namespace: string;
|
|
38
28
|
}
|
|
39
|
-
export interface
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
search(agentId: string, query: string, topK?: number): Promise<MemoryEntry[]>;
|
|
45
|
-
/** Persist a completed session for future consolidation via `Agent.dream()`. */
|
|
46
|
-
saveSession(data: SessionData): Promise<void>;
|
|
29
|
+
export interface MemoryProvenance {
|
|
30
|
+
session_id?: string;
|
|
31
|
+
author: MemoryAuthor;
|
|
32
|
+
trust: MemoryTrustLevel;
|
|
33
|
+
evidence_refs: string[];
|
|
47
34
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
export interface MemoryMetadata {
|
|
35
|
+
export interface MemoryRecord {
|
|
36
|
+
record_id: string;
|
|
37
|
+
scope: MemoryScope;
|
|
52
38
|
name: string;
|
|
39
|
+
kind: MemoryKind;
|
|
40
|
+
content: string;
|
|
53
41
|
description: string;
|
|
54
|
-
|
|
42
|
+
provenance: MemoryProvenance;
|
|
55
43
|
created_at: number;
|
|
56
44
|
updated_at: number;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
relative_date?: string;
|
|
64
|
-
external_url?: string;
|
|
65
|
-
ticket_ref?: string;
|
|
45
|
+
last_recalled_at?: number;
|
|
46
|
+
recall_count: number;
|
|
47
|
+
confidence: number;
|
|
48
|
+
links: string[];
|
|
49
|
+
pinned: boolean;
|
|
50
|
+
ttl_days?: number;
|
|
66
51
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
export interface MemoryRecall {
|
|
53
|
+
record: MemoryRecord;
|
|
54
|
+
score: number;
|
|
55
|
+
why: string;
|
|
56
|
+
}
|
|
57
|
+
/** One record's recall lifecycle, mirrored from the kernel's `memory_recalled` observation. */
|
|
58
|
+
export interface MemoryRecallLifecycle {
|
|
59
|
+
record_id: string;
|
|
60
|
+
recall_count: number;
|
|
61
|
+
last_recalled_at: number;
|
|
62
|
+
}
|
|
63
|
+
export interface DreamStore {
|
|
64
|
+
/** The only durable memory mutation. Callers must reach this through the kernel WriteMemory gate. */
|
|
65
|
+
upsert(agentId: string, record: MemoryRecord): Promise<void>;
|
|
66
|
+
/** Semantic search over the agent's long-term memories. Called on demand during a run. */
|
|
67
|
+
search(agentId: string, query: MemoryQuery): Promise<MemoryRecall[]>;
|
|
68
|
+
/** Persist the completed session before the runner performs its one extraction pass. */
|
|
69
|
+
saveSession(data: SessionData): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* M3: mirror the kernel's journaled recall lifecycle into the durable store so recall history
|
|
72
|
+
* (count + last-recalled turn) survives across sessions. Optional: a store that does not track
|
|
73
|
+
* recall history omits it. The runner calls it when it observes `memory_recalled`.
|
|
74
|
+
*/
|
|
75
|
+
recordRecall?(agentId: string, recalls: MemoryRecallLifecycle[]): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* M4: set (or clear) a record's pin. Pinned records are exempt from the store's retention
|
|
78
|
+
* eviction. Optional. The runner calls it when the host/model acts on a promotion suggestion.
|
|
79
|
+
*/
|
|
80
|
+
setPinned?(agentId: string, recordId: string, pinned: boolean): Promise<void>;
|
|
71
81
|
}
|
|
72
82
|
/** Memory query request (kernel → SDK). */
|
|
73
83
|
export interface MemoryQuery {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
already_surfaced: string[];
|
|
84
|
+
scope: MemoryScope;
|
|
85
|
+
query: string;
|
|
77
86
|
top_k: number;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
export interface MemoryRetrieval {
|
|
81
|
-
selected_memory_ids: string[];
|
|
82
|
-
selection_rationale: string;
|
|
87
|
+
kinds: MemoryKind[];
|
|
88
|
+
min_score?: number;
|
|
83
89
|
}
|
|
84
90
|
/** Memory validation error (mirroring kernel MemoryValidationError). */
|
|
85
91
|
export type MemoryValidationError = {
|
|
@@ -102,9 +108,3 @@ export type MemoryValidationError = {
|
|
|
102
108
|
limit: number;
|
|
103
109
|
};
|
|
104
110
|
/** Durable transcript storage for same-session conversational continuity. */
|
|
105
|
-
export interface DreamResult {
|
|
106
|
-
sessionsProcessed: number;
|
|
107
|
-
insightsExtracted: number;
|
|
108
|
-
entriesAdded: number;
|
|
109
|
-
entriesRemoved: number;
|
|
110
|
-
}
|
package/dist/memory/protocols.js
CHANGED
package/dist/memory/public.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { WorkingMemory } from "./working.js";
|
|
2
2
|
export { InMemoryDreamStore } from "./in-memory-store.js";
|
|
3
|
-
export type {
|
|
3
|
+
export type { InMemoryDreamStoreOptions } from "./in-memory-store.js";
|
|
4
|
+
export { memoryRetentionScore } from "./retention.js";
|
|
5
|
+
export type { DreamStore, SessionData, SessionMessage, MemoryRecord, MemoryRecall, MemoryQuery, MemoryScope, MemoryProvenance, MemoryRecallLifecycle, MemoryKind, MemoryAuthor, MemoryTrustLevel, } from "./protocols.js";
|
|
4
6
|
export type { KnowledgeSource } from "../knowledge/source.js";
|
package/dist/memory/public.js
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
interface RankableMemory<T> {
|
|
2
|
+
value: T;
|
|
3
|
+
searchableText: string;
|
|
4
|
+
updatedAt: number;
|
|
5
|
+
/** Times this record has been recalled — a proven-useful record ranks slightly higher. */
|
|
6
|
+
recallCount: number;
|
|
7
|
+
/** Optional day-based TTL. Records past it are discounted, not dropped (host owns hard deletion). */
|
|
8
|
+
ttlDays?: number;
|
|
9
|
+
insertionIndex: number;
|
|
10
|
+
}
|
|
11
|
+
/** One ranked hit with a genuine relevance score in [0,1] and a human-readable rationale. */
|
|
12
|
+
export interface RankedMemory<T> {
|
|
13
|
+
value: T;
|
|
14
|
+
score: number;
|
|
15
|
+
why: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RankOptions {
|
|
18
|
+
/** Wall-clock reference for the staleness discount. Omit to disable TTL/staleness scoring. */
|
|
19
|
+
nowMs?: number;
|
|
20
|
+
/** Age (days) past which a record starts losing relevance. */
|
|
21
|
+
staleWarningDays?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Rank memories without embeddings or provider calls, returning a genuine relevance score in [0,1].
|
|
25
|
+
*
|
|
26
|
+
* The score is lexical overlap (distinct query terms present, as a fraction) as the dominant term,
|
|
27
|
+
* lifted slightly by recall history and lowered by TTL/staleness. Recency and insertion order break
|
|
28
|
+
* ties. A non-empty query never returns unrelated entries (lexical overlap zero ⇒ filtered out).
|
|
29
|
+
*
|
|
30
|
+
* The score is relevance, deliberately distinct from the record's stored confidence.
|
|
31
|
+
*/
|
|
32
|
+
export declare function rankMemories<T>(query: string, candidates: Array<RankableMemory<T>>, topK: number, opts?: RankOptions): Array<RankedMemory<T>>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function terms(text) {
|
|
2
|
+
const result = new Set();
|
|
3
|
+
for (const segment of text.toLocaleLowerCase().match(/[\p{L}\p{N}]+/gu) ?? []) {
|
|
4
|
+
result.add(segment);
|
|
5
|
+
if (/\p{Script=Han}/u.test(segment)) {
|
|
6
|
+
const characters = [...segment];
|
|
7
|
+
for (let index = 0; index + 1 < characters.length; index++) {
|
|
8
|
+
result.add(characters[index] + characters[index + 1]);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
const DAY_MS = 86_400_000;
|
|
15
|
+
/** Staleness discount in [0,1): grows once a record is older than the warning window, and jumps
|
|
16
|
+
* past its TTL. Clock-based, so it lives host-side (the kernel owns no wall clock). */
|
|
17
|
+
function stalenessPenalty(updatedAt, ttlDays, opts) {
|
|
18
|
+
if (opts.nowMs === undefined)
|
|
19
|
+
return 0;
|
|
20
|
+
const ageDays = Math.max(0, (opts.nowMs - updatedAt) / DAY_MS);
|
|
21
|
+
let penalty = 0;
|
|
22
|
+
if (opts.staleWarningDays !== undefined && ageDays > opts.staleWarningDays) {
|
|
23
|
+
penalty += Math.min(0.3, 0.05 * (ageDays - opts.staleWarningDays));
|
|
24
|
+
}
|
|
25
|
+
if (ttlDays !== undefined && ageDays > ttlDays) {
|
|
26
|
+
penalty += 0.4;
|
|
27
|
+
}
|
|
28
|
+
return Math.min(0.9, penalty);
|
|
29
|
+
}
|
|
30
|
+
/** Small proven-usefulness boost from recall history: log-shaped, capped so it never overturns a
|
|
31
|
+
* clearly more lexically relevant record. */
|
|
32
|
+
function recallBoost(recallCount) {
|
|
33
|
+
if (recallCount <= 0)
|
|
34
|
+
return 0;
|
|
35
|
+
return Math.min(0.15, 0.05 * Math.log2(1 + recallCount));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Rank memories without embeddings or provider calls, returning a genuine relevance score in [0,1].
|
|
39
|
+
*
|
|
40
|
+
* The score is lexical overlap (distinct query terms present, as a fraction) as the dominant term,
|
|
41
|
+
* lifted slightly by recall history and lowered by TTL/staleness. Recency and insertion order break
|
|
42
|
+
* ties. A non-empty query never returns unrelated entries (lexical overlap zero ⇒ filtered out).
|
|
43
|
+
*
|
|
44
|
+
* The score is relevance, deliberately distinct from the record's stored confidence.
|
|
45
|
+
*/
|
|
46
|
+
export function rankMemories(query, candidates, topK, opts = {}) {
|
|
47
|
+
const queryTerms = terms(query);
|
|
48
|
+
const limit = Math.max(0, Math.floor(topK));
|
|
49
|
+
if (limit === 0)
|
|
50
|
+
return [];
|
|
51
|
+
return candidates
|
|
52
|
+
.map(candidate => {
|
|
53
|
+
const candidateTerms = terms(candidate.searchableText);
|
|
54
|
+
let lexicalMatches = 0;
|
|
55
|
+
for (const term of queryTerms) {
|
|
56
|
+
if (candidateTerms.has(term))
|
|
57
|
+
lexicalMatches++;
|
|
58
|
+
}
|
|
59
|
+
const lexicalFraction = queryTerms.size === 0 ? 0 : lexicalMatches / queryTerms.size;
|
|
60
|
+
const penalty = stalenessPenalty(candidate.updatedAt, candidate.ttlDays, opts);
|
|
61
|
+
const boost = recallBoost(candidate.recallCount);
|
|
62
|
+
const score = Math.max(0, Math.min(1, lexicalFraction * 0.85 + boost - penalty));
|
|
63
|
+
const why = queryTerms.size === 0
|
|
64
|
+
? "no query terms; insertion order"
|
|
65
|
+
: `lexical ${lexicalMatches}/${queryTerms.size}`
|
|
66
|
+
+ (boost > 0 ? `, recall×${candidate.recallCount}` : "")
|
|
67
|
+
+ (penalty > 0 ? `, stale −${penalty.toFixed(2)}` : "");
|
|
68
|
+
return { ...candidate, lexicalMatches, score, why };
|
|
69
|
+
})
|
|
70
|
+
.filter(candidate => queryTerms.size === 0 || candidate.lexicalMatches > 0)
|
|
71
|
+
.sort((a, b) => b.score - a.score
|
|
72
|
+
|| b.lexicalMatches - a.lexicalMatches
|
|
73
|
+
|| b.updatedAt - a.updatedAt
|
|
74
|
+
|| a.insertionIndex - b.insertionIndex)
|
|
75
|
+
.slice(0, limit)
|
|
76
|
+
.map(candidate => ({ value: candidate.value, score: candidate.score, why: candidate.why }));
|
|
77
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side mirror of the kernel's shared retention vocabulary (`crates/.../mm/value.rs` +
|
|
3
|
+
* `memory_retention_score`). The durable store owns the full cross-session record set, so it — not
|
|
4
|
+
* the kernel — enforces the capacity bound; it must rank by the same integer "value" definition so
|
|
5
|
+
* memory and context knowledge agree on what is worth keeping.
|
|
6
|
+
*
|
|
7
|
+
* Integer terms (magnitudes well within 2^53, so JS number math is exact). The turn-based recency
|
|
8
|
+
* term is omitted here: the host store has no turn counter, so a record's recall_count, kind,
|
|
9
|
+
* confidence, size, and (clock-based) staleness drive the ordering. `parity` tests pin this against
|
|
10
|
+
* the Rust reference for the terms both compute.
|
|
11
|
+
*/
|
|
12
|
+
import type { MemoryRecord } from "./protocols.js";
|
|
13
|
+
/**
|
|
14
|
+
* Deterministic retention score for a durable record. Higher is retained first;
|
|
15
|
+
* `Number.POSITIVE_INFINITY` is reserved for pins (the kernel uses `i64::MAX`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function memoryRetentionScore(record: MemoryRecord, nowMs: number, staleWarningDays: number): number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const DAY_MS = 86_400_000;
|
|
2
|
+
const KIND_WEIGHT = {
|
|
3
|
+
user: 1_600,
|
|
4
|
+
feedback: 1_800,
|
|
5
|
+
project: 1_400,
|
|
6
|
+
reference: 1_200,
|
|
7
|
+
};
|
|
8
|
+
/** floor(log2(1 + n)) — the kernel's stable ln(1+n) proxy for usage. */
|
|
9
|
+
function usageBucket(useCount) {
|
|
10
|
+
if (useCount <= 0)
|
|
11
|
+
return 0;
|
|
12
|
+
return Math.floor(Math.log2(useCount + 1));
|
|
13
|
+
}
|
|
14
|
+
/** Day-based staleness discount in parts-per-million, matching the store's recall-ranking penalty
|
|
15
|
+
* band but expressed on the kernel's ppm scale. */
|
|
16
|
+
function staleDiscountPpm(updatedAt, ttlDays, nowMs, staleWarningDays) {
|
|
17
|
+
const ageDays = Math.max(0, (nowMs - updatedAt) / DAY_MS);
|
|
18
|
+
let ppm = 0;
|
|
19
|
+
if (ageDays > staleWarningDays) {
|
|
20
|
+
ppm += Math.min(300_000, 50_000 * (ageDays - staleWarningDays));
|
|
21
|
+
}
|
|
22
|
+
if (ttlDays !== undefined && ageDays > ttlDays) {
|
|
23
|
+
ppm += 400_000;
|
|
24
|
+
}
|
|
25
|
+
return Math.min(1_000_000, Math.floor(ppm));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Deterministic retention score for a durable record. Higher is retained first;
|
|
29
|
+
* `Number.POSITIVE_INFINITY` is reserved for pins (the kernel uses `i64::MAX`).
|
|
30
|
+
*/
|
|
31
|
+
export function memoryRetentionScore(record, nowMs, staleWarningDays) {
|
|
32
|
+
if (record.pinned)
|
|
33
|
+
return Number.POSITIVE_INFINITY;
|
|
34
|
+
const usage = usageBucket(record.recall_count) * 8_192;
|
|
35
|
+
// Recency (turn-based in the kernel) is unavailable host-side; omitted deterministically.
|
|
36
|
+
const kind = KIND_WEIGHT[record.kind] ?? 0;
|
|
37
|
+
const confidencePpm = Math.min(1_000_000, Math.floor(Math.max(0, Math.min(1, record.confidence)) * 1_000_000));
|
|
38
|
+
const confidence = Math.floor(confidencePpm / 250);
|
|
39
|
+
const stalePpm = staleDiscountPpm(record.updated_at, record.ttl_days, nowMs, staleWarningDays);
|
|
40
|
+
const staleness = Math.floor(stalePpm / 125);
|
|
41
|
+
// 4-bytes-per-token proxy, matching the kernel's content.len()/4.
|
|
42
|
+
const tokens = Math.min(0xffffffff, Math.floor(byteLength(record.content) / 4));
|
|
43
|
+
const size = tokens * 4;
|
|
44
|
+
return usage + kind + confidence - staleness - size;
|
|
45
|
+
}
|
|
46
|
+
function byteLength(text) {
|
|
47
|
+
// Match Rust's content.len() (UTF-8 bytes) without pulling in Buffer for portability.
|
|
48
|
+
let bytes = 0;
|
|
49
|
+
for (const ch of text) {
|
|
50
|
+
const code = ch.codePointAt(0);
|
|
51
|
+
bytes += code <= 0x7f ? 1 : code <= 0x7ff ? 2 : code <= 0xffff ? 3 : 4;
|
|
52
|
+
}
|
|
53
|
+
return bytes;
|
|
54
|
+
}
|
package/dist/os/public.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type { NativeOsProfile, OsProfileId } from "../runtime/os-profile.js";
|
|
1
|
+
export { DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, assertNativeProfile, osProfile, } from "../runtime/os-profile.js";
|
|
2
|
+
export type { NativeOsProfile, OsProfileId, SignalPolicy } from "../runtime/os-profile.js";
|
|
3
3
|
export { rebuildOsSnapshotFromSessionEvents } from "../runtime/os-snapshot.js";
|
|
4
4
|
export type { OsSnapshot } from "../runtime/os-snapshot.js";
|
|
5
5
|
export type { KernelEventCategory } from "../runtime/kernel-event-log.js";
|
|
6
6
|
export { KernelPrimitivesDashboard } from "../runtime/kernel-primitives-dashboard.js";
|
|
7
7
|
export type { MemoryPolicy, MemoryWriteRateLimit, ResourceQuota } from "../kernel.js";
|
|
8
|
-
export type {
|
|
8
|
+
export type { PromptBudget, SchedulerPolicy } from "../runtime/runner.js";
|
|
9
9
|
export { ScheduledPrompt } from "../signals/scheduled.js";
|
|
10
10
|
export { SignalGateway } from "../signals/gateway.js";
|
|
11
11
|
export { PermissionManager, PermissionMode } from "../safety/permissions.js";
|
package/dist/os/public.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// `@deepstrike/sdk/os` — Agent-OS diagnostics, profiles, signal/permission machinery, replay-testing,
|
|
2
2
|
// and the scheduler/quota/policy types referenced by advanced `RuntimeOptions` fields.
|
|
3
|
-
export {
|
|
3
|
+
export { DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, assertNativeProfile, osProfile, } from "../runtime/os-profile.js";
|
|
4
4
|
export { rebuildOsSnapshotFromSessionEvents } from "../runtime/os-snapshot.js";
|
|
5
5
|
export { KernelPrimitivesDashboard } from "../runtime/kernel-primitives-dashboard.js";
|
|
6
6
|
// Signals + SDK-side permissions.
|
package/dist/providers/base.d.ts
CHANGED
|
@@ -48,6 +48,11 @@ export declare function normalizeToolCall(id: string, name: string, args: unknow
|
|
|
48
48
|
name: string;
|
|
49
49
|
arguments: string;
|
|
50
50
|
} | null;
|
|
51
|
+
export declare class UnsupportedModalityError extends Error {
|
|
52
|
+
readonly modality: string;
|
|
53
|
+
readonly provider: string;
|
|
54
|
+
constructor(modality: string, provider: string);
|
|
55
|
+
}
|
|
51
56
|
export declare function toAnthropicContent(msg: Message): string | Array<Record<string, unknown>>;
|
|
52
57
|
/**
|
|
53
58
|
* History turns with the volatile State turn appended as the latest turn, for
|
|
@@ -63,6 +68,9 @@ export declare function turnsWithStateAppended(context: RenderedContext): Messag
|
|
|
63
68
|
/** Convert RenderedContext.turns to Anthropic messages array.
|
|
64
69
|
* `turns` contains only user / assistant / tool roles — no system filtering needed. */
|
|
65
70
|
export declare function toAnthropicMessages(turns: Message[], nativeReplay?: (message: Message) => Array<Record<string, unknown>> | undefined): Array<Record<string, unknown>>;
|
|
71
|
+
/** Map an audio MIME type to OpenAI's `input_audio.format` (accepts "mp3" | "wav").
|
|
72
|
+
* `audio/mpeg` must become "mp3", not the raw "mpeg" subtype. */
|
|
73
|
+
export declare function openaiAudioFormat(mediaType: string | undefined): string;
|
|
66
74
|
export declare function toOpenAIContent(msg: Message): string | Array<Record<string, unknown>>;
|
|
67
75
|
/** Build the full OpenAI messages array from a RenderedContext.
|
|
68
76
|
* Prepends systemText as the first system message, then converts turns. */
|
package/dist/providers/base.js
CHANGED
|
Binary file
|
package/dist/providers/gemini.js
CHANGED
|
@@ -2,6 +2,7 @@ import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
|
2
2
|
import { withServerRuntimeGuard } from "../runtime/server.js";
|
|
3
3
|
import { CircuitBreaker, normalizeToolCall, turnsWithStateAppended } from "./base.js";
|
|
4
4
|
import { endpointProfiles } from "./profiles.js";
|
|
5
|
+
import { UnsupportedModalityError } from "./base.js";
|
|
5
6
|
const GEMINI_BASE = endpointProfiles["gemini.google"].baseURL;
|
|
6
7
|
const GEMINI_POLICIES = {
|
|
7
8
|
"gemini-3-pro-preview": { maxTurns: 50 },
|
|
@@ -68,6 +69,17 @@ export function buildContents(turns) {
|
|
|
68
69
|
else if (p.url)
|
|
69
70
|
parts.push({ fileData: { mimeType: p.mediaType ?? "image/png", fileUri: p.url } });
|
|
70
71
|
}
|
|
72
|
+
else if (p.type === "audio") {
|
|
73
|
+
if (!p.data)
|
|
74
|
+
throw new UnsupportedModalityError("audio", "gemini");
|
|
75
|
+
parts.push({ inlineData: { mimeType: p.mediaType ?? "audio/wav", data: p.data } });
|
|
76
|
+
}
|
|
77
|
+
else if (p.type === "tool_result") {
|
|
78
|
+
// tool results are handled via functionResponse on tool role messages
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new UnsupportedModalityError(String(p.type ?? "unknown"), "gemini");
|
|
82
|
+
}
|
|
71
83
|
}
|
|
72
84
|
}
|
|
73
85
|
else if (msg.content) {
|
package/dist/providers/ollama.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeToolCall, omitExtensionKeys, turnsWithStateAppended } from "./base.js";
|
|
1
|
+
import { normalizeToolCall, omitExtensionKeys, turnsWithStateAppended, UnsupportedModalityError } from "./base.js";
|
|
2
2
|
// Prefix-based policy for local models (first match wins)
|
|
3
3
|
const OLLAMA_PREFIX_POLICIES = [
|
|
4
4
|
["deepseek-r1", { maxTurns: 40 }],
|
|
@@ -38,6 +38,8 @@ export class OllamaProvider {
|
|
|
38
38
|
for (const p of m.contentParts) {
|
|
39
39
|
if (p.type === "image" && p.data)
|
|
40
40
|
images.push(p.data);
|
|
41
|
+
else if (p.type === "audio")
|
|
42
|
+
throw new UnsupportedModalityError("audio", "ollama");
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
result.push({ role: m.role, content: m.content, ...(images.length ? { images } : {}) });
|
|
@@ -2,6 +2,7 @@ import OpenAI from "openai";
|
|
|
2
2
|
import { withServerRuntimeGuard } from "../runtime/server.js";
|
|
3
3
|
import { CircuitBreaker, omitExtensionKeys } from "./base.js";
|
|
4
4
|
import { normalizeToolCall } from "./base.js";
|
|
5
|
+
import { UnsupportedModalityError } from "./base.js";
|
|
5
6
|
export class OpenAIResponsesAdapter {
|
|
6
7
|
buildTools(tools) {
|
|
7
8
|
return tools.map(t => ({
|
|
@@ -111,8 +112,10 @@ export class OpenAIResponsesAdapter {
|
|
|
111
112
|
continue;
|
|
112
113
|
}
|
|
113
114
|
if (part.type === "image") {
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
// Default the MIME type (like every other serializer) so a data-only image is
|
|
116
|
+
// not silently dropped; only a part with neither url nor data yields undefined.
|
|
117
|
+
const imageUrl = part.url ?? (part.data
|
|
118
|
+
? `data:${part.mediaType ?? "image/png"};base64,${part.data}`
|
|
116
119
|
: undefined);
|
|
117
120
|
if (imageUrl)
|
|
118
121
|
content.push({
|
|
@@ -120,6 +123,10 @@ export class OpenAIResponsesAdapter {
|
|
|
120
123
|
detail: part.detail ?? "auto",
|
|
121
124
|
image_url: imageUrl,
|
|
122
125
|
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (part.type === "audio") {
|
|
129
|
+
throw new UnsupportedModalityError("audio", "openai-responses");
|
|
123
130
|
}
|
|
124
131
|
}
|
|
125
132
|
return content;
|
|
@@ -11,6 +11,8 @@ export interface ModelProfile {
|
|
|
11
11
|
providerId: ProviderId;
|
|
12
12
|
defaultEndpointId: string;
|
|
13
13
|
contextWindow?: number;
|
|
14
|
+
/** Agent-message modalities the ContentPart → provider serializer path can deliver.
|
|
15
|
+
* Do not advertise video/pdf until ContentPart gains those variants. */
|
|
14
16
|
modalities: {
|
|
15
17
|
input: Array<"text" | "image" | "audio" | "video" | "pdf">;
|
|
16
18
|
output: Array<"text" | "embedding">;
|
|
@@ -1448,7 +1450,7 @@ export declare const modelProfiles: {
|
|
|
1448
1450
|
readonly defaultEndpointId: "qwen.dashscope.multimodal-embeddings";
|
|
1449
1451
|
readonly contextWindow: 32000;
|
|
1450
1452
|
readonly modalities: {
|
|
1451
|
-
readonly input: ["text", "image"
|
|
1453
|
+
readonly input: ["text", "image"];
|
|
1452
1454
|
readonly output: ["embedding"];
|
|
1453
1455
|
};
|
|
1454
1456
|
readonly tools: {
|
|
@@ -1465,7 +1467,7 @@ export declare const modelProfiles: {
|
|
|
1465
1467
|
readonly defaultEndpointId: "qwen.dashscope.multimodal-embeddings";
|
|
1466
1468
|
readonly contextWindow: 32000;
|
|
1467
1469
|
readonly modalities: {
|
|
1468
|
-
readonly input: ["text", "image"
|
|
1470
|
+
readonly input: ["text", "image"];
|
|
1469
1471
|
readonly output: ["embedding"];
|
|
1470
1472
|
};
|
|
1471
1473
|
readonly tools: {
|
|
@@ -1679,7 +1681,7 @@ export declare const modelProfiles: {
|
|
|
1679
1681
|
readonly defaultEndpointId: "gemini.google.embeddings";
|
|
1680
1682
|
readonly contextWindow: 8192;
|
|
1681
1683
|
readonly modalities: {
|
|
1682
|
-
readonly input: ["text", "image", "audio"
|
|
1684
|
+
readonly input: ["text", "image", "audio"];
|
|
1683
1685
|
readonly output: ["embedding"];
|
|
1684
1686
|
};
|
|
1685
1687
|
readonly tools: {
|
|
@@ -605,13 +605,13 @@ export const modelProfiles = {
|
|
|
605
605
|
"qwen/qwen3-vl-embedding": {
|
|
606
606
|
id: "qwen/qwen3-vl-embedding", providerId: "qwen", defaultEndpointId: "qwen.dashscope.multimodal-embeddings",
|
|
607
607
|
contextWindow: 32_000,
|
|
608
|
-
modalities: { input: ["text", "image"
|
|
608
|
+
modalities: { input: ["text", "image"], output: ["embedding"] },
|
|
609
609
|
tools: { supported: false }, reasoning: { supported: false, preserveAcrossToolTurns: false },
|
|
610
610
|
},
|
|
611
611
|
"qwen/qwen2.5-vl-embedding": {
|
|
612
612
|
id: "qwen/qwen2.5-vl-embedding", providerId: "qwen", defaultEndpointId: "qwen.dashscope.multimodal-embeddings",
|
|
613
613
|
contextWindow: 32_000,
|
|
614
|
-
modalities: { input: ["text", "image"
|
|
614
|
+
modalities: { input: ["text", "image"], output: ["embedding"] },
|
|
615
615
|
tools: { supported: false }, reasoning: { supported: false, preserveAcrossToolTurns: false },
|
|
616
616
|
},
|
|
617
617
|
// ── Gemini ─────────────────────────────────────────────────────────────────
|
|
@@ -687,7 +687,7 @@ export const modelProfiles = {
|
|
|
687
687
|
"gemini/gemini-embedding-2": {
|
|
688
688
|
id: "gemini/gemini-embedding-2", providerId: "gemini", defaultEndpointId: "gemini.google.embeddings",
|
|
689
689
|
contextWindow: 8_192,
|
|
690
|
-
modalities: { input: ["text", "image", "audio"
|
|
690
|
+
modalities: { input: ["text", "image", "audio"], output: ["embedding"] },
|
|
691
691
|
tools: { supported: false }, reasoning: { supported: false, preserveAcrossToolTurns: false },
|
|
692
692
|
},
|
|
693
693
|
// ── GLM ────────────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const CONTEXT_POLICY_VERSION: 1;
|
|
2
|
+
export declare const PPM_SCALE: 1000000;
|
|
3
|
+
export interface ContextPressureThresholdsV1 {
|
|
4
|
+
snip: number;
|
|
5
|
+
micro: number;
|
|
6
|
+
collapse: number;
|
|
7
|
+
auto: number;
|
|
8
|
+
renewal: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ContextPolicyV1 {
|
|
11
|
+
pressureThresholds: ContextPressureThresholdsV1;
|
|
12
|
+
targetAfterCompress: number;
|
|
13
|
+
preserveRecentTurns: number;
|
|
14
|
+
renewalCarryover: number;
|
|
15
|
+
collapseOldAssistantNarration: boolean;
|
|
16
|
+
idleMicroCompactMinutes: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ContextPolicyWireV1 {
|
|
19
|
+
version: typeof CONTEXT_POLICY_VERSION;
|
|
20
|
+
pressure_thresholds_ppm: ContextPressureThresholdsV1;
|
|
21
|
+
target_after_compress_ppm: number;
|
|
22
|
+
preserve_recent_turns: number;
|
|
23
|
+
renewal_carryover_ppm: number;
|
|
24
|
+
collapse_old_assistant_narration: boolean;
|
|
25
|
+
idle_micro_compact_minutes: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ContextPolicyOverridesV1 extends Partial<Omit<ContextPolicyV1, "pressureThresholds">> {
|
|
28
|
+
pressureThresholds?: Partial<ContextPressureThresholdsV1>;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_CONTEXT_POLICY_V1: Readonly<ContextPolicyV1>;
|
|
31
|
+
/** Resolve ergonomic partial SDK options into one complete, atomically validated policy. */
|
|
32
|
+
export declare function contextPolicyV1(overrides?: ContextPolicyOverridesV1): ContextPolicyV1;
|
|
33
|
+
/** Convert the public ratio-based policy to the canonical integer-only ABI wire shape. */
|
|
34
|
+
export declare function normalizeContextPolicyV1(policy: ContextPolicyV1): ContextPolicyWireV1;
|
|
35
|
+
export declare function ratioToPpm(value: number, field?: string): number;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const CONTEXT_POLICY_VERSION = 1;
|
|
2
|
+
export const PPM_SCALE = 1_000_000;
|
|
3
|
+
export const DEFAULT_CONTEXT_POLICY_V1 = Object.freeze({
|
|
4
|
+
pressureThresholds: Object.freeze({ snip: 0.70, micro: 0.80, collapse: 0.90, auto: 0.95, renewal: 0.98 }),
|
|
5
|
+
targetAfterCompress: 0.65,
|
|
6
|
+
preserveRecentTurns: 2,
|
|
7
|
+
renewalCarryover: 0.05,
|
|
8
|
+
collapseOldAssistantNarration: true,
|
|
9
|
+
idleMicroCompactMinutes: 60,
|
|
10
|
+
});
|
|
11
|
+
/** Resolve ergonomic partial SDK options into one complete, atomically validated policy. */
|
|
12
|
+
export function contextPolicyV1(overrides = {}) {
|
|
13
|
+
const policy = {
|
|
14
|
+
...DEFAULT_CONTEXT_POLICY_V1,
|
|
15
|
+
...overrides,
|
|
16
|
+
pressureThresholds: {
|
|
17
|
+
...DEFAULT_CONTEXT_POLICY_V1.pressureThresholds,
|
|
18
|
+
...overrides.pressureThresholds,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
normalizeContextPolicyV1(policy);
|
|
22
|
+
return policy;
|
|
23
|
+
}
|
|
24
|
+
/** Convert the public ratio-based policy to the canonical integer-only ABI wire shape. */
|
|
25
|
+
export function normalizeContextPolicyV1(policy) {
|
|
26
|
+
const pressure_thresholds_ppm = {
|
|
27
|
+
snip: ratioToPpm(policy.pressureThresholds.snip, "pressureThresholds.snip"),
|
|
28
|
+
micro: ratioToPpm(policy.pressureThresholds.micro, "pressureThresholds.micro"),
|
|
29
|
+
collapse: ratioToPpm(policy.pressureThresholds.collapse, "pressureThresholds.collapse"),
|
|
30
|
+
auto: ratioToPpm(policy.pressureThresholds.auto, "pressureThresholds.auto"),
|
|
31
|
+
renewal: ratioToPpm(policy.pressureThresholds.renewal, "pressureThresholds.renewal"),
|
|
32
|
+
};
|
|
33
|
+
const ordered = Object.values(pressure_thresholds_ppm);
|
|
34
|
+
if (!ordered.every((value, index) => index === 0 || ordered[index - 1] < value)) {
|
|
35
|
+
throw new RangeError("context pressure thresholds must satisfy snip < micro < collapse < auto < renewal");
|
|
36
|
+
}
|
|
37
|
+
const target_after_compress_ppm = ratioToPpm(policy.targetAfterCompress, "targetAfterCompress");
|
|
38
|
+
if (target_after_compress_ppm >= pressure_thresholds_ppm.snip) {
|
|
39
|
+
throw new RangeError("targetAfterCompress must be lower than the snip threshold");
|
|
40
|
+
}
|
|
41
|
+
assertIntegerAtLeast(policy.preserveRecentTurns, 1, "preserveRecentTurns");
|
|
42
|
+
assertIntegerAtLeast(policy.idleMicroCompactMinutes, 0, "idleMicroCompactMinutes");
|
|
43
|
+
if (typeof policy.collapseOldAssistantNarration !== "boolean") {
|
|
44
|
+
throw new TypeError("collapseOldAssistantNarration must be boolean");
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
version: CONTEXT_POLICY_VERSION,
|
|
48
|
+
pressure_thresholds_ppm,
|
|
49
|
+
target_after_compress_ppm,
|
|
50
|
+
preserve_recent_turns: policy.preserveRecentTurns,
|
|
51
|
+
renewal_carryover_ppm: ratioToPpm(policy.renewalCarryover, "renewalCarryover"),
|
|
52
|
+
collapse_old_assistant_narration: policy.collapseOldAssistantNarration,
|
|
53
|
+
idle_micro_compact_minutes: policy.idleMicroCompactMinutes,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function ratioToPpm(value, field = "ratio") {
|
|
57
|
+
if (!Number.isFinite(value) || value < 0 || value > 1) {
|
|
58
|
+
throw new RangeError(`${field} must be a finite number between 0 and 1`);
|
|
59
|
+
}
|
|
60
|
+
return Math.floor(value * PPM_SCALE + 0.5);
|
|
61
|
+
}
|
|
62
|
+
function assertIntegerAtLeast(value, minimum, field) {
|
|
63
|
+
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
64
|
+
throw new RangeError(`${field} must be a safe integer >= ${minimum}`);
|
|
65
|
+
}
|
|
66
|
+
}
|