@namzu/sdk 57.1.0 → 58.1.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 +72 -0
- package/dist/agents/QueryAgent.d.ts.map +1 -1
- package/dist/agents/QueryAgent.js +2 -0
- package/dist/agents/QueryAgent.js.map +1 -1
- package/dist/agents/file-definitions.d.ts +35 -4
- package/dist/agents/file-definitions.d.ts.map +1 -1
- package/dist/agents/file-definitions.js +98 -8
- package/dist/agents/file-definitions.js.map +1 -1
- package/dist/authorization/protected-paths.d.ts +9 -0
- package/dist/authorization/protected-paths.d.ts.map +1 -1
- package/dist/authorization/protected-paths.js +29 -3
- package/dist/authorization/protected-paths.js.map +1 -1
- package/dist/compaction/context-window.d.ts +1 -1
- package/dist/compaction/context-window.d.ts.map +1 -1
- package/dist/compaction/context-window.js +8 -1
- package/dist/compaction/context-window.js.map +1 -1
- package/dist/compaction/plan.d.ts.map +1 -1
- package/dist/compaction/plan.js +2 -2
- package/dist/compaction/plan.js.map +1 -1
- package/dist/config/runtime.d.ts +10 -0
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +2 -0
- package/dist/config/runtime.js.map +1 -1
- package/dist/connector/mcp/client.d.ts +8 -0
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +75 -2
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/constants/mcp/index.d.ts +2 -0
- package/dist/constants/mcp/index.d.ts.map +1 -1
- package/dist/constants/mcp/index.js +2 -0
- package/dist/constants/mcp/index.js.map +1 -1
- package/dist/constants/plugin/index.d.ts +2 -0
- package/dist/constants/plugin/index.d.ts.map +1 -1
- package/dist/constants/plugin/index.js +2 -0
- package/dist/constants/plugin/index.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +1 -1
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +25 -4
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/session/turn-recorder.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.js +2 -1
- package/dist/manager/session/turn-recorder.js.map +1 -1
- package/dist/persona/assembler.d.ts.map +1 -1
- package/dist/persona/assembler.js +2 -2
- package/dist/persona/assembler.js.map +1 -1
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/lifecycle.d.ts +8 -1
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +9 -2
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/shell-hook-http.d.ts +39 -0
- package/dist/plugin/shell-hook-http.d.ts.map +1 -0
- package/dist/plugin/shell-hook-http.js +163 -0
- package/dist/plugin/shell-hook-http.js.map +1 -0
- package/dist/plugin/shell-hook.d.ts +93 -11
- package/dist/plugin/shell-hook.d.ts.map +1 -1
- package/dist/plugin/shell-hook.js +223 -39
- package/dist/plugin/shell-hook.js.map +1 -1
- package/dist/public-runtime.d.ts +2 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +2 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +1 -0
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +2 -0
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +1 -1
- package/dist/public-types.d.ts.map +1 -1
- package/dist/runtime/query/executor.d.ts +1 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +34 -9
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +2 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +25 -1
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +47 -10
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts +18 -8
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-breaker.js +33 -9
- package/dist/runtime/query/iteration/phases/compaction-breaker.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +7 -5
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +70 -3
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/path-escalation.d.ts +2 -0
- package/dist/runtime/query/path-escalation.d.ts.map +1 -1
- package/dist/runtime/query/path-escalation.js +7 -4
- package/dist/runtime/query/path-escalation.js.map +1 -1
- package/dist/runtime/query/plugin-hooks.js +2 -2
- package/dist/runtime/query/plugin-hooks.js.map +1 -1
- package/dist/runtime/query/prepare-turn.d.ts +2 -0
- package/dist/runtime/query/prepare-turn.d.ts.map +1 -1
- package/dist/runtime/query/prepare-turn.js +25 -0
- package/dist/runtime/query/prepare-turn.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +3 -2
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +32 -13
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/session/retention/archive.js +1 -1
- package/dist/session/retention/archive.js.map +1 -1
- package/dist/session/workspace/driver.d.ts +6 -0
- package/dist/session/workspace/driver.d.ts.map +1 -1
- package/dist/session/workspace/git-worktree.d.ts.map +1 -1
- package/dist/session/workspace/git-worktree.js +28 -0
- package/dist/session/workspace/git-worktree.js.map +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/loader.d.ts +7 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +53 -0
- package/dist/skills/loader.js.map +1 -1
- package/dist/skills/registry.d.ts +1 -1
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +2 -1
- package/dist/skills/registry.js.map +1 -1
- package/dist/tools/builtins/bash-cwd.d.ts +52 -0
- package/dist/tools/builtins/bash-cwd.d.ts.map +1 -0
- package/dist/tools/builtins/bash-cwd.js +127 -0
- package/dist/tools/builtins/bash-cwd.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +41 -6
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/bounded-file-read.d.ts +10 -0
- package/dist/tools/builtins/bounded-file-read.d.ts.map +1 -0
- package/dist/tools/builtins/bounded-file-read.js +67 -0
- package/dist/tools/builtins/bounded-file-read.js.map +1 -0
- package/dist/tools/builtins/grep.d.ts +6 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +187 -24
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts +1 -0
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +113 -28
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/read-media.d.ts +68 -0
- package/dist/tools/builtins/read-media.d.ts.map +1 -0
- package/dist/tools/builtins/read-media.js +397 -0
- package/dist/tools/builtins/read-media.js.map +1 -0
- package/dist/tools/builtins/search-tools.js +1 -1
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/builtins/skill.d.ts +4 -2
- package/dist/tools/builtins/skill.d.ts.map +1 -1
- package/dist/tools/builtins/skill.js +61 -2
- package/dist/tools/builtins/skill.js.map +1 -1
- package/dist/tools/builtins/sleep-guard.d.ts +15 -0
- package/dist/tools/builtins/sleep-guard.d.ts.map +1 -0
- package/dist/tools/builtins/sleep-guard.js +33 -0
- package/dist/tools/builtins/sleep-guard.js.map +1 -0
- package/dist/tools/builtins/view-image.d.ts +23 -1
- package/dist/tools/builtins/view-image.d.ts.map +1 -1
- package/dist/tools/builtins/view-image.js +66 -58
- package/dist/tools/builtins/view-image.js.map +1 -1
- package/dist/tools/file-read-tracker.d.ts.map +1 -1
- package/dist/tools/file-read-tracker.js +31 -0
- package/dist/tools/file-read-tracker.js.map +1 -1
- package/dist/toolsets/manager.js +3 -3
- package/dist/toolsets/manager.js.map +1 -1
- package/dist/types/agent/query.d.ts +2 -0
- package/dist/types/agent/query.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +6 -2
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/connector/mcp.d.ts +46 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/hitl/index.d.ts +1 -1
- package/dist/types/plugin/index.d.ts +72 -5
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +12 -1
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/session/sub-session.d.ts +6 -2
- package/dist/types/session/sub-session.d.ts.map +1 -1
- package/dist/types/skills/index.d.ts +36 -0
- package/dist/types/skills/index.d.ts.map +1 -1
- package/dist/types/skills/index.js +9 -0
- package/dist/types/skills/index.js.map +1 -1
- package/dist/types/tool/index.d.ts +22 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/workspace/ref.d.ts +2 -0
- package/dist/types/workspace/ref.d.ts.map +1 -1
- package/dist/utils/frontmatter.d.ts +12 -0
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +6 -0
- package/dist/utils/frontmatter.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/QueryAgent.ts +2 -0
- package/src/agents/file-definitions.ts +126 -6
- package/src/authorization/protected-paths.ts +30 -2
- package/src/compaction/context-window.ts +10 -0
- package/src/compaction/plan.ts +12 -2
- package/src/config/runtime.ts +2 -0
- package/src/connector/mcp/client.ts +87 -1
- package/src/constants/mcp/index.ts +3 -0
- package/src/constants/plugin/index.ts +2 -0
- package/src/manager/agent/lifecycle.ts +24 -5
- package/src/manager/session/turn-recorder.ts +2 -1
- package/src/persona/assembler.ts +2 -2
- package/src/plugin/index.ts +5 -0
- package/src/plugin/lifecycle.ts +16 -2
- package/src/plugin/shell-hook-http.ts +181 -0
- package/src/plugin/shell-hook.ts +386 -89
- package/src/public-runtime.ts +2 -0
- package/src/public-tools.ts +2 -0
- package/src/public-types.ts +5 -0
- package/src/runtime/query/executor.ts +40 -10
- package/src/runtime/query/index.ts +33 -0
- package/src/runtime/query/iteration/index.ts +51 -11
- package/src/runtime/query/iteration/phases/compaction-breaker.ts +38 -9
- package/src/runtime/query/iteration/phases/compaction.ts +27 -5
- package/src/runtime/query/iteration/phases/context.ts +2 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +74 -3
- package/src/runtime/query/path-escalation.ts +11 -5
- package/src/runtime/query/plugin-hooks.ts +2 -2
- package/src/runtime/query/prepare-turn.ts +33 -0
- package/src/runtime/query/review-policy.ts +45 -16
- package/src/session/retention/archive.ts +1 -1
- package/src/session/workspace/driver.ts +6 -0
- package/src/session/workspace/git-worktree.ts +31 -0
- package/src/skills/index.ts +6 -1
- package/src/skills/loader.ts +54 -0
- package/src/skills/registry.ts +7 -6
- package/src/tools/builtins/bash-cwd.ts +156 -0
- package/src/tools/builtins/bash.ts +79 -34
- package/src/tools/builtins/bounded-file-read.ts +80 -0
- package/src/tools/builtins/grep.ts +198 -28
- package/src/tools/builtins/read-file.ts +151 -30
- package/src/tools/builtins/read-media.ts +483 -0
- package/src/tools/builtins/search-tools.ts +1 -1
- package/src/tools/builtins/skill.ts +91 -2
- package/src/tools/builtins/sleep-guard.ts +31 -0
- package/src/tools/builtins/view-image.ts +74 -62
- package/src/tools/file-read-tracker.ts +30 -0
- package/src/toolsets/manager.ts +3 -3
- package/src/types/agent/query.ts +2 -0
- package/src/types/agent/task.ts +6 -2
- package/src/types/connector/mcp.ts +48 -0
- package/src/types/hitl/index.ts +1 -1
- package/src/types/plugin/index.ts +102 -16
- package/src/types/session/sub-session.ts +6 -2
- package/src/types/skills/index.ts +48 -0
- package/src/types/tool/index.ts +22 -0
- package/src/types/workspace/ref.ts +2 -0
- package/src/utils/frontmatter.ts +21 -0
|
@@ -3,14 +3,14 @@ import { open } from 'node:fs/promises'
|
|
|
3
3
|
import { inflateSync } from 'node:zlib'
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { admitMcpImageBatch } from '../../connector/mcp/image-admission.js'
|
|
6
|
-
import type { ToolContext, ToolDefinition } from '../../types/tool/index.js'
|
|
6
|
+
import type { ToolContext, ToolDefinition, ToolResult } from '../../types/tool/index.js'
|
|
7
7
|
import { defineTool } from '../defineTool.js'
|
|
8
8
|
import { resolveWithinAnyReal, toolRoots } from '../paths.js'
|
|
9
9
|
import { STANDARD_SCREENSHOT_LIMITS, fitPng, screenshotTargetSize } from './computer-use-image.js'
|
|
10
10
|
|
|
11
11
|
// 16 MiB becomes less than the runtime's 24 MiB encoded rich-content budget.
|
|
12
12
|
// Admission is per artifact; the runtime still budgets accumulated images.
|
|
13
|
-
const MAX_BYTES = 16 * 1024 * 1024
|
|
13
|
+
export const MAX_BYTES = 16 * 1024 * 1024
|
|
14
14
|
const READ_CHUNK_BYTES = 1024 * 1024
|
|
15
15
|
const MAX_EDGE = 16_384
|
|
16
16
|
const MAX_PIXELS = 16_000_000
|
|
@@ -55,7 +55,7 @@ async function readBounded(
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
async function readArtifact(
|
|
58
|
+
export async function readArtifact(
|
|
59
59
|
path: string,
|
|
60
60
|
context: ToolContext,
|
|
61
61
|
): Promise<{ path: string; bytes: Buffer; sandboxed: boolean }> {
|
|
@@ -168,7 +168,7 @@ function webpDimensions(bytes: Buffer): Pick<Raster, 'width' | 'height'> {
|
|
|
168
168
|
return dimensions ?? malformed()
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
function describeRaster(bytes: Buffer): Raster {
|
|
171
|
+
export function describeRaster(bytes: Buffer): Raster {
|
|
172
172
|
let raster: Raster
|
|
173
173
|
if (bytes.subarray(0, 8).equals(PNG_SIGNATURE)) {
|
|
174
174
|
if (bytes.length < 33) malformed()
|
|
@@ -313,6 +313,75 @@ async function validatedPng(bytes: Buffer, raster: Raster): Promise<Buffer> {
|
|
|
313
313
|
return canonical
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Validate and fit the bytes of a saved image and shape them as a tool result
|
|
318
|
+
* carrying the pixels. `view_image` and an image `read` share this, so both
|
|
319
|
+
* give the model the same checked picture and the same source dimensions.
|
|
320
|
+
*/
|
|
321
|
+
export async function inspectImageBytes(
|
|
322
|
+
artifact: { readonly path: string; readonly bytes: Buffer; readonly sandboxed: boolean },
|
|
323
|
+
signal: AbortSignal,
|
|
324
|
+
): Promise<ToolResult> {
|
|
325
|
+
const source = describeRaster(artifact.bytes)
|
|
326
|
+
if (
|
|
327
|
+
!admitMcpImageBatch([
|
|
328
|
+
{
|
|
329
|
+
type: 'image',
|
|
330
|
+
mimeType: source.mediaType,
|
|
331
|
+
data: artifact.bytes.toString('base64'),
|
|
332
|
+
},
|
|
333
|
+
])
|
|
334
|
+
)
|
|
335
|
+
malformed()
|
|
336
|
+
signal.throwIfAborted()
|
|
337
|
+
let image = {
|
|
338
|
+
data: artifact.bytes,
|
|
339
|
+
width: source.width,
|
|
340
|
+
height: source.height,
|
|
341
|
+
}
|
|
342
|
+
if (source.mediaType === 'image/png') {
|
|
343
|
+
const png = await validatedPng(artifact.bytes, source)
|
|
344
|
+
image = await fitPng(png, STANDARD_SCREENSHOT_LIMITS)
|
|
345
|
+
} else {
|
|
346
|
+
const target = screenshotTargetSize(source.width, source.height)
|
|
347
|
+
if (target.width !== source.width || target.height !== source.height)
|
|
348
|
+
throw new Error(
|
|
349
|
+
`This ${source.mediaType} image needs resizing. JPEG/WebP decoding and resizing are unavailable here; export a PNG (or a smaller JPEG/WebP) and inspect that file.`,
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
signal.throwIfAborted()
|
|
353
|
+
const validation = source.mediaType === 'image/png' ? 'decoded' : 'container'
|
|
354
|
+
const output = `Image artifact: ${artifact.path} (${source.width}x${source.height}, ${source.mediaType}); shown at ${image.width}x${image.height}.`
|
|
355
|
+
return {
|
|
356
|
+
success: true,
|
|
357
|
+
output,
|
|
358
|
+
content: [
|
|
359
|
+
{
|
|
360
|
+
type: 'text',
|
|
361
|
+
text: `${output}\n${validation === 'container' ? 'The complete container and dimensions were validated; compressed JPEG/WebP pixels were not decoded by this tool. ' : ''}Inspect these pixels for visual evidence. This saved artifact is not a current computer_use screenshot; capture the application before GUI input.`,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
type: 'image',
|
|
365
|
+
mediaType: source.mediaType,
|
|
366
|
+
data: image.data.toString('base64'),
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
data: {
|
|
370
|
+
path: artifact.path,
|
|
371
|
+
sandboxed: artifact.sandboxed,
|
|
372
|
+
artifact: true,
|
|
373
|
+
mediaType: source.mediaType,
|
|
374
|
+
sourceWidth: source.width,
|
|
375
|
+
sourceHeight: source.height,
|
|
376
|
+
width: image.width,
|
|
377
|
+
height: image.height,
|
|
378
|
+
sourceBytes: artifact.bytes.length,
|
|
379
|
+
sha256: createHash('sha256').update(artifact.bytes).digest('hex'),
|
|
380
|
+
validation,
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
316
385
|
/**
|
|
317
386
|
* Inspect an artifact without granting screen-coordinate authority. An image
|
|
318
387
|
* file can be a reference, render or export; it is never a computer_use frame.
|
|
@@ -343,64 +412,7 @@ export function createViewImageTool(
|
|
|
343
412
|
return { success: false, output: message, error: message }
|
|
344
413
|
}
|
|
345
414
|
const artifact = await readArtifact(input.path, context)
|
|
346
|
-
|
|
347
|
-
if (
|
|
348
|
-
!admitMcpImageBatch([
|
|
349
|
-
{
|
|
350
|
-
type: 'image',
|
|
351
|
-
mimeType: source.mediaType,
|
|
352
|
-
data: artifact.bytes.toString('base64'),
|
|
353
|
-
},
|
|
354
|
-
])
|
|
355
|
-
)
|
|
356
|
-
malformed()
|
|
357
|
-
context.abortSignal.throwIfAborted()
|
|
358
|
-
let image = {
|
|
359
|
-
data: artifact.bytes,
|
|
360
|
-
width: source.width,
|
|
361
|
-
height: source.height,
|
|
362
|
-
}
|
|
363
|
-
if (source.mediaType === 'image/png') {
|
|
364
|
-
const png = await validatedPng(artifact.bytes, source)
|
|
365
|
-
image = await fitPng(png, STANDARD_SCREENSHOT_LIMITS)
|
|
366
|
-
} else {
|
|
367
|
-
const target = screenshotTargetSize(source.width, source.height)
|
|
368
|
-
if (target.width !== source.width || target.height !== source.height)
|
|
369
|
-
throw new Error(
|
|
370
|
-
`This ${source.mediaType} image needs resizing. JPEG/WebP decoding and resizing are unavailable here; export a PNG (or a smaller JPEG/WebP) and inspect that file.`,
|
|
371
|
-
)
|
|
372
|
-
}
|
|
373
|
-
context.abortSignal.throwIfAborted()
|
|
374
|
-
const validation = source.mediaType === 'image/png' ? 'decoded' : 'container'
|
|
375
|
-
const output = `Image artifact: ${artifact.path} (${source.width}x${source.height}, ${source.mediaType}); shown at ${image.width}x${image.height}.`
|
|
376
|
-
return {
|
|
377
|
-
success: true,
|
|
378
|
-
output,
|
|
379
|
-
content: [
|
|
380
|
-
{
|
|
381
|
-
type: 'text',
|
|
382
|
-
text: `${output}\n${validation === 'container' ? 'The complete container and dimensions were validated; compressed JPEG/WebP pixels were not decoded by this tool. ' : ''}Inspect these pixels for visual evidence. This saved artifact is not a current computer_use screenshot; capture the application before GUI input.`,
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
type: 'image',
|
|
386
|
-
mediaType: source.mediaType,
|
|
387
|
-
data: image.data.toString('base64'),
|
|
388
|
-
},
|
|
389
|
-
],
|
|
390
|
-
data: {
|
|
391
|
-
path: artifact.path,
|
|
392
|
-
sandboxed: artifact.sandboxed,
|
|
393
|
-
artifact: true,
|
|
394
|
-
mediaType: source.mediaType,
|
|
395
|
-
sourceWidth: source.width,
|
|
396
|
-
sourceHeight: source.height,
|
|
397
|
-
width: image.width,
|
|
398
|
-
height: image.height,
|
|
399
|
-
sourceBytes: artifact.bytes.length,
|
|
400
|
-
sha256: createHash('sha256').update(artifact.bytes).digest('hex'),
|
|
401
|
-
validation,
|
|
402
|
-
},
|
|
403
|
-
}
|
|
415
|
+
return inspectImageBytes(artifact, context.abortSignal)
|
|
404
416
|
},
|
|
405
417
|
})
|
|
406
418
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { FileReadTracker, ReadWindowEntry } from '../types/tool/index.js'
|
|
2
2
|
import { fingerprintContent } from './builtins/content-fingerprint.js'
|
|
3
3
|
|
|
4
|
+
/** A body larger than this is not kept; the file's change is still seen by fingerprint. */
|
|
5
|
+
const MAX_BODY_CHARS = 512 * 1024
|
|
6
|
+
const MAX_BODIES = 128
|
|
7
|
+
|
|
4
8
|
/** Host-owned observation ledger. Share only across turns of the same conversation and filesystem. */
|
|
5
9
|
export function createFileReadTracker(): FileReadTracker {
|
|
6
10
|
const paths = new Set<string>()
|
|
@@ -27,6 +31,21 @@ export function createFileReadTracker(): FileReadTracker {
|
|
|
27
31
|
// `editChain` or `readWitness` answers; it says only that what this ledger
|
|
28
32
|
// holds for the path is known to be behind the disk.
|
|
29
33
|
const drifted = new Set<string>()
|
|
34
|
+
// The body of each file whose last observation was the whole file, newest
|
|
35
|
+
// last, so a host can show what changed under it. Bounded: a file larger
|
|
36
|
+
// than the cap keeps no body (its change is still detectable by
|
|
37
|
+
// fingerprint), and the oldest bodies go first.
|
|
38
|
+
const bodies = new Map<string, string>()
|
|
39
|
+
function keepBody(key: string, content: string | undefined): void {
|
|
40
|
+
bodies.delete(key)
|
|
41
|
+
if (content === undefined || content.length > MAX_BODY_CHARS) return
|
|
42
|
+
bodies.set(key, content)
|
|
43
|
+
while (bodies.size > MAX_BODIES) {
|
|
44
|
+
const oldest = bodies.keys().next().value
|
|
45
|
+
if (oldest === undefined) break
|
|
46
|
+
bodies.delete(oldest)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
// One observation, whatever witness the caller goes on to record against it.
|
|
31
50
|
// A shared function rather than `this.recordRead`, so a destructured method
|
|
32
51
|
// keeps working.
|
|
@@ -41,6 +60,9 @@ export function createFileReadTracker(): FileReadTracker {
|
|
|
41
60
|
}
|
|
42
61
|
if (next !== undefined) fingerprints.set(key, next)
|
|
43
62
|
else fingerprints.delete(key)
|
|
63
|
+
// A write supplies the whole body; any other observation without a
|
|
64
|
+
// witness may be a window of the file, which proves nothing about the rest.
|
|
65
|
+
keepBody(key, fullWriteCallId ? content : undefined)
|
|
44
66
|
if (next !== undefined && fullWriteCallId) {
|
|
45
67
|
writes.set(key, fullWriteCallId)
|
|
46
68
|
// A full body arrived whole in one call, so the chain is empty
|
|
@@ -76,12 +98,19 @@ export function createFileReadTracker(): FileReadTracker {
|
|
|
76
98
|
recordRead: observe,
|
|
77
99
|
recordFullRead(key, content, callId, renderedFingerprint) {
|
|
78
100
|
observe(key, content)
|
|
101
|
+
keepBody(key, content)
|
|
79
102
|
// A surviving write witness outranks this one: it names a body the
|
|
80
103
|
// model composed itself, and the chain machinery can replay onto it.
|
|
81
104
|
// This is the same observation either way — only the witness differs.
|
|
82
105
|
if (!writes.has(key)) reads.set(key, { callId, renderedFingerprint })
|
|
83
106
|
},
|
|
84
107
|
readWitness: (key) => reads.get(key),
|
|
108
|
+
fullBody: (key) => bodies.get(key),
|
|
109
|
+
fullBodyPaths: () => [...bodies.keys()],
|
|
110
|
+
recordFullBody(key, content) {
|
|
111
|
+
observe(key, content)
|
|
112
|
+
keepBody(key, content)
|
|
113
|
+
},
|
|
85
114
|
recordEdit(key, content, callId) {
|
|
86
115
|
// Both conditions are about the PRE-image, not this edit. A chain
|
|
87
116
|
// replays only if the content this edit ran against is itself
|
|
@@ -97,6 +126,7 @@ export function createFileReadTracker(): FileReadTracker {
|
|
|
97
126
|
// no chain can be rooted at a rendering to carry it forward.
|
|
98
127
|
reads.delete(key)
|
|
99
128
|
fingerprints.set(key, fingerprintContent(content))
|
|
129
|
+
keepBody(key, content)
|
|
100
130
|
if (!chained) {
|
|
101
131
|
writes.delete(key)
|
|
102
132
|
chains.delete(key)
|
package/src/toolsets/manager.ts
CHANGED
|
@@ -547,7 +547,7 @@ export class ToolManager {
|
|
|
547
547
|
|
|
548
548
|
const parts: string[] = []
|
|
549
549
|
const contractNote = `<tool_runtime_contract>
|
|
550
|
-
Executable tool names, descriptions, and JSON input schemas are attached through the runtime tools parameter. Treat that runtime schema as authoritative
|
|
550
|
+
Executable tool names, descriptions, and JSON input schemas are attached through the runtime tools parameter. Treat that runtime schema as authoritative. This catalogue is a snapshot for discovery, not live availability status: a tool listed under deferred_tools may already be loaded through history. If its schema is visible in the current runtime tools parameter, call it directly without searching again.
|
|
551
551
|
</tool_runtime_contract>`
|
|
552
552
|
|
|
553
553
|
if (active.length > 0) {
|
|
@@ -571,8 +571,8 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
571
571
|
this.has('search_tools') &&
|
|
572
572
|
this.availability('search_tools') === 'active' &&
|
|
573
573
|
(!names || names.includes('search_tools'))
|
|
574
|
-
? '
|
|
575
|
-
: '
|
|
574
|
+
? "Only when a needed deferred tool's schema is absent from the current runtime tools parameter, use search_tools with its exact name to load it:"
|
|
575
|
+
: 'For a needed deferred tool whose schema is absent, wait for runtime activation before calling it:'
|
|
576
576
|
parts.push(`<deferred_tools>\n${deferredIntro}\n${entries}\n</deferred_tools>`)
|
|
577
577
|
}
|
|
578
578
|
|
package/src/types/agent/query.ts
CHANGED
|
@@ -18,6 +18,8 @@ import type { WorkingMemoryProvider } from './working-memory.js'
|
|
|
18
18
|
|
|
19
19
|
export interface QueryAgentConfig extends BaseAgentConfig {
|
|
20
20
|
systemPrompt?: string
|
|
21
|
+
/** Host lifecycle hooks; forwarded unchanged to the child query. */
|
|
22
|
+
pluginManager?: QueryParams['pluginManager']
|
|
21
23
|
/** Provider-hosted search for this turn; the selected driver must support it. */
|
|
22
24
|
webSearch?: { mode: 'live' | 'cached' }
|
|
23
25
|
|
package/src/types/agent/task.ts
CHANGED
|
@@ -28,8 +28,12 @@ export type ChildWorkspaceRequest =
|
|
|
28
28
|
readonly baseRef?: string
|
|
29
29
|
/** Relative directory within the checkout where this child starts. */
|
|
30
30
|
readonly subdirectory?: string
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The existing SDK behavior is `dispose`; `retain` always keeps the
|
|
33
|
+
* checkout; `retain-changed` removes it when the child ended with no
|
|
34
|
+
* uncommitted changes and no new commits, and keeps it otherwise.
|
|
35
|
+
*/
|
|
36
|
+
readonly retention?: 'dispose' | 'retain' | 'retain-changed'
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export function isTerminalAgentTaskState(state: AgentTaskState): boolean {
|
|
@@ -410,6 +410,12 @@ export interface MCPPromptMessage {
|
|
|
410
410
|
export interface MCPClientCapabilities {
|
|
411
411
|
roots?: { listChanged?: boolean }
|
|
412
412
|
sampling?: Record<string, never>
|
|
413
|
+
/**
|
|
414
|
+
* Declared on a legacy-era `initialize` when the client was built with
|
|
415
|
+
* {@link MCPClientConfig.onElicitation}; an empty object means form mode
|
|
416
|
+
* only. The client sets it, a caller passing it by hand gets no handler.
|
|
417
|
+
*/
|
|
418
|
+
elicitation?: Record<string, never>
|
|
413
419
|
experimental?: Record<string, unknown>
|
|
414
420
|
}
|
|
415
421
|
|
|
@@ -451,6 +457,34 @@ export interface MCPInitializeResult {
|
|
|
451
457
|
instructions?: string
|
|
452
458
|
}
|
|
453
459
|
|
|
460
|
+
/**
|
|
461
|
+
* A server's request for structured input from the person, form mode.
|
|
462
|
+
*
|
|
463
|
+
* `requestedSchema` is the server's flat object schema, kept as received:
|
|
464
|
+
* the host decides which property shapes it can show.
|
|
465
|
+
*/
|
|
466
|
+
export interface MCPElicitationRequest {
|
|
467
|
+
readonly serverName: string
|
|
468
|
+
readonly message: string
|
|
469
|
+
readonly requestedSchema: {
|
|
470
|
+
readonly type?: 'object'
|
|
471
|
+
readonly properties?: Readonly<Record<string, unknown>>
|
|
472
|
+
readonly required?: readonly string[]
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* What the person did: `accept` carries the form values, `decline` is an
|
|
478
|
+
* explicit no, `cancel` is a dismissal (closed without choosing).
|
|
479
|
+
*/
|
|
480
|
+
export type MCPElicitationResult =
|
|
481
|
+
| {
|
|
482
|
+
readonly action: 'accept'
|
|
483
|
+
readonly content: Readonly<Record<string, string | number | boolean | readonly string[]>>
|
|
484
|
+
}
|
|
485
|
+
| { readonly action: 'decline' }
|
|
486
|
+
| { readonly action: 'cancel' }
|
|
487
|
+
|
|
454
488
|
export type MCPConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error'
|
|
455
489
|
|
|
456
490
|
export interface MCPClientConfig {
|
|
@@ -466,6 +500,20 @@ export interface MCPClientConfig {
|
|
|
466
500
|
transportFactory?: () => MCPTransport
|
|
467
501
|
capabilities?: MCPClientCapabilities
|
|
468
502
|
clientInfo?: { name: string; version: string }
|
|
503
|
+
/**
|
|
504
|
+
* Answer a server's `elicitation/create` (form mode) by asking the person.
|
|
505
|
+
*
|
|
506
|
+
* Setting it makes the client declare the `elicitation` capability on a
|
|
507
|
+
* legacy-era handshake. Left out, nothing is declared and a server's
|
|
508
|
+
* elicitation request is refused as an unknown method, exactly as before.
|
|
509
|
+
* `signal` fires when the server withdraws the request or the connection
|
|
510
|
+
* ends; a handler that throws answers `cancel`. URL-mode requests are
|
|
511
|
+
* never passed here: they are refused as invalid params.
|
|
512
|
+
*/
|
|
513
|
+
onElicitation?: (
|
|
514
|
+
request: MCPElicitationRequest,
|
|
515
|
+
context: { readonly signal: AbortSignal },
|
|
516
|
+
) => Promise<MCPElicitationResult>
|
|
469
517
|
/**
|
|
470
518
|
* Deadline for a single JSON-RPC round trip. Defaults to
|
|
471
519
|
* `DEFAULT_MCP_REQUEST_TIMEOUT_MS`.
|
package/src/types/hitl/index.ts
CHANGED
|
@@ -249,7 +249,7 @@ export interface ToolCallSummary {
|
|
|
249
249
|
explicitReview?: true
|
|
250
250
|
/**
|
|
251
251
|
* A rule written to ask a person (a `review` rule), or a hook that asked
|
|
252
|
-
* for one, requested this review.
|
|
252
|
+
* for one, requested this review. Like {@link explicitReview}, it is not
|
|
253
253
|
* set when an `allow` rule was demoted to review because the call reaches
|
|
254
254
|
* past its boundary. `bypass` and `classify` keep this question for a
|
|
255
255
|
* person; they answer the demoted kind themselves.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import {
|
|
3
|
+
MAX_AGENT_DIRS_PER_PLUGIN,
|
|
4
|
+
MAX_COMMAND_DIRS_PER_PLUGIN,
|
|
3
5
|
MAX_CONNECTORS_PER_PLUGIN,
|
|
4
6
|
MAX_HOOKS_PER_PLUGIN,
|
|
5
7
|
MAX_MCP_SERVERS_PER_PLUGIN,
|
|
@@ -100,10 +102,27 @@ export type PluginHookEvent =
|
|
|
100
102
|
/** A compaction pass is about to run / has run. Carries `compaction`. */
|
|
101
103
|
| 'pre_compact'
|
|
102
104
|
| 'post_compact'
|
|
103
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* A child session is starting, before its first prompt. Carries `parentSessionId`,
|
|
107
|
+
* `parentTurnId` and `agentType`. A hook may `annotate` to add context to the
|
|
108
|
+
* child's turn.
|
|
109
|
+
*/
|
|
110
|
+
| 'subagent_start'
|
|
111
|
+
/** A child session's turn ended. Fired after its own `turn_end`; carries `parentSessionId`, `parentTurnId` and `agentType`. */
|
|
104
112
|
| 'subagent_stop'
|
|
113
|
+
/**
|
|
114
|
+
* A child session's turn is starting. Fired right after its own
|
|
115
|
+
* `turn_start`; carries `parentSessionId` and `parentTurnId`. Observational.
|
|
116
|
+
*/
|
|
117
|
+
| 'subagent_start'
|
|
105
118
|
| 'turn_start'
|
|
106
119
|
| 'turn_end'
|
|
120
|
+
/**
|
|
121
|
+
* A turn ended because the model call or the turn itself failed, not because
|
|
122
|
+
* the model finished. Carries `error` (the message). Observational: the turn
|
|
123
|
+
* has already failed.
|
|
124
|
+
*/
|
|
125
|
+
| 'turn_failure'
|
|
107
126
|
| 'turn_interrupt'
|
|
108
127
|
| 'pre_tool_use'
|
|
109
128
|
| 'post_tool_use'
|
|
@@ -113,6 +132,19 @@ export type PluginHookEvent =
|
|
|
113
132
|
* and `toolResult`.
|
|
114
133
|
*/
|
|
115
134
|
| 'post_tool_use_failure'
|
|
135
|
+
/**
|
|
136
|
+
* Every tool call of one model step has settled, before the next model
|
|
137
|
+
* request. Fired once per step; carries `toolCalls`. `post_tool_use` fires
|
|
138
|
+
* per call and calls may run side by side, so this is the place to look at
|
|
139
|
+
* the step as a whole. `continue` may carry `halt`.
|
|
140
|
+
*/
|
|
141
|
+
| 'post_tool_batch'
|
|
142
|
+
/**
|
|
143
|
+
* A tool call was refused without a person saying No: by a rule, the
|
|
144
|
+
* policy of the current mode, a classifier, or a hook. Carries `toolName`,
|
|
145
|
+
* `toolInput` and `reason`. Observational.
|
|
146
|
+
*/
|
|
147
|
+
| 'permission_denied'
|
|
116
148
|
/**
|
|
117
149
|
* A person is about to be asked whether a tool call may run. Carries
|
|
118
150
|
* `toolName` and `toolInput`. A hook may answer before the question is
|
|
@@ -151,13 +183,17 @@ export function assertPluginHookEvent(event: PluginHookEvent): void {
|
|
|
151
183
|
case 'session_end':
|
|
152
184
|
case 'pre_compact':
|
|
153
185
|
case 'post_compact':
|
|
186
|
+
case 'subagent_start':
|
|
154
187
|
case 'subagent_stop':
|
|
155
188
|
case 'turn_start':
|
|
156
189
|
case 'turn_end':
|
|
190
|
+
case 'turn_failure':
|
|
157
191
|
case 'turn_interrupt':
|
|
158
192
|
case 'pre_tool_use':
|
|
159
193
|
case 'post_tool_use':
|
|
160
194
|
case 'post_tool_use_failure':
|
|
195
|
+
case 'post_tool_batch':
|
|
196
|
+
case 'permission_denied':
|
|
161
197
|
case 'permission_request':
|
|
162
198
|
case 'notification':
|
|
163
199
|
case 'pre_llm_call':
|
|
@@ -217,6 +253,16 @@ export interface PluginCompactionInfo {
|
|
|
217
253
|
readonly contextWindowTokens: number
|
|
218
254
|
}
|
|
219
255
|
|
|
256
|
+
/** One call in a `post_tool_batch` hook's context. */
|
|
257
|
+
export interface PluginToolBatchCall {
|
|
258
|
+
readonly toolCallId: string
|
|
259
|
+
readonly toolName: string
|
|
260
|
+
readonly toolInput: unknown
|
|
261
|
+
/** The text the model was given for the call, a refusal or an error included. */
|
|
262
|
+
readonly output: string
|
|
263
|
+
readonly isError: boolean
|
|
264
|
+
}
|
|
265
|
+
|
|
220
266
|
/** What a `notification` hook is shown. */
|
|
221
267
|
export interface PluginNotificationInfo {
|
|
222
268
|
/**
|
|
@@ -234,10 +280,12 @@ export interface PluginHookContext {
|
|
|
234
280
|
readonly event: PluginHookEvent
|
|
235
281
|
/** The host's session. Always present. */
|
|
236
282
|
readonly sessionId: SessionId
|
|
237
|
-
/** The session that delegated, on `subagent_stop`. */
|
|
283
|
+
/** The session that delegated, on `subagent_start` and `subagent_stop`. */
|
|
238
284
|
readonly parentSessionId?: SessionId
|
|
239
|
-
/** The turn whose tool call spawned the child, on `subagent_stop`. */
|
|
285
|
+
/** The turn whose tool call spawned the child, on `subagent_start` and `subagent_stop`. */
|
|
240
286
|
readonly parentTurnId?: TurnId
|
|
287
|
+
/** The name of the agent the child runs, on `subagent_start` and `subagent_stop`. */
|
|
288
|
+
readonly agentType?: string
|
|
241
289
|
/** The operator's prompt, on `user_prompt_submit`. */
|
|
242
290
|
readonly prompt?: string
|
|
243
291
|
/** The pass, on `pre_compact` and `post_compact`. */
|
|
@@ -245,6 +293,12 @@ export interface PluginHookContext {
|
|
|
245
293
|
readonly toolName?: string
|
|
246
294
|
readonly toolInput?: unknown
|
|
247
295
|
readonly toolResult?: ToolResult
|
|
296
|
+
/** The calls of one model step with their outcomes, on `post_tool_batch`. */
|
|
297
|
+
readonly toolCalls?: readonly PluginToolBatchCall[]
|
|
298
|
+
/** Why the call was refused, on `permission_denied`. */
|
|
299
|
+
readonly reason?: string
|
|
300
|
+
/** The failure's message, on `turn_failure`. */
|
|
301
|
+
readonly error?: string
|
|
248
302
|
/** What the host is telling the operator, on `notification`. */
|
|
249
303
|
readonly notification?: PluginNotificationInfo
|
|
250
304
|
/**
|
|
@@ -406,19 +460,27 @@ export function assertPluginHookResult(result: PluginHookResult): asserts result
|
|
|
406
460
|
/** Actions the query can interpret for a particular hook event. */
|
|
407
461
|
export type PluginHookResultFor<E extends PluginHookEvent> = E extends 'user_prompt_submit'
|
|
408
462
|
? Extract<PluginHookResult, { action: 'continue' | 'annotate' | 'skip' | 'error' }>
|
|
409
|
-
: E extends '
|
|
410
|
-
? Extract<PluginHookResult, { action: 'continue' | '
|
|
411
|
-
: E extends '
|
|
412
|
-
? Extract<PluginHookResult, { action: 'continue' | '
|
|
413
|
-
: E extends '
|
|
414
|
-
? Extract<PluginHookResult, { action: 'continue' | 'error' }>
|
|
415
|
-
: E extends '
|
|
416
|
-
? Extract<PluginHookResult, { action: 'continue' | '
|
|
417
|
-
: E extends '
|
|
418
|
-
? Extract<PluginHookResult, { action: 'continue' | 'skip'
|
|
419
|
-
: E extends '
|
|
420
|
-
? Extract<PluginHookResult, { action: 'continue' }>
|
|
421
|
-
:
|
|
463
|
+
: E extends 'subagent_start'
|
|
464
|
+
? Extract<PluginHookResult, { action: 'continue' | 'annotate' | 'error' }>
|
|
465
|
+
: E extends 'pre_tool_use'
|
|
466
|
+
? Extract<PluginHookResult, { action: 'continue' | 'skip' | 'modify' | 'error' }>
|
|
467
|
+
: E extends 'post_tool_use'
|
|
468
|
+
? Extract<PluginHookResult, { action: 'continue' | 'replace' | 'retry' | 'error' }>
|
|
469
|
+
: E extends 'post_tool_use_failure'
|
|
470
|
+
? Extract<PluginHookResult, { action: 'continue' | 'error' }>
|
|
471
|
+
: E extends 'permission_request'
|
|
472
|
+
? Extract<PluginHookResult, { action: 'continue' | 'skip' }>
|
|
473
|
+
: E extends 'turn_end' | 'subagent_stop' | 'pre_compact'
|
|
474
|
+
? Extract<PluginHookResult, { action: 'continue' | 'skip' | 'error' }>
|
|
475
|
+
: E extends
|
|
476
|
+
| 'turn_interrupt'
|
|
477
|
+
| 'session_start'
|
|
478
|
+
| 'session_end'
|
|
479
|
+
| 'notification'
|
|
480
|
+
| 'turn_failure'
|
|
481
|
+
| 'permission_denied'
|
|
482
|
+
? Extract<PluginHookResult, { action: 'continue' }>
|
|
483
|
+
: Extract<PluginHookResult, { action: 'continue' | 'error' }>
|
|
422
484
|
|
|
423
485
|
/** The event and its handler verdict stay correlated, including in hook arrays. */
|
|
424
486
|
export type PluginHookDefinition<E extends PluginHookEvent = PluginHookEvent> =
|
|
@@ -475,6 +537,18 @@ export interface PluginManifest {
|
|
|
475
537
|
readonly mcpServers?: readonly PluginMCPServerConfig[]
|
|
476
538
|
readonly connectors?: readonly string[]
|
|
477
539
|
readonly personas?: readonly string[]
|
|
540
|
+
/**
|
|
541
|
+
* Folders of markdown prompt files, relative to the plugin folder. Each
|
|
542
|
+
* file is a slash command named `<plugin>__<file name>`. The runtime does
|
|
543
|
+
* not read them: the host that owns slash commands does.
|
|
544
|
+
*/
|
|
545
|
+
readonly commands?: readonly string[]
|
|
546
|
+
/**
|
|
547
|
+
* Folders of markdown agent files, relative to the plugin folder. Each
|
|
548
|
+
* file is an agent type named `<plugin>__<name>`. Read by the host that
|
|
549
|
+
* owns delegation, not by the runtime.
|
|
550
|
+
*/
|
|
551
|
+
readonly agents?: readonly string[]
|
|
478
552
|
}
|
|
479
553
|
|
|
480
554
|
export const PluginMCPServerConfigSchema = z
|
|
@@ -487,6 +561,16 @@ export const PluginMCPServerConfigSchema = z
|
|
|
487
561
|
})
|
|
488
562
|
.strict()
|
|
489
563
|
|
|
564
|
+
/** A folder inside the plugin: relative, no `..` step, no drive or root. */
|
|
565
|
+
const PluginRelativeDirSchema = z
|
|
566
|
+
.string()
|
|
567
|
+
.min(1)
|
|
568
|
+
.refine(
|
|
569
|
+
(value) =>
|
|
570
|
+
!/^([a-zA-Z]:|[\\/])/.test(value) && !value.split(/[\\/]/).some((part) => part === '..'),
|
|
571
|
+
'must be a folder inside the plugin, with no ".." and no absolute path',
|
|
572
|
+
)
|
|
573
|
+
|
|
490
574
|
export const PluginManifestSchema = z.object({
|
|
491
575
|
name: z
|
|
492
576
|
.string()
|
|
@@ -503,6 +587,8 @@ export const PluginManifestSchema = z.object({
|
|
|
503
587
|
mcpServers: z.array(PluginMCPServerConfigSchema).max(MAX_MCP_SERVERS_PER_PLUGIN).optional(),
|
|
504
588
|
connectors: z.array(z.string()).max(MAX_CONNECTORS_PER_PLUGIN).optional(),
|
|
505
589
|
personas: z.array(z.string()).max(MAX_PERSONAS_PER_PLUGIN).optional(),
|
|
590
|
+
commands: z.array(PluginRelativeDirSchema).max(MAX_COMMAND_DIRS_PER_PLUGIN).optional(),
|
|
591
|
+
agents: z.array(PluginRelativeDirSchema).max(MAX_AGENT_DIRS_PER_PLUGIN).optional(),
|
|
506
592
|
})
|
|
507
593
|
|
|
508
594
|
// ---------------------------------------------------------------------------
|
|
@@ -100,8 +100,12 @@ export interface SubSession {
|
|
|
100
100
|
failureMode: FailureMode
|
|
101
101
|
completionMode: CompletionMode
|
|
102
102
|
workspaceId: WorkspaceId | null
|
|
103
|
-
/**
|
|
104
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Keep this delegated workspace when the child ends or its session is
|
|
105
|
+
* archived. `retain-changed` keeps it only if the child changed something;
|
|
106
|
+
* a workspace that is still there is therefore one worth keeping.
|
|
107
|
+
*/
|
|
108
|
+
workspaceRetention?: 'retain' | 'retain-changed'
|
|
105
109
|
/**
|
|
106
110
|
* For interventions, the immutable artifact being addressed. Chains form
|
|
107
111
|
* a strict acyclic DAG — see session-hierarchy.md §4.5.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReasoningEffort } from '../provider/chat.js'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Who may reach for a skill.
|
|
3
5
|
*
|
|
@@ -37,6 +39,52 @@ export interface SkillMetadata {
|
|
|
37
39
|
invocation?: SkillInvocation
|
|
38
40
|
|
|
39
41
|
metadata?: Record<string, string>
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* When the model should reach for the skill, in the author's words.
|
|
45
|
+
* Shown to the model next to the description (`when_to_use`); see
|
|
46
|
+
* {@link skillModelDescription}.
|
|
47
|
+
*/
|
|
48
|
+
whenToUse?: string
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Where the skill runs. `fork` hands its instructions to a delegated agent
|
|
52
|
+
* and returns that agent's report; absent or `inline` loads them into the
|
|
53
|
+
* current conversation.
|
|
54
|
+
*/
|
|
55
|
+
context?: 'inline' | 'fork'
|
|
56
|
+
|
|
57
|
+
/** The delegated agent type a `fork` skill runs as (`agent`). */
|
|
58
|
+
agent?: string
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The model a `fork` skill's delegated agent runs on (`model`). An inline
|
|
62
|
+
* skill runs on the turn's own model; this does not switch it.
|
|
63
|
+
*/
|
|
64
|
+
model?: string
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The reasoning effort requested for a `fork` skill's delegated agent
|
|
68
|
+
* (`effort`), even without `model`. The host validates the combination;
|
|
69
|
+
* this does not switch the current turn's effort for an inline skill.
|
|
70
|
+
*/
|
|
71
|
+
effort?: ReasoningEffort
|
|
72
|
+
|
|
73
|
+
/** Whether a `fork` skill's agent runs in the background (`background`). */
|
|
74
|
+
background?: boolean
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* What the model reads as a skill's description: the description, then the
|
|
79
|
+
* author's `when_to_use` guidance when there is one.
|
|
80
|
+
*/
|
|
81
|
+
export function skillModelDescription(metadata: {
|
|
82
|
+
description: string
|
|
83
|
+
whenToUse?: string
|
|
84
|
+
}): string {
|
|
85
|
+
const description = metadata.description.trim()
|
|
86
|
+
const when = metadata.whenToUse?.trim()
|
|
87
|
+
return when ? `${description} - ${when}` : description
|
|
40
88
|
}
|
|
41
89
|
|
|
42
90
|
/** What a skill that says nothing means. */
|