@jini-ai/daemon 0.6.15-rc.2 → 0.6.16
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 +12 -0
- package/README.md +14 -4
- package/dist/agent-executor/codex/home-config.js +3 -2
- package/dist/agent-executor/codex/home-staging.js +2 -2
- package/dist/agent-executor/codex/isolation.js +4 -3
- package/dist/agent-executor/contracts.d.ts +1 -1
- package/dist/agent-executor/contracts.js +0 -1
- package/dist/agent-executor/event-translation.d.ts +3 -3
- package/dist/agent-executor/event-translation.js +6 -6
- package/dist/agent-executor/events.js +65 -51
- package/dist/agent-executor/index.d.ts +5 -5
- package/dist/agent-executor/index.js +5 -5
- package/dist/agent-executor/launch.js +30 -46
- package/dist/agent-executor/live-session-state.js +2 -2
- package/dist/agent-executor/mcp-bridge.js +5 -0
- package/dist/agent-executor/message-relay.js +5 -6
- package/dist/agent-executor/run-output.js +7 -2
- package/dist/ai-trace-lifecycle.d.ts +1 -1
- package/dist/ai-trace-lifecycle.js +1 -1
- package/dist/close-status.js +6 -2
- package/dist/core/omit-keys.d.ts +7 -0
- package/dist/core/omit-keys.js +12 -0
- package/dist/core/read-only-tools.js +5 -1
- package/dist/core/tool-audit.js +11 -7
- package/dist/core/tool-gaps.js +1 -1
- package/dist/delegated-result-correlation.js +2 -2
- package/dist/frontend-capability-tools.d.ts +2 -0
- package/dist/frontend-capability-tools.js +7 -1
- package/dist/frontend-session-registry.d.ts +42 -3
- package/dist/frontend-session-registry.js +61 -9
- package/dist/http/agents.d.ts +4 -0
- package/dist/http/attachments.js +13 -12
- package/dist/http/component-catalog.js +1 -1
- package/dist/http/connectors.js +7 -5
- package/dist/http/db-ops.js +5 -0
- package/dist/http/delegated-tools.js +5 -0
- package/dist/http/frontend-control.d.ts +13 -0
- package/dist/http/frontend-control.js +14 -3
- package/dist/http/frontend-guest-scope.d.ts +32 -0
- package/dist/http/frontend-guest-scope.js +63 -0
- package/dist/http/frontend-sessions.d.ts +29 -6
- package/dist/http/frontend-sessions.js +108 -28
- package/dist/http/host-tools.js +7 -5
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +1 -0
- package/dist/http/memory.js +3 -1
- package/dist/http/model-proxy.js +13 -8
- package/dist/http/research-tavily.adapter.js +2 -1
- package/dist/http/routines.js +7 -5
- package/dist/http/terminals.js +5 -0
- package/dist/http/tool-catalog.js +1 -1
- package/dist/http/xai.js +10 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/legacy-data-migration.d.ts +0 -12
- package/dist/legacy-data-migration.js +21 -13
- package/dist/remote-tool-executor.js +2 -1
- package/dist/routines/schedule.js +2 -1
- package/dist/routines/scheduler.js +6 -7
- package/dist/run-lifecycle.js +2 -1
- package/dist/store/agent-sessions/sql.js +7 -3
- package/dist/store/event-log/sqlite-kernel.js +7 -2
- package/dist/store/event-log/sqlite.js +6 -2
- package/dist/surface-exchanges.js +3 -3
- package/dist/terminal-session.d.ts +51 -20
- package/dist/terminal-session.js +10 -94
- package/dist/terminal.adapter.d.ts +22 -0
- package/dist/terminal.adapter.js +47 -0
- package/dist/tool-executor.d.ts +4 -2
- package/dist/tool-executor.js +95 -15
- package/dist/tool-recovery/recovery.js +5 -3
- package/dist/tool-recovery/redaction.js +1 -2
- package/dist/tool-recovery/stack.js +5 -1
- package/dist/tool-result-media.d.ts +4 -0
- package/dist/tool-result-media.js +10 -3
- package/dist/tool-result-surfaces.js +10 -9
- package/package.json +30 -34
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isIssuedToolFailureDiagnostic } from "./diagnostics.js";
|
|
2
|
-
import { askOnce, SURFACE_DISMISSED_PARAM,
|
|
2
|
+
import { askOnce, SURFACE_DISMISSED_PARAM, } from "../surface-exchanges.js";
|
|
3
3
|
import { refuseNonReadOnlyDispatch } from "../core/read-only-tools.js";
|
|
4
4
|
/**
|
|
5
5
|
* @file The CONSUMER of `contracts/core/tool-failure-diagnostics.ts`'s `ToolFailureDiagnostic`
|
|
@@ -119,7 +119,9 @@ function isActionableDiagnostic(value) {
|
|
|
119
119
|
* @complexity O(1).
|
|
120
120
|
*/
|
|
121
121
|
function remedyReportedFailure(output) {
|
|
122
|
-
|
|
122
|
+
if (!isPlainObject(output))
|
|
123
|
+
return false;
|
|
124
|
+
return output["saved"] === false || output["created"] === false || output["cancelled"] === true || output["connected"] === false;
|
|
123
125
|
}
|
|
124
126
|
/** `true` once the bounded walk should stop descending — depth past {@link MAX_DIAGNOSTIC_SCAN_DEPTH}
|
|
125
127
|
* or the node budget exhausted. Pulled out of {@link walkForDiagnostic} so that function's own guard
|
|
@@ -400,7 +402,7 @@ function remedyApplied(remedyResult) {
|
|
|
400
402
|
export function withToolFailureRecovery({ inner, ...deps }, _optional = {}) {
|
|
401
403
|
return {
|
|
402
404
|
execute: async (required, optional = {}) => {
|
|
403
|
-
const { principal,
|
|
405
|
+
const { principal, input } = required;
|
|
404
406
|
const { signal, emitSurface } = optional;
|
|
405
407
|
const result = await inner.execute(required, optional);
|
|
406
408
|
// SILENCE STAYS FREE: everything but a completed call whose output carries an actionable
|
|
@@ -148,8 +148,7 @@ function redactFailedResult(result, context, deps) {
|
|
|
148
148
|
return result;
|
|
149
149
|
return { ...result, error: deps.redactSecretShapes({ text: result.error }).text };
|
|
150
150
|
}
|
|
151
|
-
const mintErrorId = deps
|
|
152
|
-
const onFailure = deps.onFailure;
|
|
151
|
+
const { mintErrorId, onFailure } = deps;
|
|
153
152
|
const { text, redactions } = deps.redactSecretShapes({ text: result.error ?? `tool "${context.toolId}" failed` });
|
|
154
153
|
const errorId = mintErrorId();
|
|
155
154
|
safeOnFailure(onFailure, {
|
|
@@ -46,6 +46,10 @@ import { withReadOnlyToolConstraint } from "../core/read-only-tools.js";
|
|
|
46
46
|
import { withToolAttemptAudit } from "../core/tool-audit.js";
|
|
47
47
|
import { withToolFailureRecovery } from "./recovery.js";
|
|
48
48
|
import { withRedactedToolFailures, readToolErrorId } from "./redaction.js";
|
|
49
|
+
/** The audit wrapper's options: only an error sink the caller actually supplied. */
|
|
50
|
+
function auditOptions(audit) {
|
|
51
|
+
return audit.onSinkError ? { onSinkError: audit.onSinkError } : {};
|
|
52
|
+
}
|
|
49
53
|
/** One registry and innermost read-only gate protect original, remedy and retry alike.
|
|
50
54
|
* Redaction precedes observation; recovery is outermost so each actual attempt is audited.
|
|
51
55
|
* @complexity O(1) composition; each decorator owns its runtime cost.
|
|
@@ -55,7 +59,7 @@ export function createAssistantToolExecutor(deps, _optional = {}) {
|
|
|
55
59
|
registry: deps.registry, idGenerator: { newId: deps.newExecutionId }, messages: deps.readOnlyMessages }, {});
|
|
56
60
|
const redacted = withRedactedToolFailures({ inner: guarded, ...deps.toolFailures }, {});
|
|
57
61
|
const audited = deps.toolAttemptAudit
|
|
58
|
-
? withToolAttemptAudit({ inner: redacted, ...deps.toolAttemptAudit, readErrorId: readToolErrorId }, deps.toolAttemptAudit
|
|
62
|
+
? withToolAttemptAudit({ inner: redacted, ...deps.toolAttemptAudit, readErrorId: readToolErrorId }, auditOptions(deps.toolAttemptAudit))
|
|
59
63
|
: redacted;
|
|
60
64
|
return withToolFailureRecovery({ ...deps, inner: audited }, {});
|
|
61
65
|
}
|
|
@@ -42,6 +42,10 @@ export interface ToolResultImageBlock {
|
|
|
42
42
|
readonly mimeType: string;
|
|
43
43
|
/** Base64-encoded image bytes. */
|
|
44
44
|
readonly data: string;
|
|
45
|
+
/** Optional caption and alt text for a chat renderer. Not an MCP field; MCP clients ignore it. */
|
|
46
|
+
readonly title?: string;
|
|
47
|
+
/** Optional link the chat opens on click (e.g. the full-size file). The renderer still checks it. */
|
|
48
|
+
readonly href?: string;
|
|
45
49
|
}
|
|
46
50
|
/** A tool result content block `media` may carry. Modeled on MCP's own content-block vocabulary —
|
|
47
51
|
* see this module's doc for why that vocabulary is reused rather than a fourth one invented. */
|
|
@@ -8,10 +8,11 @@ function isRecord(value) {
|
|
|
8
8
|
function asImageBlock(block) {
|
|
9
9
|
if (!isRecord(block) || block['type'] !== 'image')
|
|
10
10
|
return undefined;
|
|
11
|
-
const { mimeType, data } = block;
|
|
11
|
+
const { mimeType, data, title, href } = block;
|
|
12
12
|
if (typeof mimeType !== 'string' || typeof data !== 'string')
|
|
13
13
|
return undefined;
|
|
14
|
-
|
|
14
|
+
// Untrusted extras are kept only as strings, so a caption or link can never smuggle an object.
|
|
15
|
+
return { type: 'image', mimeType, data, ...(typeof title === 'string' ? { title } : {}), ...(typeof href === 'string' ? { href } : {}) };
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Splits a tool handler's raw return value into its recognized media blocks and the remainder,
|
|
@@ -74,6 +75,11 @@ export function resultContent({ result }) {
|
|
|
74
75
|
return 'Tool execution cancelled.';
|
|
75
76
|
case 'failed':
|
|
76
77
|
return result.error ?? 'Tool execution failed.';
|
|
78
|
+
default: {
|
|
79
|
+
// Unreachable: every tool result status has a case above, and a new one fails typecheck here.
|
|
80
|
+
const unhandled = result.status;
|
|
81
|
+
throw new TypeError(`Unhandled tool result status: ${String(unhandled)}`);
|
|
82
|
+
}
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
/** Projects a model-safe result into the saved event: pixels occur only in `media`.
|
|
@@ -81,9 +87,10 @@ export function resultContent({ result }) {
|
|
|
81
87
|
* @complexity O(n) output bytes, with O(n) transient serialization space. */
|
|
82
88
|
export function projectToolResultEvent({ result }, _options = {}) {
|
|
83
89
|
const { remainder, media } = extractResultMedia({ output: result.output });
|
|
90
|
+
const outputFlagsError = isRecord(result.output) && result.output.isError === true;
|
|
84
91
|
const isError = result.status !== 'completed'
|
|
85
92
|
|| (batchOutcomeFor({ output: result.output }) ?? 'completed') !== 'completed'
|
|
86
|
-
||
|
|
93
|
+
|| outputFlagsError;
|
|
87
94
|
return {
|
|
88
95
|
content: resultContent({ result: { ...result, output: remainder } }),
|
|
89
96
|
...(isError ? { isError: true } : {}),
|
|
@@ -52,6 +52,13 @@
|
|
|
52
52
|
* break the feature. Anything else absent from this list is still treated as human-only.
|
|
53
53
|
*/
|
|
54
54
|
export const MODEL_VISIBLE_BLOCK_TYPES = ['text', 'image'];
|
|
55
|
+
/** A record block whose string `type` is one the model may see. */
|
|
56
|
+
function isModelVisibleBlock(block) {
|
|
57
|
+
if (!isRecord(block))
|
|
58
|
+
return false;
|
|
59
|
+
const type = block['type'];
|
|
60
|
+
return typeof type === 'string' && MODEL_VISIBLE_BLOCK_TYPES.includes(type);
|
|
61
|
+
}
|
|
55
62
|
function isRecord(value) {
|
|
56
63
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
57
64
|
}
|
|
@@ -74,16 +81,10 @@ export function splitToolResultSurfaces({ output }) {
|
|
|
74
81
|
for (const block of content) {
|
|
75
82
|
// A non-record block carries no `type` to check, so it cannot be shown to be model-safe.
|
|
76
83
|
// Withheld rather than passed through, per this module's fail-closed rule.
|
|
77
|
-
if (
|
|
78
|
-
surfaces.push({ type: 'unknown', value: block });
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const type = block['type'];
|
|
82
|
-
if (typeof type === 'string' && MODEL_VISIBLE_BLOCK_TYPES.includes(type)) {
|
|
84
|
+
if (isModelVisibleBlock(block))
|
|
83
85
|
modelBlocks.push(block);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
surfaces.push(block);
|
|
86
|
+
else
|
|
87
|
+
surfaces.push(isRecord(block) ? block : { type: 'unknown', value: block });
|
|
87
88
|
}
|
|
88
89
|
if (surfaces.length === 0)
|
|
89
90
|
return { modelOutput: output, surfaces: [] };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/daemon",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
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": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"runtime": "node",
|
|
15
15
|
"entries": {
|
|
16
16
|
".": "node",
|
|
17
|
+
"./terminal": "node",
|
|
17
18
|
"./store/event-log/sqlite": "node",
|
|
18
19
|
"./store/agent-sessions": "universal",
|
|
19
20
|
"./store/agent-sessions/sqlite": "node",
|
|
@@ -34,6 +35,12 @@
|
|
|
34
35
|
"src/surface-exchanges.ts",
|
|
35
36
|
"src/scheduler.ts"
|
|
36
37
|
]
|
|
38
|
+
},
|
|
39
|
+
"optionalPeers": {
|
|
40
|
+
"node-pty": "opt-in: import @jini-ai/daemon/terminal — Interactive terminals could not load node-pty. Install node-pty to enable this feature, or check its installed version and native binaries.",
|
|
41
|
+
"better-sqlite3": "opt-in: sqlite storage — SQLite storage could not load better-sqlite3. Install better-sqlite3 to enable this feature, or check its installed version and native binaries.",
|
|
42
|
+
"@electric-sql/pglite": "opt-in: embedded postgresql storage — Embedded PostgreSQL storage could not load @electric-sql/pglite. Install @electric-sql/pglite to enable this feature, or check its installed version and native binaries.",
|
|
43
|
+
"pg": "opt-in: postgresql storage — PostgreSQL storage could not load pg. Install pg to enable this feature, or check its installed version and native binaries."
|
|
37
44
|
}
|
|
38
45
|
},
|
|
39
46
|
"type": "module",
|
|
@@ -46,6 +53,11 @@
|
|
|
46
53
|
"import": "./dist/index.js",
|
|
47
54
|
"default": "./dist/index.js"
|
|
48
55
|
},
|
|
56
|
+
"./terminal": {
|
|
57
|
+
"types": "./dist/terminal.adapter.d.ts",
|
|
58
|
+
"import": "./dist/terminal.adapter.js",
|
|
59
|
+
"default": "./dist/terminal.adapter.js"
|
|
60
|
+
},
|
|
49
61
|
"./store/event-log/sqlite": {
|
|
50
62
|
"types": "./dist/store/event-log/sqlite.d.ts",
|
|
51
63
|
"import": "./dist/store/event-log/sqlite.js",
|
|
@@ -129,6 +141,7 @@
|
|
|
129
141
|
"registry": "https://registry.npmjs.org"
|
|
130
142
|
},
|
|
131
143
|
"devDependencies": {
|
|
144
|
+
"smol-toml": "1.9.1",
|
|
132
145
|
"@vitest/coverage-v8": "^2.1.9",
|
|
133
146
|
"node-pty": "^1.1.0",
|
|
134
147
|
"better-sqlite3": "^13.0.0",
|
|
@@ -139,41 +152,35 @@
|
|
|
139
152
|
"@types/pg": "8.23.1",
|
|
140
153
|
"express": "^4.21.0",
|
|
141
154
|
"@types/express": "^4.17.21",
|
|
142
|
-
"@jini-ai/db": "0.6.
|
|
143
|
-
"@jini-ai/
|
|
144
|
-
"@jini-ai/
|
|
145
|
-
"@jini-ai/core": "^0.6.
|
|
146
|
-
"@jini-ai/
|
|
147
|
-
"@jini-ai/
|
|
148
|
-
"@jini-ai/
|
|
155
|
+
"@jini-ai/db": "0.6.16",
|
|
156
|
+
"@jini-ai/http-kit": "0.6.16",
|
|
157
|
+
"@jini-ai/agent-runtime": "^0.6.16",
|
|
158
|
+
"@jini-ai/core": "^0.6.16",
|
|
159
|
+
"@jini-ai/protocol": "^0.6.16",
|
|
160
|
+
"@jini-ai/chat": "0.6.16",
|
|
161
|
+
"@jini-ai/platform": "^0.6.16"
|
|
149
162
|
},
|
|
150
163
|
"dependencies": {
|
|
151
164
|
"smol-toml": "1.9.1",
|
|
152
|
-
"
|
|
153
|
-
"@jini-ai/
|
|
165
|
+
"kysely": "^0.29.6",
|
|
166
|
+
"@jini-ai/agent-runtime": "^0.6.16",
|
|
167
|
+
"@jini-ai/db": "^0.6.16",
|
|
168
|
+
"@jini-ai/core": "^0.6.16",
|
|
169
|
+
"@jini-ai/http-kit": "^0.6.16",
|
|
170
|
+
"@jini-ai/protocol": "^0.6.16",
|
|
171
|
+
"@jini-ai/platform": "^0.6.16"
|
|
154
172
|
},
|
|
155
173
|
"peerDependencies": {
|
|
156
174
|
"node-pty": "^1.1.0",
|
|
157
|
-
"@jini-ai/db": "^0.6.15-rc.2",
|
|
158
|
-
"kysely": "^0.29.6",
|
|
159
175
|
"better-sqlite3": "^13.0.0",
|
|
160
176
|
"@electric-sql/pglite": "0.5.8",
|
|
161
177
|
"pg": "^8.23.0",
|
|
162
|
-
"
|
|
163
|
-
"express": "^4.21.0 || ^5.0.0",
|
|
164
|
-
"@jini-ai/agent-runtime": "^0.6.15-rc.2",
|
|
165
|
-
"@jini-ai/platform": "^0.6.15-rc.2"
|
|
178
|
+
"express": "^4.21.0 || ^5.0.0"
|
|
166
179
|
},
|
|
167
180
|
"peerDependenciesMeta": {
|
|
168
181
|
"node-pty": {
|
|
169
182
|
"optional": true
|
|
170
183
|
},
|
|
171
|
-
"@jini-ai/db": {
|
|
172
|
-
"optional": true
|
|
173
|
-
},
|
|
174
|
-
"kysely": {
|
|
175
|
-
"optional": true
|
|
176
|
-
},
|
|
177
184
|
"better-sqlite3": {
|
|
178
185
|
"optional": true
|
|
179
186
|
},
|
|
@@ -182,24 +189,13 @@
|
|
|
182
189
|
},
|
|
183
190
|
"pg": {
|
|
184
191
|
"optional": true
|
|
185
|
-
},
|
|
186
|
-
"@jini-ai/http-kit": {
|
|
187
|
-
"optional": true
|
|
188
|
-
},
|
|
189
|
-
"express": {
|
|
190
|
-
"optional": true
|
|
191
|
-
},
|
|
192
|
-
"@jini-ai/agent-runtime": {
|
|
193
|
-
"optional": true
|
|
194
|
-
},
|
|
195
|
-
"@jini-ai/platform": {
|
|
196
|
-
"optional": true
|
|
197
192
|
}
|
|
198
193
|
},
|
|
199
194
|
"scripts": {
|
|
200
195
|
"build": "tsc -p tsconfig.json",
|
|
201
196
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
202
197
|
"test": "vitest run",
|
|
198
|
+
"test:live:claude-bash": "vitest run --config vitest.claude-bash.live.config.ts",
|
|
203
199
|
"test:coverage": "vitest run --coverage",
|
|
204
200
|
"test:postgres": "vitest run --config vitest.postgres.config.ts src/store/agent-sessions/__tests__/postgres.postgres.test.ts"
|
|
205
201
|
}
|