@jini-ai/daemon 0.3.7 → 0.5.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 +119 -0
- package/README.md +50 -8
- package/dist/agent-executor/contracts.d.ts +736 -0
- package/dist/agent-executor/contracts.js +28 -0
- package/dist/agent-executor/event-translation.d.ts +87 -0
- package/dist/agent-executor/event-translation.js +230 -0
- package/dist/agent-executor/events.d.ts +190 -0
- package/dist/agent-executor/events.js +848 -0
- package/dist/agent-executor/handoff.d.ts +18 -0
- package/dist/agent-executor/handoff.js +16 -0
- package/dist/agent-executor/index.d.ts +98 -0
- package/dist/agent-executor/index.js +98 -0
- package/dist/agent-executor/launch.d.ts +375 -0
- package/dist/agent-executor/launch.js +1001 -0
- package/dist/agent-executor/mcp-bridge.d.ts +338 -0
- package/dist/agent-executor/mcp-bridge.js +835 -0
- package/dist/agent-executor/values.d.ts +5 -0
- package/dist/agent-executor/values.js +13 -0
- package/dist/agent-executor.d.ts +382 -177
- package/dist/agent-executor.js +408 -344
- package/dist/close-status.d.ts +11 -8
- package/dist/close-status.js +31 -19
- package/dist/continuation/continuation-transport.d.ts +3 -1
- package/dist/continuation/continuation-transport.js +1 -1
- package/dist/continuation/journal.d.ts +12 -5
- package/dist/continuation/journal.js +4 -4
- package/dist/continuation/run-scoped-context-store.d.ts +13 -4
- package/dist/continuation/run-scoped-context-store.js +6 -6
- package/dist/continuation/run-start-handler.d.ts +1 -1
- package/dist/continuation/run-start-handler.js +3 -16
- package/dist/delegated-tool-bridge.d.ts +7 -3
- package/dist/delegated-tool-bridge.js +32 -31
- package/dist/event-log.d.ts +7 -5
- package/dist/event-log.js +12 -11
- package/dist/frontend-capability-tools.d.ts +1 -1
- package/dist/frontend-capability-tools.js +3 -2
- package/dist/frontend-session-registry.d.ts +32 -9
- package/dist/frontend-session-registry.js +12 -11
- package/dist/http/active-context.d.ts +105 -0
- package/dist/http/active-context.js +67 -0
- package/dist/http/agents.d.ts +68 -0
- package/dist/http/agents.js +12 -0
- package/dist/http/attachments.d.ts +618 -0
- package/dist/http/attachments.js +1034 -0
- package/dist/http/cancel-owned-runs.d.ts +49 -0
- package/dist/http/cancel-owned-runs.js +35 -0
- package/dist/http/component-catalog.d.ts +84 -0
- package/dist/http/component-catalog.js +64 -0
- package/dist/http/connectors.d.ts +209 -0
- package/dist/http/connectors.js +409 -0
- package/dist/http/daemon-status.d.ts +76 -0
- package/dist/http/daemon-status.js +55 -0
- package/dist/http/db-ops.d.ts +123 -0
- package/dist/http/db-ops.js +189 -0
- package/dist/http/delegated-tools.d.ts +113 -0
- package/dist/http/delegated-tools.js +230 -0
- package/dist/http/frontend-control.d.ts +136 -0
- package/dist/http/frontend-control.js +79 -0
- package/dist/http/frontend-sessions.d.ts +110 -0
- package/dist/http/frontend-sessions.js +180 -0
- package/dist/http/health.d.ts +95 -0
- package/dist/http/health.js +40 -0
- package/dist/http/host-tools.d.ts +214 -0
- package/dist/http/host-tools.js +329 -0
- package/dist/http/index.d.ts +52 -0
- package/dist/http/index.js +27 -0
- package/dist/http/media.d.ts +146 -0
- package/dist/http/media.js +346 -0
- package/dist/http/memory.d.ts +265 -0
- package/dist/http/memory.js +328 -0
- package/dist/http/model-proxy.d.ts +49 -0
- package/dist/http/model-proxy.js +642 -0
- package/dist/http/remote-run-events.d.ts +70 -0
- package/dist/http/remote-run-events.js +224 -0
- package/dist/http/research.d.ts +48 -0
- package/dist/http/research.js +315 -0
- package/dist/http/route-manifest.d.ts +35 -0
- package/dist/http/route-manifest.js +103 -0
- package/dist/http/routines.d.ts +120 -0
- package/dist/http/routines.js +298 -0
- package/dist/http/run-credentials.d.ts +73 -0
- package/dist/http/run-credentials.js +71 -0
- package/dist/http/runs.d.ts +91 -0
- package/dist/http/runs.js +221 -0
- package/dist/http/terminals.d.ts +138 -0
- package/dist/http/terminals.js +325 -0
- package/dist/http/tool-catalog.d.ts +78 -0
- package/dist/http/tool-catalog.js +66 -0
- package/dist/http/workspace-root.d.ts +77 -0
- package/dist/http/workspace-root.js +63 -0
- package/dist/http/xai.d.ts +90 -0
- package/dist/http/xai.js +655 -0
- package/dist/image-prompt-delivery.d.ts +13 -3
- package/dist/image-prompt-delivery.js +5 -5
- package/dist/index.d.ts +556 -4
- package/dist/index.js +556 -4
- package/dist/legacy-data-migration.d.ts +59 -8
- package/dist/legacy-data-migration.js +38 -33
- package/dist/read-only-tools.d.ts +130 -0
- package/dist/read-only-tools.js +115 -0
- package/dist/remote-tool-bridge.d.ts +11 -5
- package/dist/remote-tool-bridge.js +15 -15
- package/dist/routines/index.d.ts +1 -1
- package/dist/routines/index.js +1 -1
- package/dist/routines/routine-store.d.ts +34 -12
- package/dist/routines/routine-store.js +21 -20
- package/dist/routines/schedule.d.ts +48 -10
- package/dist/routines/schedule.js +21 -21
- package/dist/routines/scheduler.d.ts +32 -11
- package/dist/routines/scheduler.js +61 -57
- package/dist/routines/types.d.ts +10 -3
- package/dist/run/core/result.d.ts +6 -2
- package/dist/run/core/result.js +3 -3
- package/dist/run/core/retry.d.ts +17 -4
- package/dist/run/core/retry.js +7 -11
- package/dist/run/diagnostics/diagnostics.d.ts +14 -4
- package/dist/run/diagnostics/diagnostics.js +7 -7
- package/dist/run/index.d.ts +1 -1
- package/dist/run/index.js +1 -1
- package/dist/run-credentials.d.ts +138 -0
- package/dist/run-credentials.js +152 -0
- package/dist/run-lifecycle.d.ts +92 -33
- package/dist/run-lifecycle.js +86 -73
- package/dist/scheduler.d.ts +8 -0
- package/dist/scheduler.js +2 -0
- package/dist/session-coordination.d.ts +115 -0
- package/dist/session-coordination.js +111 -0
- package/dist/store/agent-sessions/errors.d.ts +8 -0
- package/dist/store/agent-sessions/errors.js +10 -0
- package/dist/store/agent-sessions/index.d.ts +12 -0
- package/dist/store/agent-sessions/index.js +19 -0
- package/dist/store/agent-sessions/pglite.d.ts +12 -0
- package/dist/store/agent-sessions/pglite.js +7 -0
- package/dist/store/agent-sessions/ports.d.ts +24 -0
- package/dist/store/agent-sessions/ports.js +2 -0
- package/dist/store/agent-sessions/postgres.d.ts +12 -0
- package/dist/store/agent-sessions/postgres.js +7 -0
- package/dist/store/agent-sessions/schema.d.ts +3 -0
- package/dist/store/agent-sessions/schema.js +23 -0
- package/dist/store/agent-sessions/sql.d.ts +35 -0
- package/dist/store/agent-sessions/sql.js +59 -0
- package/dist/store/agent-sessions/sqlite.d.ts +117 -0
- package/dist/store/agent-sessions/sqlite.js +128 -0
- package/dist/store/event-log/sqlite.d.ts +75 -0
- package/dist/store/event-log/sqlite.js +230 -0
- package/dist/surface-exchanges.d.ts +97 -0
- package/dist/surface-exchanges.js +153 -0
- package/dist/terminal-session.d.ts +43 -11
- package/dist/terminal-session.js +22 -20
- package/dist/tokens.js +4 -4
- package/dist/tool-audit.d.ts +114 -0
- package/dist/tool-audit.js +95 -0
- package/dist/tool-executor.d.ts +22 -7
- package/dist/tool-executor.js +16 -16
- package/dist/tool-result-media.d.ts +3 -1
- package/dist/tool-result-media.js +1 -1
- package/dist/tool-result-surfaces.d.ts +3 -1
- package/dist/tool-result-surfaces.js +1 -1
- package/package.json +127 -9
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory
|
|
3
|
+
*
|
|
4
|
+
* Generic memory/notes HTTP surface — thin route wrappers over a
|
|
5
|
+
* frontmatter-backed note store, an extraction-attempt log, and a
|
|
6
|
+
* verify-outcome log, plus a multiplexed SSE change feed. Ported from OD's
|
|
7
|
+
* `apps/daemon/src/routes/memory.ts` (690 lines) — see `archived provenance ledger`'s
|
|
8
|
+
* 2026-07-21 memory-routes section for the full per-route classification.
|
|
9
|
+
*
|
|
10
|
+
* **Deliberately does NOT depend on `@jini-ai/memory`.** That package exists in
|
|
11
|
+
* this repo (`packages/memory/`, `createNoteStore`/`createExtractionLog`/
|
|
12
|
+
* `createVerifyLog` structurally match every collaborator type below field
|
|
13
|
+
* for field). The host supplies the concrete memory implementation rather than
|
|
14
|
+
* making the daemon transport depend on that implementation's release policy.
|
|
15
|
+
* The types below (`MemoryNoteStore`/`MemoryExtractionLog`/`MemoryVerifyLog`) are
|
|
16
|
+
* structural mirrors of `@jini-ai/memory`'s real `NoteStore`/`ExtractionLog`/
|
|
17
|
+
* `VerifyLog` interfaces — a real instance satisfies them with zero adapter
|
|
18
|
+
* code, following the dependency-injection convention established by
|
|
19
|
+
* `daemon-status.ts`/`host-tools.ts`/`db-ops.ts`. The route pack remains replaceable, locked
|
|
20
|
+
* or not. If/when `@jini-ai/memory` is promoted to `"stable"`, a follow-up can
|
|
21
|
+
* replace these local types with direct imports — a mechanical change, not
|
|
22
|
+
* a redesign, since the shapes already match.
|
|
23
|
+
*
|
|
24
|
+
* **Ported (generic, no OD coupling):** the config `enabled` toggle, entry
|
|
25
|
+
* CRUD (`POST /api/memory`, `GET/PUT/DELETE /api/memory/:id`), the tree
|
|
26
|
+
* view and single-node patch, the raw index text, the extraction/
|
|
27
|
+
* verification history lists + clear/remove, and the multiplexed
|
|
28
|
+
* `change`/`extraction`/`verify` SSE feed.
|
|
29
|
+
*
|
|
30
|
+
* **Explicitly NOT ported (OD-PRODUCT or missing-primitive, see
|
|
31
|
+
* `archived provenance ledger` for the full reasoning per route):**
|
|
32
|
+
* - `POST /api/memory/rules/suggest` — OD's canvas/deck-annotation shape.
|
|
33
|
+
* - `POST /api/memory/connectors/suggest` / `.../connectors/extract` — OD's
|
|
34
|
+
* project-scoped connector-mining pipeline.
|
|
35
|
+
* - `POST /api/memory/extract` — the heuristic-regex pre-turn phase and the
|
|
36
|
+
* BYOK-chat-provider-passthrough LLM post-turn phase are both OD-specific
|
|
37
|
+
* composition, per this repo's root `AGENTS.md`'s existing note that
|
|
38
|
+
* `@jini-ai/memory`'s "heuristic-regex... prompt-composition pieces" were
|
|
39
|
+
* "explicitly left un-ported."
|
|
40
|
+
* - `GET /api/memory/system-prompt` — depends on `composeMemoryBody`, which
|
|
41
|
+
* does not exist anywhere in `@jini-ai/memory` yet (same `AGENTS.md` note).
|
|
42
|
+
* - The four extra `MemoryConfigPatch` boolean toggles
|
|
43
|
+
* (`chatExtractionEnabled`/`profileEnabled`/`rewriteEnabled`/
|
|
44
|
+
* `verifyEnabled`) and the whole `extraction` (LLM-provider) config
|
|
45
|
+
* sub-object: `@jini-ai/memory`'s `NoteStoreOptions` is `{enabled: boolean}`
|
|
46
|
+
* only — a real, documented capability gap in the underlying store, not a
|
|
47
|
+
* route-level scoping choice. A host needing those toggles today has to
|
|
48
|
+
* layer its own config storage alongside `NoteStore.writeConfig`.
|
|
49
|
+
*/
|
|
50
|
+
import type { Express } from 'express';
|
|
51
|
+
import { type AdapterContext } from '@jini-ai/http-kit';
|
|
52
|
+
export interface MemoryNoteEntrySummary {
|
|
53
|
+
readonly id: string;
|
|
54
|
+
readonly name: string;
|
|
55
|
+
readonly description: string;
|
|
56
|
+
readonly type: string;
|
|
57
|
+
readonly updatedAt: number;
|
|
58
|
+
}
|
|
59
|
+
export interface MemoryNoteEntry extends MemoryNoteEntrySummary {
|
|
60
|
+
readonly body: string;
|
|
61
|
+
}
|
|
62
|
+
export interface MemoryTreeNode {
|
|
63
|
+
readonly id: string;
|
|
64
|
+
readonly parentId: string | null;
|
|
65
|
+
readonly path: string;
|
|
66
|
+
readonly name: string;
|
|
67
|
+
readonly description: string;
|
|
68
|
+
readonly kind: 'folder' | 'entry';
|
|
69
|
+
readonly type: string;
|
|
70
|
+
readonly createdAt: string;
|
|
71
|
+
readonly updatedAt: string;
|
|
72
|
+
readonly childrenCount: number;
|
|
73
|
+
}
|
|
74
|
+
export interface MemoryNoteStoreOptions {
|
|
75
|
+
readonly enabled: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Minimal event-emitter surface every collaborator's `events` field needs — satisfied structurally by a real `node:events` `EventEmitter`. Its positional methods are a framework ABI, exempt from the object-argument convention. */
|
|
78
|
+
export interface MemoryChangeEmitter {
|
|
79
|
+
on(event: string, listener: (event: unknown) => void): unknown;
|
|
80
|
+
off(event: string, listener: (event: unknown) => void): unknown;
|
|
81
|
+
}
|
|
82
|
+
export interface MemoryNoteStore {
|
|
83
|
+
readonly events: MemoryChangeEmitter;
|
|
84
|
+
dir({ dataDir }: {
|
|
85
|
+
dataDir: string;
|
|
86
|
+
}): string;
|
|
87
|
+
readConfig({ dataDir }: {
|
|
88
|
+
dataDir: string;
|
|
89
|
+
}): Promise<MemoryNoteStoreOptions>;
|
|
90
|
+
writeConfig({ dataDir, patch }: {
|
|
91
|
+
dataDir: string;
|
|
92
|
+
patch: Partial<MemoryNoteStoreOptions>;
|
|
93
|
+
}): Promise<MemoryNoteStoreOptions>;
|
|
94
|
+
readIndex({ dataDir }: {
|
|
95
|
+
dataDir: string;
|
|
96
|
+
}): Promise<string>;
|
|
97
|
+
writeIndex({ dataDir, body }: {
|
|
98
|
+
dataDir: string;
|
|
99
|
+
body: string;
|
|
100
|
+
}): Promise<void>;
|
|
101
|
+
listEntries({ dataDir }: {
|
|
102
|
+
dataDir: string;
|
|
103
|
+
}): Promise<readonly MemoryNoteEntrySummary[]>;
|
|
104
|
+
readEntry({ dataDir, id }: {
|
|
105
|
+
dataDir: string;
|
|
106
|
+
id: string;
|
|
107
|
+
}): Promise<MemoryNoteEntry | null>;
|
|
108
|
+
upsertEntry({ dataDir, input }: {
|
|
109
|
+
dataDir: string;
|
|
110
|
+
input: {
|
|
111
|
+
id?: string;
|
|
112
|
+
name: string;
|
|
113
|
+
description?: string;
|
|
114
|
+
type: string;
|
|
115
|
+
body?: string;
|
|
116
|
+
};
|
|
117
|
+
}): Promise<MemoryNoteEntry>;
|
|
118
|
+
deleteEntry({ dataDir, id }: {
|
|
119
|
+
dataDir: string;
|
|
120
|
+
id: string;
|
|
121
|
+
}): Promise<void>;
|
|
122
|
+
updateTreeNode({ dataDir, id, patch }: {
|
|
123
|
+
dataDir: string;
|
|
124
|
+
id: string;
|
|
125
|
+
patch: {
|
|
126
|
+
name?: string;
|
|
127
|
+
description?: string;
|
|
128
|
+
type?: string;
|
|
129
|
+
body?: string;
|
|
130
|
+
};
|
|
131
|
+
}): Promise<MemoryNoteEntry>;
|
|
132
|
+
buildTree({ dataDir }: {
|
|
133
|
+
dataDir: string;
|
|
134
|
+
}): Promise<readonly MemoryTreeNode[]>;
|
|
135
|
+
}
|
|
136
|
+
export interface MemoryExtractionLog {
|
|
137
|
+
readonly events: MemoryChangeEmitter;
|
|
138
|
+
list(): readonly unknown[];
|
|
139
|
+
remove({ id }: {
|
|
140
|
+
id: string;
|
|
141
|
+
}): number;
|
|
142
|
+
clear(): number;
|
|
143
|
+
}
|
|
144
|
+
export interface MemoryVerifyLog {
|
|
145
|
+
readonly events: MemoryChangeEmitter;
|
|
146
|
+
list(): readonly unknown[];
|
|
147
|
+
remove({ id }: {
|
|
148
|
+
id: string;
|
|
149
|
+
}): number;
|
|
150
|
+
clear(): number;
|
|
151
|
+
}
|
|
152
|
+
export interface MemoryHttpDeps {
|
|
153
|
+
readonly notes: MemoryNoteStore;
|
|
154
|
+
readonly extractions: MemoryExtractionLog;
|
|
155
|
+
readonly verifications: MemoryVerifyLog;
|
|
156
|
+
/** Forwarded verbatim to every `MemoryNoteStore`/log call — the same `dataDir` a host passes to its own `createNoteStore`-backed instance. */
|
|
157
|
+
readonly dataDir: string;
|
|
158
|
+
}
|
|
159
|
+
export interface MemoryOverviewResponse {
|
|
160
|
+
readonly enabled: boolean;
|
|
161
|
+
readonly rootDir: string;
|
|
162
|
+
readonly index: string;
|
|
163
|
+
readonly entries: readonly MemoryNoteEntrySummary[];
|
|
164
|
+
}
|
|
165
|
+
export declare const memoryOverviewRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryOverviewResponse, MemoryHttpDeps>;
|
|
166
|
+
export interface MemoryTreeResponse {
|
|
167
|
+
readonly enabled: boolean;
|
|
168
|
+
readonly rootDir: string;
|
|
169
|
+
readonly tree: readonly MemoryTreeNode[];
|
|
170
|
+
}
|
|
171
|
+
export declare const memoryTreeRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryTreeResponse, MemoryHttpDeps>;
|
|
172
|
+
export interface MemoryTreeNodePatch {
|
|
173
|
+
readonly name?: string;
|
|
174
|
+
readonly description?: string;
|
|
175
|
+
readonly type?: string;
|
|
176
|
+
readonly body?: string;
|
|
177
|
+
}
|
|
178
|
+
interface MemoryUpdateTreeNodeInput {
|
|
179
|
+
readonly id: string;
|
|
180
|
+
readonly patch: MemoryTreeNodePatch;
|
|
181
|
+
}
|
|
182
|
+
export interface MemoryUpdateTreeNodeResponse {
|
|
183
|
+
readonly entry: MemoryNoteEntry;
|
|
184
|
+
readonly tree: readonly MemoryTreeNode[];
|
|
185
|
+
}
|
|
186
|
+
export declare const memoryUpdateTreeNodeRoute: import("@jini-ai/http-kit").JsonRouteSpec<MemoryUpdateTreeNodeInput, MemoryUpdateTreeNodeResponse, MemoryHttpDeps>;
|
|
187
|
+
export interface MemoryIndexResponse {
|
|
188
|
+
readonly index: string;
|
|
189
|
+
}
|
|
190
|
+
export declare const memoryWriteIndexRoute: import("@jini-ai/http-kit").JsonRouteSpec<string, MemoryIndexResponse, MemoryHttpDeps>;
|
|
191
|
+
export interface MemoryConfigResponse {
|
|
192
|
+
readonly enabled: boolean;
|
|
193
|
+
}
|
|
194
|
+
export declare const memoryWriteConfigRoute: import("@jini-ai/http-kit").JsonRouteSpec<Partial<MemoryNoteStoreOptions>, MemoryConfigResponse, MemoryHttpDeps>;
|
|
195
|
+
export interface MemoryExtractionsResponse {
|
|
196
|
+
readonly extractions: readonly unknown[];
|
|
197
|
+
}
|
|
198
|
+
export declare const memoryListExtractionsRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryExtractionsResponse, MemoryHttpDeps>;
|
|
199
|
+
export interface MemoryRemovedResponse {
|
|
200
|
+
readonly removed: number;
|
|
201
|
+
}
|
|
202
|
+
export declare const memoryClearExtractionsRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryRemovedResponse, MemoryHttpDeps>;
|
|
203
|
+
export declare const memoryRemoveExtractionRoute: import("@jini-ai/http-kit").JsonRouteSpec<string, MemoryRemovedResponse, MemoryHttpDeps>;
|
|
204
|
+
export interface MemoryVerificationsResponse {
|
|
205
|
+
readonly verifications: readonly unknown[];
|
|
206
|
+
}
|
|
207
|
+
export declare const memoryListVerificationsRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryVerificationsResponse, MemoryHttpDeps>;
|
|
208
|
+
export declare const memoryClearVerificationsRoute: import("@jini-ai/http-kit").JsonRouteSpec<void, MemoryRemovedResponse, MemoryHttpDeps>;
|
|
209
|
+
export declare const memoryRemoveVerificationRoute: import("@jini-ai/http-kit").JsonRouteSpec<string, MemoryRemovedResponse, MemoryHttpDeps>;
|
|
210
|
+
export interface MemoryEntryInput {
|
|
211
|
+
readonly id?: string;
|
|
212
|
+
readonly name: string;
|
|
213
|
+
readonly description?: string;
|
|
214
|
+
readonly type: string;
|
|
215
|
+
readonly body?: string;
|
|
216
|
+
}
|
|
217
|
+
export interface MemoryEntryResponse {
|
|
218
|
+
readonly entry: MemoryNoteEntry;
|
|
219
|
+
}
|
|
220
|
+
export declare const memoryCreateEntryRoute: import("@jini-ai/http-kit").JsonRouteSpec<MemoryEntryInput, MemoryEntryResponse, MemoryHttpDeps>;
|
|
221
|
+
export declare const memoryReadEntryRoute: import("@jini-ai/http-kit").JsonRouteSpec<string, MemoryEntryResponse, MemoryHttpDeps>;
|
|
222
|
+
interface MemoryUpdateEntryInput {
|
|
223
|
+
readonly id: string;
|
|
224
|
+
readonly input: MemoryEntryInput;
|
|
225
|
+
}
|
|
226
|
+
export declare const memoryUpdateEntryRoute: import("@jini-ai/http-kit").JsonRouteSpec<MemoryUpdateEntryInput, MemoryEntryResponse, MemoryHttpDeps>;
|
|
227
|
+
export interface MemoryDeleteEntryResponse {
|
|
228
|
+
readonly ok: true;
|
|
229
|
+
}
|
|
230
|
+
export declare const memoryDeleteEntryRoute: import("@jini-ai/http-kit").JsonRouteSpec<string, MemoryDeleteEntryResponse, MemoryHttpDeps>;
|
|
231
|
+
/**
|
|
232
|
+
* `GET /api/memory/events` — one SSE connection multiplexing three channels
|
|
233
|
+
* (matching OD's own reasoning: "so the browser opens one connection instead
|
|
234
|
+
* of two/three"): `connected` (once, on open), `change` (relayed from
|
|
235
|
+
* `deps.notes.events`), `extraction` (relayed from `deps.extractions.events`,
|
|
236
|
+
* whose underlying event name is `'attempt'` — see `@jini-ai/memory`'s
|
|
237
|
+
* `extraction-log.ts`), and `verify` (relayed from `deps.verifications.events`).
|
|
238
|
+
* Uses `sse.ts`'s generic channel rather than OD's bespoke `createSseResponse`;
|
|
239
|
+
* no Last-Event-ID replay (unlike `runs.ts`) since none of the three
|
|
240
|
+
* underlying emitters buffer history for reconnect — this mirrors the OD
|
|
241
|
+
* origin's own behavior (a live tail only, no replay).
|
|
242
|
+
*
|
|
243
|
+
* Bypasses `mountJsonRoute` (raw `app.get`, for the SSE response shape), so it does not get
|
|
244
|
+
* `requireSameOrigin` for free the way the JSON routes below do — the guard is applied here
|
|
245
|
+
* directly, before the SSE channel is opened, so a cross-origin request never gets a stream.
|
|
246
|
+
*/
|
|
247
|
+
export declare function registerMemoryEventStream({ app, deps, adapter }: {
|
|
248
|
+
readonly app: Express;
|
|
249
|
+
readonly deps: MemoryHttpDeps;
|
|
250
|
+
readonly adapter: AdapterContext;
|
|
251
|
+
}, _optional?: Record<string, never>): void;
|
|
252
|
+
/**
|
|
253
|
+
* Mounts every ported memory route. Static sub-resources (`/tree`,
|
|
254
|
+
* `/index`, `/config`, `/events`, `/extractions`, `/verifications`) are
|
|
255
|
+
* mounted BEFORE the `/api/memory/:id` catch-all routes, preserving OD's own
|
|
256
|
+
* ordering discipline ("so an `index`/`config`/`extract` slug can't shadow
|
|
257
|
+
* the real handlers") — Express matches routes in registration order.
|
|
258
|
+
*/
|
|
259
|
+
export declare function registerMemoryRoutes({ app, deps, adapter }: {
|
|
260
|
+
readonly app: Express;
|
|
261
|
+
readonly deps: MemoryHttpDeps;
|
|
262
|
+
readonly adapter: AdapterContext;
|
|
263
|
+
}, _optional?: Record<string, never>): void;
|
|
264
|
+
export {};
|
|
265
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { createApiError } from '@jini-ai/protocol';
|
|
2
|
+
import { defineJsonRoute, mountJsonRoute } from '@jini-ai/http-kit';
|
|
3
|
+
import { guardSameOrigin } from '@jini-ai/http-kit';
|
|
4
|
+
import { validationError } from '@jini-ai/http-kit';
|
|
5
|
+
import { sendApiError, statusForError } from '@jini-ai/http-kit';
|
|
6
|
+
import { createSseChannel } from '@jini-ai/http-kit';
|
|
7
|
+
import { err, ok } from '@jini-ai/http-kit';
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
function errorMessage(error) {
|
|
12
|
+
return error instanceof Error ? error.message : String(error);
|
|
13
|
+
}
|
|
14
|
+
function parseIdParam(input) {
|
|
15
|
+
const id = input.params.id;
|
|
16
|
+
return typeof id === 'string' && id.length > 0 ? ok({ value: id }) : err({ error: validationError({ message: 'id must be a non-empty path parameter' }) });
|
|
17
|
+
}
|
|
18
|
+
export const memoryOverviewRoute = defineJsonRoute({
|
|
19
|
+
method: 'get',
|
|
20
|
+
path: '/api/memory',
|
|
21
|
+
parse: () => ok({ value: undefined }),
|
|
22
|
+
handle: async ({ input: _input, deps }) => {
|
|
23
|
+
const [config, index, entries] = await Promise.all([
|
|
24
|
+
deps.notes.readConfig({ dataDir: deps.dataDir }),
|
|
25
|
+
deps.notes.readIndex({ dataDir: deps.dataDir }),
|
|
26
|
+
deps.notes.listEntries({ dataDir: deps.dataDir }),
|
|
27
|
+
]);
|
|
28
|
+
return ok({ value: { enabled: config.enabled, rootDir: deps.notes.dir({ dataDir: deps.dataDir }), index, entries } });
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
export const memoryTreeRoute = defineJsonRoute({
|
|
32
|
+
method: 'get',
|
|
33
|
+
path: '/api/memory/tree',
|
|
34
|
+
parse: () => ok({ value: undefined }),
|
|
35
|
+
handle: async ({ input: _input, deps }) => {
|
|
36
|
+
const [config, tree] = await Promise.all([deps.notes.readConfig({ dataDir: deps.dataDir }), deps.notes.buildTree({ dataDir: deps.dataDir })]);
|
|
37
|
+
return ok({ value: { enabled: config.enabled, rootDir: deps.notes.dir({ dataDir: deps.dataDir }), tree } });
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
function parseUpdateTreeNode(input) {
|
|
41
|
+
const parsedId = parseIdParam(input);
|
|
42
|
+
if (!parsedId.ok)
|
|
43
|
+
return parsedId;
|
|
44
|
+
if (!isRecord(input.body))
|
|
45
|
+
return err({ error: validationError({ message: 'body must be a JSON object' }) });
|
|
46
|
+
const patch = {};
|
|
47
|
+
for (const key of ['name', 'description', 'type', 'body']) {
|
|
48
|
+
const value = input.body[key];
|
|
49
|
+
if (value === undefined)
|
|
50
|
+
continue;
|
|
51
|
+
if (typeof value !== 'string')
|
|
52
|
+
return err({ error: validationError({ message: `${key} must be a string when provided` }) });
|
|
53
|
+
patch[key] = value;
|
|
54
|
+
}
|
|
55
|
+
return ok({ value: { id: parsedId.value, patch } });
|
|
56
|
+
}
|
|
57
|
+
export const memoryUpdateTreeNodeRoute = defineJsonRoute({
|
|
58
|
+
method: 'patch',
|
|
59
|
+
path: '/api/memory/tree/:id',
|
|
60
|
+
parse: parseUpdateTreeNode,
|
|
61
|
+
handle: async ({ input: { id, patch }, deps }) => {
|
|
62
|
+
try {
|
|
63
|
+
const entry = await deps.notes.updateTreeNode({ dataDir: deps.dataDir, id, patch });
|
|
64
|
+
const tree = await deps.notes.buildTree({ dataDir: deps.dataDir });
|
|
65
|
+
return ok({ value: { entry, tree } });
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const message = errorMessage(error);
|
|
69
|
+
return err({ error: createApiError({ code: message === 'note not found' ? 'NOT_FOUND' : 'BAD_REQUEST', message }) });
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
}, { requireSameOrigin: true });
|
|
73
|
+
/**
|
|
74
|
+
* Requires `index` to be present and a string — it is not defaulted.
|
|
75
|
+
*
|
|
76
|
+
* Coercing anything else to `''` meant a malformed PUT *succeeded* and wrote an empty document over
|
|
77
|
+
* the caller's entire memory index: a misspelled field (`{ notes: "…" }`), a client that sent the
|
|
78
|
+
* value as a number, or a body that failed to serialize all landed on the same destructive path and
|
|
79
|
+
* returned 200. Clearing the index is still supported, because it is a real thing to want — it just
|
|
80
|
+
* has to be asked for explicitly with `{ index: "" }`, which no typo and no serialization accident
|
|
81
|
+
* produces by chance.
|
|
82
|
+
*/
|
|
83
|
+
function parseIndexBody(input) {
|
|
84
|
+
if (!isRecord(input.body))
|
|
85
|
+
return err({ error: validationError({ message: 'body must be a JSON object' }) });
|
|
86
|
+
const index = input.body.index;
|
|
87
|
+
if (typeof index !== 'string') {
|
|
88
|
+
return err({
|
|
89
|
+
error: validationError({ message: 'index must be a string — send an explicit empty string to clear it' }, {
|
|
90
|
+
issues: [
|
|
91
|
+
{ path: 'index', message: 'required string' },
|
|
92
|
+
]
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return ok({ value: index });
|
|
97
|
+
}
|
|
98
|
+
export const memoryWriteIndexRoute = defineJsonRoute({
|
|
99
|
+
method: 'put',
|
|
100
|
+
path: '/api/memory/index',
|
|
101
|
+
parse: parseIndexBody,
|
|
102
|
+
handle: async ({ input: index, deps }) => {
|
|
103
|
+
try {
|
|
104
|
+
await deps.notes.writeIndex({ dataDir: deps.dataDir, body: index });
|
|
105
|
+
return ok({ value: { index } });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return err({ error: createApiError({ code: 'BAD_REQUEST', message: errorMessage(error) }) });
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
}, { requireSameOrigin: true });
|
|
112
|
+
function parseConfigPatch(input) {
|
|
113
|
+
if (!isRecord(input.body))
|
|
114
|
+
return err({ error: validationError({ message: 'body must be a JSON object' }) });
|
|
115
|
+
if (input.body.enabled === undefined)
|
|
116
|
+
return ok({ value: {} });
|
|
117
|
+
if (typeof input.body.enabled !== 'boolean')
|
|
118
|
+
return err({ error: validationError({ message: 'enabled must be a boolean when provided' }) });
|
|
119
|
+
return ok({ value: { enabled: input.body.enabled } });
|
|
120
|
+
}
|
|
121
|
+
export const memoryWriteConfigRoute = defineJsonRoute({
|
|
122
|
+
method: 'patch',
|
|
123
|
+
path: '/api/memory/config',
|
|
124
|
+
parse: parseConfigPatch,
|
|
125
|
+
handle: async ({ input: patch, deps }) => {
|
|
126
|
+
try {
|
|
127
|
+
const next = await deps.notes.writeConfig({ dataDir: deps.dataDir, patch });
|
|
128
|
+
return ok({ value: { enabled: next.enabled } });
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return err({ error: createApiError({ code: 'BAD_REQUEST', message: errorMessage(error) }) });
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
}, { requireSameOrigin: true });
|
|
135
|
+
export const memoryListExtractionsRoute = defineJsonRoute({
|
|
136
|
+
method: 'get',
|
|
137
|
+
path: '/api/memory/extractions',
|
|
138
|
+
parse: () => ok({ value: undefined }),
|
|
139
|
+
handle: async ({ input: _input, deps }) => ok({ value: { extractions: deps.extractions.list() } }),
|
|
140
|
+
});
|
|
141
|
+
export const memoryClearExtractionsRoute = defineJsonRoute({
|
|
142
|
+
method: 'delete',
|
|
143
|
+
path: '/api/memory/extractions',
|
|
144
|
+
parse: () => ok({ value: undefined }),
|
|
145
|
+
handle: async ({ input: _input, deps }) => ok({ value: { removed: deps.extractions.clear() } }),
|
|
146
|
+
}, { requireSameOrigin: true });
|
|
147
|
+
export const memoryRemoveExtractionRoute = defineJsonRoute({
|
|
148
|
+
method: 'delete',
|
|
149
|
+
path: '/api/memory/extractions/:id',
|
|
150
|
+
parse: parseIdParam,
|
|
151
|
+
handle: async ({ input: id, deps }) => ok({ value: { removed: deps.extractions.remove({ id }) } }),
|
|
152
|
+
}, { requireSameOrigin: true });
|
|
153
|
+
export const memoryListVerificationsRoute = defineJsonRoute({
|
|
154
|
+
method: 'get',
|
|
155
|
+
path: '/api/memory/verifications',
|
|
156
|
+
parse: () => ok({ value: undefined }),
|
|
157
|
+
handle: async ({ input: _input, deps }) => ok({ value: { verifications: deps.verifications.list() } }),
|
|
158
|
+
});
|
|
159
|
+
export const memoryClearVerificationsRoute = defineJsonRoute({
|
|
160
|
+
method: 'delete',
|
|
161
|
+
path: '/api/memory/verifications',
|
|
162
|
+
parse: () => ok({ value: undefined }),
|
|
163
|
+
handle: async ({ input: _input, deps }) => ok({ value: { removed: deps.verifications.clear() } }),
|
|
164
|
+
}, { requireSameOrigin: true });
|
|
165
|
+
export const memoryRemoveVerificationRoute = defineJsonRoute({
|
|
166
|
+
method: 'delete',
|
|
167
|
+
path: '/api/memory/verifications/:id',
|
|
168
|
+
parse: parseIdParam,
|
|
169
|
+
handle: async ({ input: id, deps }) => ok({ value: { removed: deps.verifications.remove({ id }) } }),
|
|
170
|
+
}, { requireSameOrigin: true });
|
|
171
|
+
function parseEntryInput(input) {
|
|
172
|
+
if (!isRecord(input.body))
|
|
173
|
+
return err({ error: validationError({ message: 'body must be a JSON object' }) });
|
|
174
|
+
const { name, type } = input.body;
|
|
175
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
176
|
+
return err({ error: validationError({ message: 'name is required' }, { issues: [{ path: 'name', message: 'required non-empty string' }] }) });
|
|
177
|
+
}
|
|
178
|
+
if (typeof type !== 'string' || type.length === 0) {
|
|
179
|
+
return err({ error: validationError({ message: 'type is required' }, { issues: [{ path: 'type', message: 'required non-empty string' }] }) });
|
|
180
|
+
}
|
|
181
|
+
const description = input.body.description;
|
|
182
|
+
if (description !== undefined && typeof description !== 'string') {
|
|
183
|
+
return err({ error: validationError({ message: 'description must be a string when provided' }) });
|
|
184
|
+
}
|
|
185
|
+
const body = input.body.body;
|
|
186
|
+
if (body !== undefined && typeof body !== 'string') {
|
|
187
|
+
return err({ error: validationError({ message: 'body must be a string when provided' }) });
|
|
188
|
+
}
|
|
189
|
+
return ok({
|
|
190
|
+
value: {
|
|
191
|
+
name,
|
|
192
|
+
type,
|
|
193
|
+
...(description === undefined ? {} : { description }),
|
|
194
|
+
...(body === undefined ? {} : { body }),
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
export const memoryCreateEntryRoute = defineJsonRoute({
|
|
199
|
+
method: 'post',
|
|
200
|
+
path: '/api/memory',
|
|
201
|
+
parse: parseEntryInput,
|
|
202
|
+
handle: async ({ input, deps }) => {
|
|
203
|
+
try {
|
|
204
|
+
const entry = await deps.notes.upsertEntry({ dataDir: deps.dataDir, input });
|
|
205
|
+
return ok({ value: { entry } });
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return err({ error: createApiError({ code: 'BAD_REQUEST', message: errorMessage(error) }) });
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
}, { requireSameOrigin: true, successStatus: 201 });
|
|
212
|
+
export const memoryReadEntryRoute = defineJsonRoute({
|
|
213
|
+
method: 'get',
|
|
214
|
+
path: '/api/memory/:id',
|
|
215
|
+
parse: parseIdParam,
|
|
216
|
+
handle: async ({ input: id, deps }) => {
|
|
217
|
+
const entry = await deps.notes.readEntry({ dataDir: deps.dataDir, id });
|
|
218
|
+
return entry === null ? err({ error: createApiError({ code: 'NOT_FOUND', message: 'memory not found' }) }) : ok({ value: { entry } });
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
function parseUpdateEntry(input) {
|
|
222
|
+
const parsedId = parseIdParam(input);
|
|
223
|
+
if (!parsedId.ok)
|
|
224
|
+
return parsedId;
|
|
225
|
+
const parsedInput = parseEntryInput(input);
|
|
226
|
+
if (!parsedInput.ok)
|
|
227
|
+
return parsedInput;
|
|
228
|
+
return ok({ value: { id: parsedId.value, input: parsedInput.value } });
|
|
229
|
+
}
|
|
230
|
+
export const memoryUpdateEntryRoute = defineJsonRoute({
|
|
231
|
+
method: 'put',
|
|
232
|
+
path: '/api/memory/:id',
|
|
233
|
+
parse: parseUpdateEntry,
|
|
234
|
+
handle: async ({ input: { id, input }, deps }) => {
|
|
235
|
+
try {
|
|
236
|
+
const entry = await deps.notes.upsertEntry({ dataDir: deps.dataDir, input: { ...input, id } });
|
|
237
|
+
return ok({ value: { entry } });
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
return err({ error: createApiError({ code: 'BAD_REQUEST', message: errorMessage(error) }) });
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
}, { requireSameOrigin: true });
|
|
244
|
+
export const memoryDeleteEntryRoute = defineJsonRoute({
|
|
245
|
+
method: 'delete',
|
|
246
|
+
path: '/api/memory/:id',
|
|
247
|
+
parse: parseIdParam,
|
|
248
|
+
handle: async ({ input: id, deps }) => {
|
|
249
|
+
try {
|
|
250
|
+
await deps.notes.deleteEntry({ dataDir: deps.dataDir, id });
|
|
251
|
+
return ok({ value: { ok: true } });
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
return err({ error: createApiError({ code: 'BAD_REQUEST', message: errorMessage(error) }) });
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
}, { requireSameOrigin: true });
|
|
258
|
+
/**
|
|
259
|
+
* `GET /api/memory/events` — one SSE connection multiplexing three channels
|
|
260
|
+
* (matching OD's own reasoning: "so the browser opens one connection instead
|
|
261
|
+
* of two/three"): `connected` (once, on open), `change` (relayed from
|
|
262
|
+
* `deps.notes.events`), `extraction` (relayed from `deps.extractions.events`,
|
|
263
|
+
* whose underlying event name is `'attempt'` — see `@jini-ai/memory`'s
|
|
264
|
+
* `extraction-log.ts`), and `verify` (relayed from `deps.verifications.events`).
|
|
265
|
+
* Uses `sse.ts`'s generic channel rather than OD's bespoke `createSseResponse`;
|
|
266
|
+
* no Last-Event-ID replay (unlike `runs.ts`) since none of the three
|
|
267
|
+
* underlying emitters buffer history for reconnect — this mirrors the OD
|
|
268
|
+
* origin's own behavior (a live tail only, no replay).
|
|
269
|
+
*
|
|
270
|
+
* Bypasses `mountJsonRoute` (raw `app.get`, for the SSE response shape), so it does not get
|
|
271
|
+
* `requireSameOrigin` for free the way the JSON routes below do — the guard is applied here
|
|
272
|
+
* directly, before the SSE channel is opened, so a cross-origin request never gets a stream.
|
|
273
|
+
*/
|
|
274
|
+
export function registerMemoryEventStream({ app, deps, adapter }, _optional = {}) {
|
|
275
|
+
app.get('/api/memory/events', (req, res) => {
|
|
276
|
+
const origin = guardSameOrigin({ req, origin: adapter });
|
|
277
|
+
if (!origin.ok) {
|
|
278
|
+
sendApiError({ res, status: statusForError({ error: origin.error }), error: origin.error });
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
let seq = 0;
|
|
282
|
+
const channel = createSseChannel({ res });
|
|
283
|
+
const emit = (kind, data) => {
|
|
284
|
+
channel.enqueue({ event: { opaqueCursor: String(seq++), kind, data } });
|
|
285
|
+
};
|
|
286
|
+
const onChange = (event) => emit('change', event);
|
|
287
|
+
const onExtraction = (event) => emit('extraction', event);
|
|
288
|
+
const onVerify = (event) => emit('verify', event);
|
|
289
|
+
deps.notes.events.on('change', onChange);
|
|
290
|
+
deps.extractions.events.on('attempt', onExtraction);
|
|
291
|
+
deps.verifications.events.on('verify', onVerify);
|
|
292
|
+
channel.onClose({
|
|
293
|
+
callback: () => {
|
|
294
|
+
deps.notes.events.off('change', onChange);
|
|
295
|
+
deps.extractions.events.off('attempt', onExtraction);
|
|
296
|
+
deps.verifications.events.off('verify', onVerify);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
channel.open();
|
|
300
|
+
emit('connected', { at: Date.now() });
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Mounts every ported memory route. Static sub-resources (`/tree`,
|
|
305
|
+
* `/index`, `/config`, `/events`, `/extractions`, `/verifications`) are
|
|
306
|
+
* mounted BEFORE the `/api/memory/:id` catch-all routes, preserving OD's own
|
|
307
|
+
* ordering discipline ("so an `index`/`config`/`extract` slug can't shadow
|
|
308
|
+
* the real handlers") — Express matches routes in registration order.
|
|
309
|
+
*/
|
|
310
|
+
export function registerMemoryRoutes({ app, deps, adapter }, _optional = {}) {
|
|
311
|
+
mountJsonRoute({ app, spec: memoryOverviewRoute, deps, adapter });
|
|
312
|
+
mountJsonRoute({ app, spec: memoryTreeRoute, deps, adapter });
|
|
313
|
+
mountJsonRoute({ app, spec: memoryUpdateTreeNodeRoute, deps, adapter });
|
|
314
|
+
mountJsonRoute({ app, spec: memoryWriteIndexRoute, deps, adapter });
|
|
315
|
+
mountJsonRoute({ app, spec: memoryWriteConfigRoute, deps, adapter });
|
|
316
|
+
registerMemoryEventStream({ app, deps, adapter });
|
|
317
|
+
mountJsonRoute({ app, spec: memoryListExtractionsRoute, deps, adapter });
|
|
318
|
+
mountJsonRoute({ app, spec: memoryClearExtractionsRoute, deps, adapter });
|
|
319
|
+
mountJsonRoute({ app, spec: memoryRemoveExtractionRoute, deps, adapter });
|
|
320
|
+
mountJsonRoute({ app, spec: memoryListVerificationsRoute, deps, adapter });
|
|
321
|
+
mountJsonRoute({ app, spec: memoryClearVerificationsRoute, deps, adapter });
|
|
322
|
+
mountJsonRoute({ app, spec: memoryRemoveVerificationRoute, deps, adapter });
|
|
323
|
+
mountJsonRoute({ app, spec: memoryCreateEntryRoute, deps, adapter });
|
|
324
|
+
mountJsonRoute({ app, spec: memoryReadEntryRoute, deps, adapter });
|
|
325
|
+
mountJsonRoute({ app, spec: memoryUpdateEntryRoute, deps, adapter });
|
|
326
|
+
mountJsonRoute({ app, spec: memoryDeleteEntryRoute, deps, adapter });
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Express } from 'express';
|
|
2
|
+
import { type AnthropicToolExecutor, type AzureToolExecutor, type GoogleToolExecutor, type OllamaToolExecutor, type OpenAiToolExecutor, type DnsLookupFn, type PinnedFetch } from '@jini-ai/agent-runtime';
|
|
3
|
+
import type { AdapterContext } from '@jini-ai/http-kit';
|
|
4
|
+
/** Diagnostic detail for an internal-error response this route deliberately does not disclose to the client (SEC-005, matching `runs.ts#RunInternalErrorContext`). Only reached if a turn-runner's promise itself rejects — every turn-runner already converts every provider/network failure into an `'error'`+`'end'` event pair internally, so this is a genuinely unexpected-exception path (e.g. a caller-supplied `executeTool` throwing). */
|
|
5
|
+
export interface ModelProxyInternalErrorContext {
|
|
6
|
+
readonly provider: 'anthropic' | 'openai' | 'azure' | 'google' | 'ollama';
|
|
7
|
+
readonly correlationId: string;
|
|
8
|
+
readonly error: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface ModelProxyHttpDeps {
|
|
11
|
+
/** Host-owned tool execution for the Anthropic proxy route. Omit to stream `tool_use` events without running a server-side tool loop (see module doc). */
|
|
12
|
+
readonly anthropicExecuteTool?: AnthropicToolExecutor;
|
|
13
|
+
/** Host-owned tool execution for the OpenAI proxy route. Same default-unset behavior as `anthropicExecuteTool`. */
|
|
14
|
+
readonly openaiExecuteTool?: OpenAiToolExecutor;
|
|
15
|
+
/** Host-owned tool execution for the Azure OpenAI proxy route. Same default-unset behavior as `anthropicExecuteTool`. */
|
|
16
|
+
readonly azureExecuteTool?: AzureToolExecutor;
|
|
17
|
+
/** Host-owned tool execution for the Google (Gemini) proxy route. Same default-unset behavior as `anthropicExecuteTool`. */
|
|
18
|
+
readonly googleExecuteTool?: GoogleToolExecutor;
|
|
19
|
+
/** Host-owned tool execution for the Ollama proxy route. Same default-unset behavior as `anthropicExecuteTool`. */
|
|
20
|
+
readonly ollamaExecuteTool?: OllamaToolExecutor;
|
|
21
|
+
/** Host-owned sink for the real exception behind a generic internal-error SSE event (SEC-005). Defaults to `console.error`. */
|
|
22
|
+
readonly onInternalError?: (context: ModelProxyInternalErrorContext) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Injectable HTTP transport, forwarded verbatim to every provider turn-runner as its own
|
|
25
|
+
* `fetchImpl` option (`@jini-ai/agent-runtime`'s `AnthropicTurnOptions.fetchImpl`, etc.), which
|
|
26
|
+
* itself defaults to that package's SSRF-guarded, DNS-pinned `pinnedFetch`. This is the
|
|
27
|
+
* dependency-injection seam `__tests__/model-proxy.test.ts` uses to supply a fake transport
|
|
28
|
+
* directly, instead of module-mocking `@jini-ai/agent-runtime`'s `connection-guard.ts` (or, worse,
|
|
29
|
+
* its compiled `dist/` output, since this package only ever imports that package's single public
|
|
30
|
+
* barrel). Defaults to unset, i.e. every route keeps using the real, guarded transport — **never
|
|
31
|
+
* set this in production wiring**; doing so bypasses the SSRF guard entirely for whatever
|
|
32
|
+
* transport is supplied.
|
|
33
|
+
*/
|
|
34
|
+
readonly fetchImpl?: PinnedFetch;
|
|
35
|
+
/**
|
|
36
|
+
* Injectable DNS resolver, forwarded verbatim to every provider turn-runner as its own
|
|
37
|
+
* `dnsLookup` option, which itself defaults to `@jini-ai/agent-runtime`'s `node:dns`-backed
|
|
38
|
+
* `defaultDnsLookup`. Same test-only override rationale as `fetchImpl` — pairs with it so a test
|
|
39
|
+
* never needs to mock `node:dns` either.
|
|
40
|
+
*/
|
|
41
|
+
readonly dnsLookup?: DnsLookupFn;
|
|
42
|
+
}
|
|
43
|
+
/** Mounts `POST /api/proxy/{anthropic,openai,azure,google,ollama}/stream` and the generic `POST /api/proxy/:provider/stream` catch-all. */
|
|
44
|
+
export declare function registerModelProxyRoutes({ app, deps, adapter }: {
|
|
45
|
+
readonly app: Express;
|
|
46
|
+
readonly deps: ModelProxyHttpDeps;
|
|
47
|
+
readonly adapter: AdapterContext;
|
|
48
|
+
}, _optional?: Record<string, never>): void;
|
|
49
|
+
//# sourceMappingURL=model-proxy.d.ts.map
|