@jini-ai/daemon 0.6.19 → 0.6.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/agent-executor/events.d.ts +6 -4
- package/dist/agent-executor/events.js +27 -6
- package/dist/agent-executor/sanitized-line-stream.d.ts +24 -0
- package/dist/agent-executor/sanitized-line-stream.js +45 -0
- package/dist/http/delegated-tools.d.ts +12 -0
- package/dist/http/delegated-tools.js +18 -3
- package/dist/tool-recovery/redaction.d.ts +1 -0
- package/dist/tool-recovery/redaction.js +4 -1
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 0.6.22
|
|
2
|
+
|
|
3
|
+
- Child stdout can be framed and sanitized line by line before parsing. A timed-out or cancelled delegated tool can report host-loaded recovery facts through `recoverInterruptedTool`, with no retry.
|
|
4
|
+
|
|
1
5
|
## 0.6.19
|
|
2
6
|
|
|
3
7
|
- `DelegatedToolsHttpDeps.toolRegistry` takes a list-only registry view (`Pick<ToolRegistry, 'list'>`): the route only reads descriptors, and hosts pass descriptor-only facades.
|
|
@@ -11,7 +11,7 @@ import type { ChildDrivenStreamFormat, TerminateChildTreeDeps, AgentCleanupFailu
|
|
|
11
11
|
/** Default sink when a host does not supply `onCleanupFailure`: still observable, never silent. Redacted per SEC-007 (a spawn/permission error can embed paths/host detail). */
|
|
12
12
|
export declare function defaultCleanupFailureSink(context: AgentCleanupFailureContext): void;
|
|
13
13
|
/**
|
|
14
|
-
* Default ceiling on the `'until-close'` stdout accumulator (see `RuntimeStdoutPolicy` in
|
|
14
|
+
* Default ceiling on the `'until-close'` or per-line stdout accumulator (see `RuntimeStdoutPolicy` in
|
|
15
15
|
* `@jini-ai/agent-runtime`), in bytes of received UTF-8.
|
|
16
16
|
*
|
|
17
17
|
* A buffered def holds its child's entire stdout in one in-memory string until the process closes,
|
|
@@ -20,8 +20,8 @@ export declare function defaultCleanupFailureSink(context: AgentCleanupFailureCo
|
|
|
20
20
|
* nothing obliges it to ever close or to stop emitting. Without a ceiling one run could exhaust the
|
|
21
21
|
* daemon's heap and take every unrelated run in the process down with it.
|
|
22
22
|
*
|
|
23
|
-
* 8 MiB
|
|
24
|
-
*
|
|
23
|
+
* 8 MiB was chosen to sit far above the original buffered print-mode auth prompt and result text
|
|
24
|
+
* (a few KiB) while staying
|
|
25
25
|
* small enough that a hostile child cannot meaningfully pressure the heap. A host that genuinely
|
|
26
26
|
* needs more passes `CreateAgentExecutorOptions.bufferedStdoutMaxBytes`.
|
|
27
27
|
*/
|
|
@@ -101,13 +101,15 @@ interface WireChildLifecycleContext extends TerminateChildTreeDeps {
|
|
|
101
101
|
*
|
|
102
102
|
* *When* those chunks leave is the def's call, via `def.stdoutPolicy`:
|
|
103
103
|
*
|
|
104
|
-
* - `'live'` (the default
|
|
104
|
+
* - `'live'` (the default) — emit per
|
|
105
105
|
* chunk, as it arrives.
|
|
106
106
|
* - `'until-close'` — accumulate, and emit the whole thing exactly once
|
|
107
107
|
* from the `close` handler, after `def.stdoutPolicy.sanitize`. For an
|
|
108
108
|
* adapter that can print a secret to stdout and still exit 0, no
|
|
109
109
|
* per-chunk decision is safe: the pattern to redact can straddle two
|
|
110
110
|
* `'data'` events.
|
|
111
|
+
* - `'line'` — sanitize each bounded complete wire line before both raw delivery and parsing;
|
|
112
|
+
* retain only its partial tail. Secrets split across chunks stay private without waiting for exit.
|
|
111
113
|
*
|
|
112
114
|
* The buffered path holds back the raw `'stdout'` echo too, not just the
|
|
113
115
|
* `'agent'`/`text_delta`, and sanitizes both. Emitting an unsanitized raw
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createToolResultDiagnosticProjection, projectDiagnosticFrame } from '../tool-result-diagnostics.js';
|
|
2
2
|
import { appendSerialTask } from "@jini-ai/core/primitives";
|
|
3
3
|
import { createLiveSessionState } from './live-session-state.js';
|
|
4
|
+
import { createSanitizedLineStream } from './sanitized-line-stream.js';
|
|
4
5
|
import { acceptsMidRunUserMessages, createMessageRelay } from './message-relay.js';
|
|
5
6
|
import { randomUUID } from 'node:crypto';
|
|
6
7
|
import { createModelReceiptTracker } from './model-receipts.js';
|
|
@@ -186,7 +187,7 @@ function receivedJournalEntry(channel, content) {
|
|
|
186
187
|
return { content, provenance: { source: 'agent', channel }, trust: 'untrusted' };
|
|
187
188
|
}
|
|
188
189
|
/**
|
|
189
|
-
* Default ceiling on the `'until-close'` stdout accumulator (see `RuntimeStdoutPolicy` in
|
|
190
|
+
* Default ceiling on the `'until-close'` or per-line stdout accumulator (see `RuntimeStdoutPolicy` in
|
|
190
191
|
* `@jini-ai/agent-runtime`), in bytes of received UTF-8.
|
|
191
192
|
*
|
|
192
193
|
* A buffered def holds its child's entire stdout in one in-memory string until the process closes,
|
|
@@ -195,8 +196,8 @@ function receivedJournalEntry(channel, content) {
|
|
|
195
196
|
* nothing obliges it to ever close or to stop emitting. Without a ceiling one run could exhaust the
|
|
196
197
|
* daemon's heap and take every unrelated run in the process down with it.
|
|
197
198
|
*
|
|
198
|
-
* 8 MiB
|
|
199
|
-
*
|
|
199
|
+
* 8 MiB was chosen to sit far above the original buffered print-mode auth prompt and result text
|
|
200
|
+
* (a few KiB) while staying
|
|
200
201
|
* small enough that a hostile child cannot meaningfully pressure the heap. A host that genuinely
|
|
201
202
|
* needs more passes `CreateAgentExecutorOptions.bufferedStdoutMaxBytes`.
|
|
202
203
|
*/
|
|
@@ -283,13 +284,15 @@ function createStdoutDiagnostics({ ctx, enqueueEmit }, _options = {}) {
|
|
|
283
284
|
*
|
|
284
285
|
* *When* those chunks leave is the def's call, via `def.stdoutPolicy`:
|
|
285
286
|
*
|
|
286
|
-
* - `'live'` (the default
|
|
287
|
+
* - `'live'` (the default) — emit per
|
|
287
288
|
* chunk, as it arrives.
|
|
288
289
|
* - `'until-close'` — accumulate, and emit the whole thing exactly once
|
|
289
290
|
* from the `close` handler, after `def.stdoutPolicy.sanitize`. For an
|
|
290
291
|
* adapter that can print a secret to stdout and still exit 0, no
|
|
291
292
|
* per-chunk decision is safe: the pattern to redact can straddle two
|
|
292
293
|
* `'data'` events.
|
|
294
|
+
* - `'line'` — sanitize each bounded complete wire line before both raw delivery and parsing;
|
|
295
|
+
* retain only its partial tail. Secrets split across chunks stay private without waiting for exit.
|
|
293
296
|
*
|
|
294
297
|
* The buffered path holds back the raw `'stdout'` echo too, not just the
|
|
295
298
|
* `'agent'`/`text_delta`, and sanitizes both. Emitting an unsanitized raw
|
|
@@ -364,12 +367,25 @@ export function wireChildLifecycle(ctx) {
|
|
|
364
367
|
let bridgeChecked = !ctx.expectsJiniBridge;
|
|
365
368
|
let bridgeUnavailable = false;
|
|
366
369
|
// `def.stdoutPolicy` read once, up front, so the per-chunk handler below is a single boolean
|
|
367
|
-
// test rather than a repeated union narrowing. `undefined`
|
|
370
|
+
// test rather than a repeated union narrowing. `undefined` means
|
|
368
371
|
// live — see this function's own doc.
|
|
369
372
|
const stdoutPolicy = def.stdoutPolicy;
|
|
370
373
|
const bufferStdoutUntilClose = stdoutPolicy?.buffering === 'until-close';
|
|
371
374
|
const sanitizeBufferedStdout = stdoutPolicy?.buffering === 'until-close' ? stdoutPolicy.sanitize : undefined;
|
|
372
|
-
|
|
375
|
+
const lineStdout = stdoutPolicy?.buffering === 'line' ? createSanitizedLineStream({
|
|
376
|
+
maxBytes: ctx.bufferedStdoutMaxBytes, sanitize: stdoutPolicy.sanitize,
|
|
377
|
+
emit: ({ text }) => {
|
|
378
|
+
stdoutDiagnostics.feed({ text });
|
|
379
|
+
if (streamFormat === 'plain')
|
|
380
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'text_delta', delta: text } } }));
|
|
381
|
+
else
|
|
382
|
+
streamHandler?.feed({ chunk: text });
|
|
383
|
+
},
|
|
384
|
+
onOverflow: ({ bytes }) => enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'error', data: {
|
|
385
|
+
message: bufferedStdoutTruncationNotice(bytes, ctx.bufferedStdoutMaxBytes),
|
|
386
|
+
} } })),
|
|
387
|
+
}) : undefined;
|
|
388
|
+
// Accumulator for the `'until-close'` path. Stays `''` for live and line policies, and the flush below
|
|
373
389
|
// is then a no-op that emits nothing. Bounded by `ctx.bufferedStdoutMaxBytes` — see
|
|
374
390
|
// {@link DEFAULT_BUFFERED_STDOUT_MAX_BYTES} for why an unbounded accumulator was a
|
|
375
391
|
// denial-of-service surface rather than merely untidy.
|
|
@@ -647,6 +663,10 @@ export function wireChildLifecycle(ctx) {
|
|
|
647
663
|
child.stdout?.on('data', (chunk) => {
|
|
648
664
|
const text = chunk.toString('utf8');
|
|
649
665
|
stdoutDiagnostics.record({ chunk, text });
|
|
666
|
+
if (lineStdout) {
|
|
667
|
+
lineStdout.feed({ chunk: text });
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
650
670
|
if (streamFormat === 'plain' && text.length > 0)
|
|
651
671
|
userVisibleOutputSeen = true;
|
|
652
672
|
if (bufferStdoutUntilClose) {
|
|
@@ -716,6 +736,7 @@ export function wireChildLifecycle(ctx) {
|
|
|
716
736
|
controlScanBuffer = '';
|
|
717
737
|
}
|
|
718
738
|
flushBufferedStdout();
|
|
739
|
+
lineStdout?.flush({});
|
|
719
740
|
streamHandler?.flush();
|
|
720
741
|
session.endSession();
|
|
721
742
|
stdoutDiagnostics.flush();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Frame and sanitize stdout before either parser or raw-event delivery.
|
|
2
|
+
* @param required - Host byte cap, pure sanitizer and delivery/error sinks.
|
|
3
|
+
* @returns A per-process stream; flush delivers a final unterminated line once.
|
|
4
|
+
* @complexity O(n) time for n wire characters, O(maxBytes) retained text plus incoming chunk slices.
|
|
5
|
+
* @example const stream = createSanitizedLineStream({ maxBytes: 4096, sanitize, emit, onOverflow });
|
|
6
|
+
*/
|
|
7
|
+
export declare function createSanitizedLineStream({ maxBytes, sanitize, emit, onOverflow }: {
|
|
8
|
+
maxBytes: number;
|
|
9
|
+
sanitize: (required: {
|
|
10
|
+
fullText: string;
|
|
11
|
+
}) => string;
|
|
12
|
+
emit: (required: {
|
|
13
|
+
text: string;
|
|
14
|
+
}, optional?: Record<string, never>) => void;
|
|
15
|
+
onOverflow: (required: {
|
|
16
|
+
bytes: number;
|
|
17
|
+
}, optional?: Record<string, never>) => void;
|
|
18
|
+
}, _options?: Record<string, never>): {
|
|
19
|
+
feed(required: {
|
|
20
|
+
chunk: string;
|
|
21
|
+
}, optional?: Record<string, never>): void;
|
|
22
|
+
flush(required: Record<string, never>, optional?: Record<string, never>): void;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=sanitized-line-stream.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Frame and sanitize stdout before either parser or raw-event delivery.
|
|
2
|
+
* @param required - Host byte cap, pure sanitizer and delivery/error sinks.
|
|
3
|
+
* @returns A per-process stream; flush delivers a final unterminated line once.
|
|
4
|
+
* @complexity O(n) time for n wire characters, O(maxBytes) retained text plus incoming chunk slices.
|
|
5
|
+
* @example const stream = createSanitizedLineStream({ maxBytes: 4096, sanitize, emit, onOverflow });
|
|
6
|
+
*/
|
|
7
|
+
export function createSanitizedLineStream({ maxBytes, sanitize, emit, onOverflow }, _options = {}) {
|
|
8
|
+
let parts = [];
|
|
9
|
+
let bytes = 0;
|
|
10
|
+
let overflow = false;
|
|
11
|
+
/** One line's fragments retain at most maxBytes; an oversized line is discarded through its end. */
|
|
12
|
+
function append(text) {
|
|
13
|
+
if (!text)
|
|
14
|
+
return;
|
|
15
|
+
bytes += Buffer.byteLength(text, 'utf8');
|
|
16
|
+
if (bytes > maxBytes) {
|
|
17
|
+
parts = [];
|
|
18
|
+
overflow = true;
|
|
19
|
+
}
|
|
20
|
+
if (!overflow)
|
|
21
|
+
parts.push(text);
|
|
22
|
+
}
|
|
23
|
+
/** Delivery happens once per completed line, or once for the final unterminated tail. */
|
|
24
|
+
function flush(newline) {
|
|
25
|
+
if (overflow)
|
|
26
|
+
onOverflow({ bytes });
|
|
27
|
+
else if (bytes > 0 || newline)
|
|
28
|
+
emit({ text: sanitize({ fullText: parts.join('') + newline }) });
|
|
29
|
+
parts = [];
|
|
30
|
+
bytes = 0;
|
|
31
|
+
overflow = false;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
feed({ chunk }, _optional = {}) {
|
|
35
|
+
const lines = chunk.split('\n');
|
|
36
|
+
lines.forEach((line, index) => {
|
|
37
|
+
append(line);
|
|
38
|
+
if (index < lines.length - 1)
|
|
39
|
+
flush('\n');
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
flush(_required, _optional = {}) { flush(''); },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=sanitized-line-stream.js.map
|
|
@@ -37,6 +37,8 @@ export interface DelegatedToolExecuteResponse {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface DelegatedToolsInternalErrorContext {
|
|
39
39
|
readonly source: 'delegated-tool-execute' | 'resolve-principal';
|
|
40
|
+
/** Optional host-loaded recovery facts; the host describer must redact these as usual. */
|
|
41
|
+
readonly recoveryMessage?: string;
|
|
40
42
|
readonly runId: string;
|
|
41
43
|
readonly toolId: string;
|
|
42
44
|
readonly correlationId: string;
|
|
@@ -50,6 +52,16 @@ export interface DelegatedToolsInternalErrorContext {
|
|
|
50
52
|
readonly status?: 'timed-out' | 'cancelled' | 'failed';
|
|
51
53
|
}
|
|
52
54
|
export interface DelegatedToolsHttpDeps {
|
|
55
|
+
/** One bounded read after an interrupted call, for hosts whose jobs live in another process.
|
|
56
|
+
* Must authorize with the supplied principal, never execute a write/retry, and impose its own
|
|
57
|
+
* deadline. A throw is contained; absent facts remain unknown. No calls on the success path.
|
|
58
|
+
*/
|
|
59
|
+
readonly recoverInterruptedTool?: (required: {
|
|
60
|
+
principal: Principal;
|
|
61
|
+
runId: string;
|
|
62
|
+
toolId: string;
|
|
63
|
+
result: ToolExecutionResult;
|
|
64
|
+
}) => Promise<string | undefined>;
|
|
53
65
|
/** The same negotiated digest store supplied to the run lifecycle and agent executor. */
|
|
54
66
|
readonly delegatedResultCorrelation?: DelegatedResultCorrelation;
|
|
55
67
|
readonly lifecycle: RunLifecycle;
|
|
@@ -130,7 +130,7 @@ function parseDelegatedToolExecute(input) {
|
|
|
130
130
|
* vouches for this exact result via `deps.isModelSafeToolFailure` (it has already redacted the text
|
|
131
131
|
* itself), in which case it is a `422 TOOL_EXECUTION_FAILED` carrying the host's text verbatim.
|
|
132
132
|
*/
|
|
133
|
-
function toolExecutionResultToApiResult(deps, { runId, toolId, result }) {
|
|
133
|
+
function toolExecutionResultToApiResult(deps, { runId, toolId, result, recoveryMessage }) {
|
|
134
134
|
switch (result.status) {
|
|
135
135
|
case 'completed': {
|
|
136
136
|
const outcome = batchOutcomeFor({ output: result.output });
|
|
@@ -143,7 +143,7 @@ function toolExecutionResultToApiResult(deps, { runId, toolId, result }) {
|
|
|
143
143
|
return err({ error: createApiError({ code: 'TOOL_OPERATION_DENIED', message: 'this operation was denied during confirmation' }) });
|
|
144
144
|
case 'timed-out':
|
|
145
145
|
case 'cancelled':
|
|
146
|
-
return err({ error: reportInternalError(deps, { source: 'delegated-tool-execute', error: result.status, runId, toolId, status: result.status }) });
|
|
146
|
+
return err({ error: reportInternalError(deps, { source: 'delegated-tool-execute', error: result.status, runId, toolId, ...(recoveryMessage ? { recoveryMessage } : {}), status: result.status }) });
|
|
147
147
|
case 'failed':
|
|
148
148
|
return err({ error: failedResultToApiError(deps, { runId, toolId, result }) });
|
|
149
149
|
default: {
|
|
@@ -163,6 +163,21 @@ function failedResultToApiError(deps, { runId, toolId, result }) {
|
|
|
163
163
|
}
|
|
164
164
|
return reportInternalError(deps, { source: 'delegated-tool-execute', error: result.error ?? result.status, runId, toolId, status: 'failed' });
|
|
165
165
|
}
|
|
166
|
+
/** Read host-owned recovery facts once after interruption. The host supplies the deadline and
|
|
167
|
+
* permission-checked read; a failed read never replaces or retries the original operation.
|
|
168
|
+
* @complexity One optional bounded read; no extra work on successful executions.
|
|
169
|
+
*/
|
|
170
|
+
async function toolExecutionResultWithRecovery(deps, required) {
|
|
171
|
+
const { principal, runId, toolId, result } = required;
|
|
172
|
+
let recoveryMessage;
|
|
173
|
+
if (result.status === 'timed-out' || result.status === 'cancelled') {
|
|
174
|
+
try {
|
|
175
|
+
recoveryMessage = await deps.recoverInterruptedTool?.({ principal, runId, toolId, result });
|
|
176
|
+
}
|
|
177
|
+
catch { /* Recovery cannot change the interrupted write or expose its own failure. */ }
|
|
178
|
+
}
|
|
179
|
+
return toolExecutionResultToApiResult(deps, { runId, toolId, result, ...(recoveryMessage ? { recoveryMessage } : {}) });
|
|
180
|
+
}
|
|
166
181
|
/**
|
|
167
182
|
* `POST /api/delegated-tool-calls` — executes one delegated tool call against an already-started
|
|
168
183
|
* run. Maps `ToolExecutionResult.status` to the HTTP response via `toolExecutionResultToApiResult`
|
|
@@ -224,7 +239,7 @@ export const delegatedToolExecuteRoute = defineJsonRoute({
|
|
|
224
239
|
input: input.input,
|
|
225
240
|
...(signal !== undefined ? { signal } : {}),
|
|
226
241
|
});
|
|
227
|
-
return
|
|
242
|
+
return toolExecutionResultWithRecovery(deps, { principal, runId: input.runId, toolId: input.toolId, result });
|
|
228
243
|
}
|
|
229
244
|
catch (error) {
|
|
230
245
|
if (error instanceof ToolInputError) {
|
|
@@ -77,6 +77,7 @@ export declare function isRedactedToolFailure({ result }: {
|
|
|
77
77
|
* compiles against a published http-kit that predates `status`.
|
|
78
78
|
*/
|
|
79
79
|
export interface DelegatedInternalErrorContext {
|
|
80
|
+
readonly recoveryMessage?: string;
|
|
80
81
|
readonly source: string;
|
|
81
82
|
readonly runId: string;
|
|
82
83
|
readonly toolId: string;
|
|
@@ -97,7 +97,10 @@ function delegatedInternalErrorReason(context) {
|
|
|
97
97
|
* @complexity O(reason length) for the redaction pass.
|
|
98
98
|
*/
|
|
99
99
|
export function describeDelegatedInternalError({ context, ...deps }, _optional = {}) {
|
|
100
|
-
|
|
100
|
+
let reason = delegatedInternalErrorReason(context);
|
|
101
|
+
if ((context.status === "timed-out" || context.status === "cancelled") && context.recoveryMessage)
|
|
102
|
+
reason = context.recoveryMessage;
|
|
103
|
+
const { text, redactions } = deps.redactSecretShapes({ text: reason });
|
|
101
104
|
const errorId = deps.mintErrorId();
|
|
102
105
|
safeOnFailure(deps.onFailure, {
|
|
103
106
|
errorId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/daemon",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.22",
|
|
4
4
|
"description": "The stateful agent daemon runtime: run lifecycle, durable event-log port, the tool-execution boundary, agent executor, terminal sessions, and routines.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -153,22 +153,22 @@
|
|
|
153
153
|
"express": "^4.21.0",
|
|
154
154
|
"@types/express": "^4.17.21",
|
|
155
155
|
"@jini-ai/db": "0.6.19",
|
|
156
|
-
"@jini-ai/agent-runtime": "^0.6.
|
|
157
|
-
"@jini-ai/chat": "0.6.
|
|
158
|
-
"@jini-ai/core": "^0.6.
|
|
159
|
-
"@jini-ai/
|
|
160
|
-
"@jini-ai/
|
|
161
|
-
"@jini-ai/
|
|
156
|
+
"@jini-ai/agent-runtime": "^0.6.22",
|
|
157
|
+
"@jini-ai/chat": "0.6.22",
|
|
158
|
+
"@jini-ai/core": "^0.6.22",
|
|
159
|
+
"@jini-ai/protocol": "^0.6.19",
|
|
160
|
+
"@jini-ai/platform": "^0.6.22",
|
|
161
|
+
"@jini-ai/http-kit": "0.6.22"
|
|
162
162
|
},
|
|
163
163
|
"dependencies": {
|
|
164
164
|
"smol-toml": "1.9.1",
|
|
165
165
|
"kysely": "^0.29.6",
|
|
166
|
-
"@jini-ai/core": "^0.6.
|
|
166
|
+
"@jini-ai/core": "^0.6.22",
|
|
167
167
|
"@jini-ai/protocol": "^0.6.19",
|
|
168
|
-
"@jini-ai/agent-runtime": "^0.6.19",
|
|
169
168
|
"@jini-ai/db": "^0.6.19",
|
|
170
|
-
"@jini-ai/
|
|
171
|
-
"@jini-ai/
|
|
169
|
+
"@jini-ai/agent-runtime": "^0.6.22",
|
|
170
|
+
"@jini-ai/platform": "^0.6.22",
|
|
171
|
+
"@jini-ai/http-kit": "^0.6.22"
|
|
172
172
|
},
|
|
173
173
|
"peerDependencies": {
|
|
174
174
|
"node-pty": "^1.1.0",
|