@securecoms/agent-bridge 0.26.6 → 0.28.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/README.md +119 -0
- package/dist/bin.d.ts +24 -1
- package/dist/bin.js +4490 -375
- package/dist/bridge-agent.d.ts +405 -0
- package/dist/config.d.ts +7 -0
- package/dist/consumer-grants.d.ts +2 -1
- package/dist/embedder-manifest.json +52 -0
- package/dist/embedder-worker.js +2898 -0
- package/dist/embedder.js +1574 -0
- package/dist/index.js +4282 -297
- package/dist/memory/consumer-notes.d.ts +34 -0
- package/dist/memory/consumer-recall.d.ts +21 -0
- package/dist/memory/embedder/client.d.ts +103 -0
- package/dist/memory/embedder/download.d.ts +28 -0
- package/dist/memory/embedder/embedder-main.d.ts +1 -0
- package/dist/memory/embedder/embedder-paths.d.ts +14 -0
- package/dist/memory/embedder/engine.d.ts +21 -0
- package/dist/memory/embedder/gc.d.ts +2 -0
- package/dist/memory/embedder/handshake.d.ts +7 -0
- package/dist/memory/embedder/heartbeats.d.ts +4 -0
- package/dist/memory/embedder/import-bundle.d.ts +6 -0
- package/dist/memory/embedder/inner-source.d.ts +2 -0
- package/dist/memory/embedder/layout.d.ts +36 -0
- package/dist/memory/embedder/locks.d.ts +17 -0
- package/dist/memory/embedder/manifest.d.ts +30 -0
- package/dist/memory/embedder/no-dial.d.ts +3 -0
- package/dist/memory/embedder/protocol.d.ts +55 -0
- package/dist/memory/embedder/run-dir.d.ts +11 -0
- package/dist/memory/embedder/scheduler.d.ts +24 -0
- package/dist/memory/embedder/server.d.ts +46 -0
- package/dist/memory/embedder/session.d.ts +17 -0
- package/dist/memory/embedder/spawn.d.ts +40 -0
- package/dist/memory/embedder/tokenizer.d.ts +41 -0
- package/dist/memory/embedder/types.d.ts +32 -0
- package/dist/memory/embedder/windows.d.ts +46 -0
- package/dist/memory/embedder/worker-body.d.ts +44 -0
- package/dist/memory/embedder/worker.d.ts +1 -0
- package/dist/memory/memory-config.d.ts +23 -0
- package/dist/memory/note-frames.d.ts +47 -0
- package/dist/memory/note-provenance.d.ts +40 -0
- package/dist/memory/notes-book.d.ts +187 -0
- package/dist/memory/provider.d.ts +2 -0
- package/dist/memory/recall/call-heartbeat.d.ts +35 -0
- package/dist/memory/recall/membership-purge.d.ts +82 -0
- package/dist/memory/recall/rank.d.ts +15 -0
- package/dist/memory/recall/recall-book.d.ts +140 -0
- package/dist/memory/recall/reembed.d.ts +35 -0
- package/dist/memory/secret-scan.d.ts +5 -0
- package/dist/memory-taps.d.ts +3 -2
- package/dist/ort-wasm-simd-threaded.wasm +0 -0
- package/dist/version.d.ts +1 -1
- package/dist/voice/fast-prompt.d.ts +5 -0
- package/dist/ws-server.d.ts +28 -1
- package/package.json +2 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic memory 7b: the bridge's recall index and read path (spec §4, §7).
|
|
3
|
+
* Runs every mutation inside the NotesBook mutex (`exclusive`), which is the
|
|
4
|
+
* per-identity memory mutex. Embedding and sealing happen OUTSIDE it (M2).
|
|
5
|
+
*
|
|
6
|
+
* I8: `index` is reached only from BridgeAgent.tapRecall (the ingest tap and
|
|
7
|
+
* the restore re-run). recall-single-writer.arch.test.ts pins that.
|
|
8
|
+
*/
|
|
9
|
+
import type { RecallCapture, RecallRow, RuntimeInboxRewrite, SqliteMlsStateStore } from "@agentvault/connect-mls-store";
|
|
10
|
+
import { type ServiceLog } from "../../service-log.js";
|
|
11
|
+
import type { Embedder } from "../embedder/client.js";
|
|
12
|
+
export type IndexSkip = "mode" | "audience" | "voice" | "length" | "secret" | "stamp_missing" | "cleared" | "epoch" | "purged" | "duplicate" | "store";
|
|
13
|
+
export interface RecallTapCapture {
|
|
14
|
+
readonly generation: number | undefined;
|
|
15
|
+
readonly capture: RecallCapture;
|
|
16
|
+
}
|
|
17
|
+
export interface RecallItem {
|
|
18
|
+
readonly id: number;
|
|
19
|
+
readonly text: string;
|
|
20
|
+
readonly sent_at: number;
|
|
21
|
+
}
|
|
22
|
+
export type RecallStore = Pick<SqliteMlsStateStore, "recallState" | "recallCapture" | "sealRecallText" | "sealRecallVec" | "insertRecall" | "readRecallRows" | "readRecallRow" | "openRecallText" | "openRecallVec" | "updateRecallVec" | "listPendingRecall" | "deleteRecall" | "recentMemoryMessageIds">;
|
|
23
|
+
export declare class RecallBook {
|
|
24
|
+
private readonly d;
|
|
25
|
+
constructor(d: {
|
|
26
|
+
store: RecallStore;
|
|
27
|
+
embedder: Embedder;
|
|
28
|
+
exclusive: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
29
|
+
modelId: string;
|
|
30
|
+
threshold: number;
|
|
31
|
+
now?: () => number;
|
|
32
|
+
log?: ServiceLog;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Spec §4 order: (1) seal and embed outside the mutex; (2) take the mutex;
|
|
36
|
+
* (3) one transaction (insertRecall) that re-checks I6, I7 and M-A, then I9.
|
|
37
|
+
* A seal failure inserts nothing (fail closed, §5.2). An embedder failure
|
|
38
|
+
* inserts a pending row (sealed_vec NULL) for the re-embed (§8).
|
|
39
|
+
*/
|
|
40
|
+
index(i: {
|
|
41
|
+
conversationId: string;
|
|
42
|
+
messageId: string;
|
|
43
|
+
text: string;
|
|
44
|
+
sentAt: number;
|
|
45
|
+
capture: RecallCapture;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
ok: true;
|
|
48
|
+
recallId: number;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
reason: IndexSkip;
|
|
52
|
+
}>;
|
|
53
|
+
private static readonly MAP_MAX;
|
|
54
|
+
private static readonly IDLE_MS;
|
|
55
|
+
private static readonly TOP_K;
|
|
56
|
+
private static readonly TEXT_MAX_CHARS;
|
|
57
|
+
private static readonly QUERY_TIMEOUT_MS;
|
|
58
|
+
private readonly caches;
|
|
59
|
+
private readonly entries;
|
|
60
|
+
private readonly warming;
|
|
61
|
+
private same;
|
|
62
|
+
private nowMs;
|
|
63
|
+
cacheWarm(conversationId: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* §7.3 (H2): snapshot first, open outside the mutex, install under it. Never on a turn's path. Never rejects:
|
|
66
|
+
* a read failure leaves the cache cold (fail closed: no recall).
|
|
67
|
+
*
|
|
68
|
+
* Final-review item 1 (HIGH): prepare() starts this warm on a cold cache and the same turn's tap inserts while
|
|
69
|
+
* the vectors are still opening. At the row cap that insert count-prunes and moves the content epoch, so the old
|
|
70
|
+
* "install only if all four epochs are unchanged" rule never installed, and the next turn repeated the race
|
|
71
|
+
* forever; below the cap the new row was missing from the installed cache. So at install, under the mutex, the
|
|
72
|
+
* rows and the capture are re-read synchronously:
|
|
73
|
+
* - the clear generation, the mode epoch and the purge epoch must equal the snapshot's, else NOTHING installs
|
|
74
|
+
* (a clear, a mode change or a purge during the warm always wins);
|
|
75
|
+
* - the content epoch may differ (an insert, a prune, a forget or a re-embed): the cache is reconciled to the
|
|
76
|
+
* re-read rows (ids gone are dropped, the few new ids are opened here, under the mutex) and installed with the
|
|
77
|
+
* re-read capture.
|
|
78
|
+
*/
|
|
79
|
+
warm(conversationId: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* §7.1: compute at ingest. Snapshot the capture FIRST (H2); `receipt`
|
|
82
|
+
* replaces its purge and mode epochs with the ones captured when the turn
|
|
83
|
+
* was received (Task 16 fix H-2), so a purge or a mode change after receipt
|
|
84
|
+
* refuses too. 150 ms bound on the query embed; a cold cache starts a warm
|
|
85
|
+
* and gives nothing.
|
|
86
|
+
*/
|
|
87
|
+
prepare(p: {
|
|
88
|
+
messageId: string;
|
|
89
|
+
conversationId: string;
|
|
90
|
+
query: string;
|
|
91
|
+
excludeIds: ReadonlySet<string>;
|
|
92
|
+
timeoutMs?: number;
|
|
93
|
+
receipt?: {
|
|
94
|
+
purgeEpoch: number;
|
|
95
|
+
modeEpoch: number;
|
|
96
|
+
};
|
|
97
|
+
}): Promise<void>;
|
|
98
|
+
/** Q3 + Q6: the entry's own conversation, and its capture still current at delivery. Synchronous (ws flush). */
|
|
99
|
+
deliverable(messageId: string, conversationId: string): readonly RecallItem[] | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Spec §9.1 (H5, W9): delete one recall row and spend this message's destructive operation, in ONE store
|
|
102
|
+
* transaction (`deleteRecall` with the prepared rewrite). The caller has already checked that the id was
|
|
103
|
+
* shown with this delivery. `precommit` is the caller's last check (W1, W2), run inside the mutex with no
|
|
104
|
+
* await before the synchronous delete; a non-null veto deletes nothing.
|
|
105
|
+
*
|
|
106
|
+
* A forget is a delete, never an insert: I8 (single writer of insertRecall) is untouched.
|
|
107
|
+
* The delete moves the content epoch (audit r1 H5). The vector cache is dropped. A pending map entry that
|
|
108
|
+
* matched the capture just before the delete keeps its other items and adopts the new capture (the delete
|
|
109
|
+
* is the only change between the two reads, both inside the mutex with no await between them).
|
|
110
|
+
*/
|
|
111
|
+
forget(conversationId: string, recallId: number, rewrite: RuntimeInboxRewrite, precommit?: () => "message" | "mode" | null): Promise<"ok" | "unknown_id" | "budget" | "message" | "mode">;
|
|
112
|
+
/**
|
|
113
|
+
* Spec §8 (Task 19): a pending row just took its vector (`updateRecallVec`, which moves no epoch). A warm cache
|
|
114
|
+
* whose capture is still current gains the row, so an active conversation's cache (kept warm by use) does not
|
|
115
|
+
* hide re-embedded rows until it idles out. A stale cache is dropped. Called inside `exclusive`.
|
|
116
|
+
*/
|
|
117
|
+
onReembeddedLocked(conversationId: string, row: RecallRow, vec: Float32Array): void;
|
|
118
|
+
/** Spec §7.1: removed at ack, nack or retire. */
|
|
119
|
+
drop(messageId: string): void;
|
|
120
|
+
/** §5.4: one conversation's cache and its pending map entries. Called inside `exclusive`. */
|
|
121
|
+
dropConversationLocked(conversationId: string): void;
|
|
122
|
+
/** A retention change or a prune can remove rows: drop every vector cache. Called inside `exclusive`. */
|
|
123
|
+
dropAllCachesLocked(): void;
|
|
124
|
+
/** A clear or markdown mode: drop every cache and every map entry. Called inside `exclusive`. */
|
|
125
|
+
dropAllLocked(): void;
|
|
126
|
+
/** §7.3: a cache idle for 30 minutes is dropped. */
|
|
127
|
+
dropIdleCaches(now: number): void;
|
|
128
|
+
/**
|
|
129
|
+
* Task 17 fix round 1 (HIGH): at the row cap every insert count-prunes, so without this every pending map
|
|
130
|
+
* entry of the conversation went stale at the next insert and recall stopped. An entry is rebased only when
|
|
131
|
+
* its capture equals the exact pre-insert capture (clear generation, mode and purge epochs equal; the content
|
|
132
|
+
* epoch moved by this one insert alone) and none of its items was pruned. Anything else stays stale.
|
|
133
|
+
*/
|
|
134
|
+
private rebaseEntriesLocked;
|
|
135
|
+
/** Spec §7.3 and audit r1 H7: an insert APPENDS its vector to a warm, current cache, inside the mutex. */
|
|
136
|
+
protected onInsertedLocked(conversationId: string, row: RecallRow, vec: Float32Array | null, r: {
|
|
137
|
+
pruned: readonly number[];
|
|
138
|
+
capture: RecallCapture;
|
|
139
|
+
}): void;
|
|
140
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec §8: lazy re-embed. Rows whose model_id is NULL (pending) or another model's are embedded again by background
|
|
3
|
+
* jobs: open the text, a priority-1 embedder job, seal under the new vector AAD, then inside the memory mutex a
|
|
4
|
+
* compare-and-set on the old model_id. One row per job, at most 16 rows per tick (the bridge ticks once a second;
|
|
5
|
+
* the shared embedder enforces 16 per second per machine, §20 E1.4). Paused while any call heartbeat of this OS user
|
|
6
|
+
* is fresh (H1, B-20).
|
|
7
|
+
*
|
|
8
|
+
* The capture is read BEFORE the row is re-read, opened and embedded, and the write re-checks it inside its
|
|
9
|
+
* transaction (`updateRecallVec`), bound to the recall id read (Task 18 carry M-4). A clear, a mode change or a purge
|
|
10
|
+
* that lands during the embed refuses the write; a row forgotten, pruned or purged takes no vector.
|
|
11
|
+
*
|
|
12
|
+
* Never an insert: the single-writer rule (I8) is untouched. Embedding and sealing happen outside the mutex (M2).
|
|
13
|
+
*/
|
|
14
|
+
import type { RecallRow, SqliteMlsStateStore } from "@agentvault/connect-mls-store";
|
|
15
|
+
import type { Embedder } from "../embedder/client.js";
|
|
16
|
+
export type ReembedStore = Pick<SqliteMlsStateStore, "recallCapture" | "listPendingRecall" | "readRecallRow" | "openRecallText" | "sealRecallVec" | "updateRecallVec">;
|
|
17
|
+
export declare class ReembedQueue {
|
|
18
|
+
private readonly d;
|
|
19
|
+
constructor(d: {
|
|
20
|
+
store: ReembedStore;
|
|
21
|
+
embedder: Embedder;
|
|
22
|
+
exclusive: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
23
|
+
modelId: string;
|
|
24
|
+
paused: () => boolean;
|
|
25
|
+
now?: () => number;
|
|
26
|
+
/** Inside the mutex, after a successful write: the bridge appends the vector to a warm, current cache. */
|
|
27
|
+
onEmbeddedLocked?: (conversationId: string, row: RecallRow, vec: Float32Array) => void;
|
|
28
|
+
embedTimeoutMs?: number;
|
|
29
|
+
});
|
|
30
|
+
private running;
|
|
31
|
+
private readonly parked;
|
|
32
|
+
/** Rows embedded and written by this call (0 when paused, not ready, already running or nothing pending). */
|
|
33
|
+
tick(): Promise<number>;
|
|
34
|
+
private tickOnce;
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The `_suspect` port with skip_long_token false. Same order, same 20-character floor. */
|
|
2
|
+
export declare function suspectWholeField(v: string): string | null;
|
|
3
|
+
export declare function scanNote(input: string): string | null;
|
|
4
|
+
/** Test-only: expand the fixture placeholders (the Python twin is `expand`). */
|
|
5
|
+
export declare function expandFixture(text: string): string;
|
package/dist/memory-taps.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ interface MemorySink {
|
|
|
3
3
|
record(input: MemoryRecordInput): Promise<{
|
|
4
4
|
seq: number;
|
|
5
5
|
deduped: boolean;
|
|
6
|
+
dropped?: true;
|
|
6
7
|
}>;
|
|
7
8
|
}
|
|
8
9
|
/** Record an inbound (peer) text turn the agent actually consumed. Best-effort:
|
|
@@ -11,8 +12,8 @@ interface MemorySink {
|
|
|
11
12
|
* `modality` defaults to "text"; Task 4 (voice-mode carrier) passes "voice"
|
|
12
13
|
* for a turn whose InboxEntry had the server-set `voiceMode` flag, so memory
|
|
13
14
|
* continuity reflects how the turn actually arrived. */
|
|
14
|
-
export declare function recordInboundMemory(sink: MemorySink, channelId: string, senderId: string, text: string, messageId: string, modality?: "text" | "voice"): Promise<void>;
|
|
15
|
+
export declare function recordInboundMemory(sink: MemorySink, channelId: string, senderId: string, text: string, messageId: string, modality?: "text" | "voice", expectPurgeEpoch?: number): Promise<void>;
|
|
15
16
|
/** Record the agent's own outbound reply. Best-effort. `modality` is "voice"
|
|
16
17
|
* for a line the voice fast path spoke (H1), else "text". */
|
|
17
|
-
export declare function recordOutboundMemory(sink: MemorySink, channelId: string, text: string, messageId: string, modality?: "text" | "voice"): Promise<void>;
|
|
18
|
+
export declare function recordOutboundMemory(sink: MemorySink, channelId: string, text: string, messageId: string, modality?: "text" | "voice", expectPurgeEpoch?: number): Promise<void>;
|
|
18
19
|
export {};
|
|
Binary file
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const BRIDGE_VERSION = "0.
|
|
1
|
+
export declare const BRIDGE_VERSION = "0.28.0";
|
|
@@ -38,6 +38,8 @@ export declare const FAST_FACTS_CHARS_CAP = 2000;
|
|
|
38
38
|
*/
|
|
39
39
|
export declare const FAST_DEFER_RULE: string;
|
|
40
40
|
export declare function isRefusal(reply: string): boolean;
|
|
41
|
+
/** Spec §15 item 7 (OQ-M, Eric approved): the same line with or without notes, so it tells the proxy nothing. */
|
|
42
|
+
export declare const FAST_NOTES_DEFER_LINE = "If the answer may depend on something the owner asked you to remember, defer.";
|
|
41
43
|
export declare function buildFastMessages(args: {
|
|
42
44
|
persona: VoicePersona;
|
|
43
45
|
guidance: string;
|
|
@@ -61,6 +63,9 @@ export declare function buildFastMessages(args: {
|
|
|
61
63
|
/** The agent's identity display name ("one name", 2026-10-01): the only
|
|
62
64
|
* source of the prompt's "You are <name>." line. */
|
|
63
65
|
agentName?: string;
|
|
66
|
+
/** Spec §15 item 7: append the fixed notes-defer line. The caller sets it
|
|
67
|
+
* from provider and DM-ness only, never from whether notes exist. */
|
|
68
|
+
notesDeferLine?: boolean;
|
|
64
69
|
}): ChatMessage[];
|
|
65
70
|
/** The fast model appends this when the full agent must answer next. */
|
|
66
71
|
export declare const DEFER_TOKEN = "[[DEFER]]";
|
package/dist/ws-server.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export interface AgentWebSocketOptions {
|
|
|
9
9
|
inflightStaleAfterMs?: number;
|
|
10
10
|
/** Test seam: the clock the delivery ages are measured on. */
|
|
11
11
|
now?: () => number;
|
|
12
|
+
/**
|
|
13
|
+
* Test seam: how long a socket's deliveries wait for its hello (default
|
|
14
|
+
* HELLO_WAIT_MS). 0 delivers at once, as before N-H2.
|
|
15
|
+
*/
|
|
16
|
+
helloWaitMs?: number;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* FB-P1-024 / #842 ruling §3: a stale-in-flight OBSERVATION, not a lease.
|
|
@@ -21,6 +26,28 @@ export interface AgentWebSocketOptions {
|
|
|
21
26
|
*/
|
|
22
27
|
export declare const INFLIGHT_STALE_SWEEP_MS = 60000;
|
|
23
28
|
export declare const INFLIGHT_STALE_AFTER_MS: number;
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Audit r2 N-H2 (ruling PR-2): a new socket's deliveries wait for its first
|
|
31
|
+
* hello, or this long for a consumer that sends none. Without the hold, a
|
|
32
|
+
* turn buffered before the runtime connected went out in the connection
|
|
33
|
+
* handler's first flush, before the hello could mark the socket a runtime
|
|
34
|
+
* consumer, so it never carried its notes.
|
|
35
|
+
*/
|
|
36
|
+
export declare const HELLO_WAIT_MS = 2000;
|
|
37
|
+
/** Spec §8.5: the hello-reply feature that tells the runtime it may offer memory_note on this socket. */
|
|
38
|
+
export declare const MEMORY_NOTES_FEATURE = "memory_notes";
|
|
39
|
+
/** Semantic memory 7b (spec §7.2 Q4): the hello feature a runtime declares to receive `memory.recall`; the bridge echoes it. */
|
|
40
|
+
export declare const MEMORY_RECALL_FEATURE = "memory_recall";
|
|
41
|
+
/**
|
|
42
|
+
* Every BridgeAgent member this module touches, directly or through the
|
|
43
|
+
* consumer helpers. The handlers take `WsAgent`, so tsc rejects a call to a
|
|
44
|
+
* member missing from this list. The ws-server test fakes are passed `as
|
|
45
|
+
* never` from files tsc does not check, so the fake-coverage tests assert each
|
|
46
|
+
* fake against this list at run time (7b gate fix: a member added here without
|
|
47
|
+
* a fake made three tests throw "is not a function").
|
|
48
|
+
*/
|
|
49
|
+
export declare const WS_AGENT_MEMBERS: readonly ["ackRuntimeMessages", "action", "admitRuntimeDelivery", "applyMemoryNote", "clearHarnessReport", "clearPerToolConsumer", "isRuntimeMessageRetired", "noteNotesConsumer", "notePerToolConsumer", "noteRecallConsumer", "noteSessionClose", "noteSessionEvicted", "noteSessionOpen", "notesAppliedGeneration", "notesForDelivery", "recallForDelivery", "recordHarnessReport", "recordRuntimeReply", "reportStatusGated", "requeueFailedRuntimeDeliveries", "requeueFront", "runtimeReplyReceipt", "send", "sendA2A", "subscribe", "takeDeliverable", "wakeListeners"];
|
|
50
|
+
export type WsAgent = Pick<BridgeAgent, (typeof WS_AGENT_MEMBERS)[number]>;
|
|
51
|
+
export declare function attachAgentWebSocket(server: HttpServer, agent: WsAgent, opts: AgentWebSocketOptions): {
|
|
25
52
|
close(): void;
|
|
26
53
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@securecoms/agent-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.5.0"
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@types/node": "^22.0.0",
|
|
59
59
|
"@types/ws": "^8.18.1",
|
|
60
60
|
"esbuild": "0.24.0",
|
|
61
|
+
"onnxruntime-web": "1.29.0",
|
|
61
62
|
"typescript": "^5.4.0",
|
|
62
63
|
"vitest": "^3.2.6"
|
|
63
64
|
}
|