@code-yeongyu/senpi 2026.11.15-2 → 2026.11.15-3
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 +19 -0
- package/dist/bundle/chunks/{chunk-Q4RJ4WLE.js → chunk-225TDKTA.js} +4 -4
- package/dist/bundle/chunks/{chunk-QSU2456D.js → chunk-3KR3CDGM.js} +1 -1
- package/dist/bundle/chunks/{chunk-AOTHPTMU.js → chunk-5GCZFK4X.js} +2 -2
- package/dist/bundle/chunks/{chunk-BMADOJHZ.js → chunk-5QIFH624.js} +1 -1
- package/dist/bundle/chunks/{chunk-THYIV26N.js → chunk-GQEXLLWJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-3RILB2OD.js → chunk-OJOPOUAY.js} +9 -9
- package/dist/bundle/chunks/{chunk-64FJ4QQJ.js → chunk-PPCAJQDJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-74HCKLRH.js → chunk-TEXE4HT6.js} +1 -1
- package/dist/bundle/chunks/{chunk-RRFDLGX6.js → chunk-TNYFCGI7.js} +156 -156
- package/dist/bundle/chunks/{cli-main-GNQY2LTU.js → cli-main-CV3ODX4A.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-D3DNH6XL.js → hand-entry-2NN7ZTY6.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-ATBPY4M5.js → interactive-mode-TGHZWM2T.js} +1 -1
- package/dist/bundle/chunks/{main-OMFVSMUR.js → main-B7WEY4JW.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-ACQ5N4UB.js → multi-session-host-53YLL2OD.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-2VMRV4HL.js → package-manager-cli-2U54AVKW.js} +1 -1
- package/dist/bundle/chunks/{role-BTH5PVME.js → role-4IXZZAL4.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-XUK5SYKH.js → rpc-mode-RRYXENML.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-VO3X4OE3.js → runtime-session-KKHEYZOH.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-Y5EIFFPY.js → session-control-endpoint-HVULSIUR.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +331 -331
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.js +34 -3
- package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.d.ts +2 -0
- package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/failover.d.ts +2 -0
- package/dist/core/extensions/builtin/anthropic-subscription/failover.js +22 -4
- package/dist/core/extensions/builtin/anthropic-subscription/index.js +7 -2
- package/dist/core/extensions/builtin/anthropic-subscription/limit-recheck.d.ts +15 -0
- package/dist/core/extensions/builtin/anthropic-subscription/limit-recheck.js +55 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.d.ts +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +8 -5
- package/dist/core/extensions/builtin/anthropic-subscription/stream.d.ts +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/stream.js +3 -1
- package/dist/core/extensions/builtin/terminal/extension-state.js +15 -0
- package/dist/core/extensions/builtin/terminal/notify.d.ts +2 -1
- package/dist/core/extensions/builtin/terminal/notify.js +15 -6
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +5 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.js +41 -1
- package/dist/core/extensions/builtin/terminal/tools/context.d.ts +4 -0
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.js +5 -0
- package/dist/core/extensions/types.d.ts +7 -0
- package/dist/core/run-background-jobs.d.ts +33 -0
- package/dist/core/run-background-jobs.js +47 -0
- package/dist/core/tools/bash-core.d.ts +50 -0
- package/dist/core/tools/bash-core.js +169 -0
- package/dist/core/tools/bash-schema.d.ts +48 -0
- package/dist/core/tools/bash-schema.js +34 -0
- package/dist/core/tools/bash.d.ts +4 -70
- package/dist/core/tools/bash.js +32 -409
- package/dist/core/tools/coding-tools-core.d.ts +24 -0
- package/dist/core/tools/coding-tools-core.js +14 -0
- package/dist/core/tools/edit-core.d.ts +56 -0
- package/dist/core/tools/edit-core.js +175 -0
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.js +0 -32
- package/dist/core/tools/edit-preview.d.ts +7 -0
- package/dist/core/tools/edit-preview.js +34 -0
- package/dist/core/tools/edit.d.ts +5 -43
- package/dist/core/tools/edit.js +10 -158
- package/dist/core/tools/encoding.d.ts +10 -0
- package/dist/core/tools/encoding.js +58 -0
- package/dist/core/tools/file-tool-host.d.ts +25 -0
- package/dist/core/tools/file-tool-host.js +109 -0
- package/dist/core/tools/fs-error-code.d.ts +2 -0
- package/dist/core/tools/fs-error-code.js +15 -0
- package/dist/core/tools/machine-output-spill.d.ts +11 -0
- package/dist/core/tools/machine-output-spill.js +65 -0
- package/dist/core/tools/machine.d.ts +4 -24
- package/dist/core/tools/machine.js +4 -44
- package/dist/core/tools/output-accumulator-core.d.ts +84 -0
- package/dist/core/tools/output-accumulator-core.js +200 -0
- package/dist/core/tools/output-accumulator.d.ts +9 -61
- package/dist/core/tools/output-accumulator.js +90 -265
- package/dist/core/tools/path-utils.js +3 -48
- package/dist/core/tools/posix-signals.d.ts +3 -0
- package/dist/core/tools/posix-signals.js +113 -0
- package/dist/core/tools/read-core.d.ts +64 -0
- package/dist/core/tools/read-core.js +180 -0
- package/dist/core/tools/read-text.d.ts +23 -0
- package/dist/core/tools/read-text.js +90 -0
- package/dist/core/tools/read.d.ts +6 -47
- package/dist/core/tools/read.js +13 -218
- package/dist/core/tools/renderers/bash.d.ts +0 -1
- package/dist/core/tools/renderers/bash.js +0 -1
- package/dist/core/tools/renderers/edit.d.ts +1 -1
- package/dist/core/tools/renderers/edit.js +1 -1
- package/dist/core/tools/secret-output-redactor.js +2 -1
- package/dist/core/tools/shell-operations.d.ts +53 -0
- package/dist/core/tools/shell-operations.js +115 -0
- package/dist/core/tools/shell-output.d.ts +20 -0
- package/dist/core/tools/shell-output.js +152 -0
- package/dist/core/tools/tail-window.js +5 -7
- package/dist/core/tools/tool-machine.d.ts +30 -0
- package/dist/core/tools/tool-machine.js +47 -0
- package/dist/core/tools/truncate.js +15 -14
- package/dist/core/tools/write-core.d.ts +47 -0
- package/dist/core/tools/write-core.js +108 -0
- package/dist/core/tools/write-result.d.ts +0 -1
- package/dist/core/tools/write-result.js +0 -13
- package/dist/core/tools/write.d.ts +6 -31
- package/dist/core/tools/write.js +25 -77
- package/dist/core/turn-origin.d.ts +4 -2
- package/dist/core/turn-origin.js +15 -8
- package/dist/modes/interactive/session-control-session-commands.js +1 -1
- package/dist/modes/rpc/connection-handler.js +2 -2
- package/dist/modes/rpc/effect-commands.d.ts +1 -4
- package/dist/modes/rpc/method-classes-schema-session.d.ts +1 -0
- package/dist/modes/rpc/method-classes-schema-session.js +5 -1
- package/dist/modes/rpc/method-classes-schema.d.ts +1 -0
- package/dist/modes/rpc/pause-command-validation.js +2 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +2 -4
- package/dist/modes/rpc/rpc-session-command-types.d.ts +1 -0
- package/dist/modes/rpc/session-control-actions-data.d.ts +7 -3
- package/dist/modes/rpc/session-control-actions-data.js +12 -6
- package/dist/tools-core.d.ts +14 -0
- package/dist/tools-core.js +9 -0
- package/dist/utils/image-mime.d.ts +4 -0
- package/dist/utils/image-mime.js +99 -0
- package/dist/utils/mime.d.ts +1 -1
- package/dist/utils/mime.js +2 -97
- package/docs/extensions.md +7 -1
- package/docs/rpc.md +14 -0
- package/package.json +11 -7
- package/vendor/senpi-machine-ops/files/local-files.js +34 -5
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { decodeUtf8, encodeUtf8 } from "./encoding.js";
|
|
3
|
+
import { fsErrorCode } from "./fs-error-code.js";
|
|
4
|
+
import { inProcessFileMutationQueue, lexicalCanonicalPath, posixDirname, resolvePosixToolPath, } from "./file-tool-host.js";
|
|
5
|
+
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
6
|
+
import { createWriteDetails } from "./write-result.js";
|
|
7
|
+
export const writeSchema = Type.Object({
|
|
8
|
+
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
9
|
+
content: Type.String({ description: "Content to write to the file" }),
|
|
10
|
+
});
|
|
11
|
+
export const writeToolSystemPromptContribution = {
|
|
12
|
+
snippet: "Create or overwrite files",
|
|
13
|
+
guidelines: ["write only for new files or full rewrites."],
|
|
14
|
+
fullGuidelines: ["Use write only for new files or complete rewrites."],
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The default write operations over the shared operation layer. `files.write` creates the parent directory in the
|
|
18
|
+
* same call (`createParentDirs`), so `mkdir` has nothing left to do; the tool already holds the file's mutation slot.
|
|
19
|
+
*/
|
|
20
|
+
function machineWriteOperations(machine, signal) {
|
|
21
|
+
const ctx = machine.context(signal, "caller");
|
|
22
|
+
return {
|
|
23
|
+
writeFile: async (path, content) => {
|
|
24
|
+
await machine.ops.files.write({ path, bytes: encodeUtf8(content), createParentDirs: true }, ctx);
|
|
25
|
+
},
|
|
26
|
+
mkdir: async () => { },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** The file's content before the write, read on the machine; it feeds the patch in the result details. */
|
|
30
|
+
function machineWriteBaseline(machine) {
|
|
31
|
+
return async (absolutePath) => {
|
|
32
|
+
try {
|
|
33
|
+
const { bytes } = await machine.ops.files.read({ path: absolutePath }, machine.context(undefined, "caller"));
|
|
34
|
+
return { kind: "present", content: decodeUtf8(bytes) };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof Error && fsErrorCode(error) === "ENOENT")
|
|
38
|
+
return { kind: "missing" };
|
|
39
|
+
if (error instanceof Error)
|
|
40
|
+
return { kind: "unavailable" };
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function createCoreWriteToolDefinition(cwd, options) {
|
|
46
|
+
const machine = options.machine;
|
|
47
|
+
const readBaseline = options.operations ? undefined : (options.readBaseline ?? machineWriteBaseline(machine));
|
|
48
|
+
const filesystemPolicy = options.filesystemPolicy;
|
|
49
|
+
const resolvePath = options.resolvePath ?? resolvePosixToolPath;
|
|
50
|
+
const dirname = options.dirname ?? posixDirname;
|
|
51
|
+
const withMutationQueue = options.withMutationQueue ?? inProcessFileMutationQueue;
|
|
52
|
+
const canonicalizePath = options.canonicalizePath ?? lexicalCanonicalPath;
|
|
53
|
+
return {
|
|
54
|
+
name: "write",
|
|
55
|
+
label: "write",
|
|
56
|
+
description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
|
57
|
+
promptSnippet: writeToolSystemPromptContribution.snippet,
|
|
58
|
+
promptGuidelines: [...writeToolSystemPromptContribution.guidelines],
|
|
59
|
+
fullPromptGuidelines: [...writeToolSystemPromptContribution.fullGuidelines],
|
|
60
|
+
parameters: writeSchema,
|
|
61
|
+
constrainedSampling: { type: "json_schema", strict: "prefer" },
|
|
62
|
+
async execute(_toolCallId, { path, content }, signal, _onUpdate, ctx) {
|
|
63
|
+
const admitted = machine.begin("files.write", { path, content }, signal);
|
|
64
|
+
if (admitted !== undefined)
|
|
65
|
+
await admitted;
|
|
66
|
+
const ops = options.operations ?? machineWriteOperations(machine, signal);
|
|
67
|
+
const absolutePath = resolvePath(path, ctx?.cwd || cwd);
|
|
68
|
+
const dir = dirname(absolutePath);
|
|
69
|
+
return withMutationQueue(absolutePath, async () => {
|
|
70
|
+
// Do not reject from an abort event listener here: that would release the
|
|
71
|
+
// mutation queue while an in-flight filesystem operation may still finish.
|
|
72
|
+
// Checking signal.aborted after each await observes the same aborts while
|
|
73
|
+
// keeping the queue locked until the current operation has settled.
|
|
74
|
+
const throwIfAborted = () => {
|
|
75
|
+
if (signal?.aborted)
|
|
76
|
+
throw new Error("Operation aborted");
|
|
77
|
+
};
|
|
78
|
+
throwIfAborted();
|
|
79
|
+
if (filesystemPolicy) {
|
|
80
|
+
const decision = await filesystemPolicy({
|
|
81
|
+
operation: "write",
|
|
82
|
+
canonicalPath: await canonicalizePath(absolutePath),
|
|
83
|
+
toolName: "write",
|
|
84
|
+
});
|
|
85
|
+
if (!decision.allow)
|
|
86
|
+
throw new Error(decision.reason);
|
|
87
|
+
throwIfAborted();
|
|
88
|
+
}
|
|
89
|
+
const baseline = readBaseline ? await readBaseline(absolutePath) : { kind: "unavailable" };
|
|
90
|
+
throwIfAborted();
|
|
91
|
+
// Create parent directories if needed.
|
|
92
|
+
await ops.mkdir(dir);
|
|
93
|
+
throwIfAborted();
|
|
94
|
+
// Write the file contents.
|
|
95
|
+
await ops.writeFile(absolutePath, content);
|
|
96
|
+
throwIfAborted();
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: `Successfully wrote to ${path}` }],
|
|
99
|
+
details: createWriteDetails(path, content, baseline),
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function createCoreWriteTool(cwd, options) {
|
|
106
|
+
return wrapToolDefinition(createCoreWriteToolDefinition(cwd, options));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=write-core.js.map
|
|
@@ -11,7 +11,6 @@ export type WriteBaseline = {
|
|
|
11
11
|
} | {
|
|
12
12
|
readonly kind: "unavailable";
|
|
13
13
|
};
|
|
14
|
-
export declare function readLocalWriteBaseline(absolutePath: string): Promise<WriteBaseline>;
|
|
15
14
|
export declare function createWriteDetails(path: string, content: string, baseline: WriteBaseline): WriteToolDetails | undefined;
|
|
16
15
|
export declare function formatWriteResult(result: {
|
|
17
16
|
readonly content: readonly {
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import { readFile } from "fs/promises";
|
|
2
1
|
import { createUnifiedPatch } from "./unified-diff.js";
|
|
3
|
-
export async function readLocalWriteBaseline(absolutePath) {
|
|
4
|
-
try {
|
|
5
|
-
return { kind: "present", content: await readFile(absolutePath, "utf-8") };
|
|
6
|
-
}
|
|
7
|
-
catch (error) {
|
|
8
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
9
|
-
return { kind: "missing" };
|
|
10
|
-
if (error instanceof Error)
|
|
11
|
-
return { kind: "unavailable" };
|
|
12
|
-
throw error;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
2
|
export function createWriteDetails(path, content, baseline) {
|
|
16
3
|
switch (baseline.kind) {
|
|
17
4
|
case "missing":
|
|
@@ -1,37 +1,12 @@
|
|
|
1
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
path: Type.TString;
|
|
8
|
-
content: Type.TString;
|
|
9
|
-
}>;
|
|
10
|
-
export declare const writeToolSystemPromptContribution: {
|
|
11
|
-
readonly snippet: "Create or overwrite files";
|
|
12
|
-
readonly guidelines: readonly ["write only for new files or full rewrites."];
|
|
13
|
-
readonly fullGuidelines: readonly ["Use write only for new files or complete rewrites."];
|
|
14
|
-
};
|
|
15
|
-
export type WriteToolInput = Static<typeof writeSchema>;
|
|
16
|
-
/**
|
|
17
|
-
* Pluggable operations for the write tool.
|
|
18
|
-
* Override these to delegate file writing to remote systems (for example SSH).
|
|
19
|
-
*/
|
|
20
|
-
export interface WriteOperations {
|
|
21
|
-
/** Write content to a file */
|
|
22
|
-
writeFile: (absolutePath: string, content: string) => Promise<void>;
|
|
23
|
-
/** Create directory recursively */
|
|
24
|
-
mkdir: (dir: string) => Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
export interface WriteToolOptions {
|
|
27
|
-
/** Custom operations for file writing. Default: local filesystem */
|
|
28
|
-
operations?: WriteOperations;
|
|
29
|
-
/** Extension-registered filesystem policy checker. */
|
|
30
|
-
filesystemPolicy?: FilesystemPolicyChecker;
|
|
2
|
+
import type { ToolDefinition } from "../extensions/types.ts";
|
|
3
|
+
import { type CoreWriteToolOptions, type writeSchema } from "./write-core.ts";
|
|
4
|
+
import type { WriteToolDetails } from "./write-result.ts";
|
|
5
|
+
export { type WriteOperations, type WriteToolInput, writeToolSystemPromptContribution } from "./write-core.ts";
|
|
6
|
+
export interface WriteToolOptions extends Pick<CoreWriteToolOptions, "operations" | "filesystemPolicy"> {
|
|
31
7
|
/** Operation layer and policy gate. Default: the process-wide local machine. */
|
|
32
|
-
machine?:
|
|
8
|
+
machine?: CoreWriteToolOptions["machine"];
|
|
33
9
|
}
|
|
34
10
|
export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition<typeof writeSchema, WriteToolDetails | undefined>;
|
|
35
11
|
export declare function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema>;
|
|
36
|
-
export {};
|
|
37
12
|
//# sourceMappingURL=write.d.ts.map
|
package/dist/core/tools/write.js
CHANGED
|
@@ -1,89 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
3
|
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
4
4
|
import { canonicalizeFilesystemPath } from "./filesystem-policy.js";
|
|
5
5
|
import { defaultToolMachine } from "./machine.js";
|
|
6
6
|
import { resolveToCwd } from "./path-utils.js";
|
|
7
7
|
import { writeRenderers } from "./renderers/write.js";
|
|
8
8
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
function machineWriteOperations(machine, signal) {
|
|
24
|
-
const ctx = machine.context(signal, "caller");
|
|
25
|
-
return {
|
|
26
|
-
writeFile: async (path, content) => {
|
|
27
|
-
await machine.ops.files.write({ path, bytes: Buffer.from(content, "utf-8"), createParentDirs: true }, ctx);
|
|
28
|
-
},
|
|
29
|
-
mkdir: async () => { },
|
|
30
|
-
};
|
|
9
|
+
import { createCoreWriteToolDefinition } from "./write-core.js";
|
|
10
|
+
export { writeToolSystemPromptContribution } from "./write-core.js";
|
|
11
|
+
async function readLocalWriteBaseline(absolutePath) {
|
|
12
|
+
try {
|
|
13
|
+
return { kind: "present", content: await readFile(absolutePath, "utf-8") };
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
17
|
+
return { kind: "missing" };
|
|
18
|
+
if (error instanceof Error)
|
|
19
|
+
return { kind: "unavailable" };
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
31
22
|
}
|
|
32
23
|
export function createWriteToolDefinition(cwd, options) {
|
|
33
|
-
const machine = options?.machine ?? defaultToolMachine();
|
|
34
|
-
const readBaseline = options?.operations ? undefined : readLocalWriteBaseline;
|
|
35
|
-
const filesystemPolicy = options?.filesystemPolicy;
|
|
36
24
|
return {
|
|
37
|
-
...(options?.operations !== undefined || filesystemPolicy !== undefined ? { serverPinned: true } : {}),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const admitted = machine.begin("files.write", { path, content }, signal);
|
|
48
|
-
if (admitted !== undefined)
|
|
49
|
-
await admitted;
|
|
50
|
-
const ops = options?.operations ?? machineWriteOperations(machine, signal);
|
|
51
|
-
const absolutePath = resolveToCwd(path, ctx?.cwd || cwd);
|
|
52
|
-
const dir = dirname(absolutePath);
|
|
53
|
-
return withFileMutationQueue(absolutePath, async () => {
|
|
54
|
-
// Do not reject from an abort event listener here: that would release the
|
|
55
|
-
// mutation queue while an in-flight filesystem operation may still finish.
|
|
56
|
-
// Checking signal.aborted after each await observes the same aborts while
|
|
57
|
-
// keeping the queue locked until the current operation has settled.
|
|
58
|
-
const throwIfAborted = () => {
|
|
59
|
-
if (signal?.aborted)
|
|
60
|
-
throw new Error("Operation aborted");
|
|
61
|
-
};
|
|
62
|
-
throwIfAborted();
|
|
63
|
-
if (filesystemPolicy) {
|
|
64
|
-
const decision = await filesystemPolicy({
|
|
65
|
-
operation: "write",
|
|
66
|
-
canonicalPath: await canonicalizeFilesystemPath(absolutePath),
|
|
67
|
-
toolName: "write",
|
|
68
|
-
});
|
|
69
|
-
if (!decision.allow)
|
|
70
|
-
throw new Error(decision.reason);
|
|
71
|
-
throwIfAborted();
|
|
72
|
-
}
|
|
73
|
-
const baseline = readBaseline ? await readBaseline(absolutePath) : { kind: "unavailable" };
|
|
74
|
-
throwIfAborted();
|
|
75
|
-
// Create parent directories if needed.
|
|
76
|
-
await ops.mkdir(dir);
|
|
77
|
-
throwIfAborted();
|
|
78
|
-
// Write the file contents.
|
|
79
|
-
await ops.writeFile(absolutePath, content);
|
|
80
|
-
throwIfAborted();
|
|
81
|
-
return {
|
|
82
|
-
content: [{ type: "text", text: `Successfully wrote to ${path}` }],
|
|
83
|
-
details: createWriteDetails(path, content, baseline),
|
|
84
|
-
};
|
|
85
|
-
});
|
|
86
|
-
},
|
|
25
|
+
...(options?.operations !== undefined || options?.filesystemPolicy !== undefined ? { serverPinned: true } : {}),
|
|
26
|
+
...createCoreWriteToolDefinition(cwd, {
|
|
27
|
+
...options,
|
|
28
|
+
machine: options?.machine ?? defaultToolMachine(),
|
|
29
|
+
resolvePath: resolveToCwd,
|
|
30
|
+
dirname,
|
|
31
|
+
withMutationQueue: withFileMutationQueue,
|
|
32
|
+
canonicalizePath: canonicalizeFilesystemPath,
|
|
33
|
+
readBaseline: readLocalWriteBaseline,
|
|
34
|
+
}),
|
|
87
35
|
...writeRenderers,
|
|
88
36
|
};
|
|
89
37
|
}
|
|
@@ -16,7 +16,7 @@ export declare function inputTurnMark(input: {
|
|
|
16
16
|
readonly connectionOrigin?: ConnectionOrigin;
|
|
17
17
|
readonly source?: string;
|
|
18
18
|
}): InputTurnMark;
|
|
19
|
-
export declare function markInputTurnOrigin(message: object, mark: InputTurnMark): void;
|
|
19
|
+
export declare function markInputTurnOrigin(message: object, mark: InputTurnMark, personStarted?: boolean): void;
|
|
20
20
|
/** Carries `from`'s origin mark onto `to`, a copy of the same input: a copy without it would open or join a turn unmarked. */
|
|
21
21
|
export declare function copyInputTurnMark(from: object, to: object): void;
|
|
22
22
|
/** Whether a message carries an origin mark: a user message always opens a turn's origin, any other only when marked. */
|
|
@@ -30,10 +30,12 @@ export declare function recordIsDelegated(): boolean;
|
|
|
30
30
|
* the turn it continues. The user message that opens a turn sets its origin, a steer keeps it.
|
|
31
31
|
*/
|
|
32
32
|
export declare function noteRunStart(sessionManager: object): void;
|
|
33
|
-
/**
|
|
33
|
+
/** The next retry or recovery run repeats this turn; its start consumes the continuation mark. */
|
|
34
34
|
export declare function noteTurnContinuation(sessionManager: object): void;
|
|
35
35
|
export declare function endTurnContinuation(sessionManager: object): void;
|
|
36
36
|
export declare function noteUserMessageStart(sessionManager: object, message: object): void;
|
|
37
|
+
/** A person's admitted message owns this identity; only an explicit continuation preserves it across run starts. */
|
|
38
|
+
export declare function currentPersonTurn(sessionManager: object): object | undefined;
|
|
37
39
|
/** Whether the deciding turn counts as delegated-origin: a cross-account device started this turn or this run. */
|
|
38
40
|
export declare function decidingTurnIsDelegated(sessionManager: object): boolean;
|
|
39
41
|
//# sourceMappingURL=turn-origin.d.ts.map
|
package/dist/core/turn-origin.js
CHANGED
|
@@ -32,8 +32,8 @@ export function inputTurnMark(input) {
|
|
|
32
32
|
return "delegated";
|
|
33
33
|
return input.source === undefined || input.source === "interactive" ? "local" : "engine";
|
|
34
34
|
}
|
|
35
|
-
export function markInputTurnOrigin(message, mark) {
|
|
36
|
-
inputMarks.set(message, mark);
|
|
35
|
+
export function markInputTurnOrigin(message, mark, personStarted = false) {
|
|
36
|
+
inputMarks.set(message, { origin: mark, personStarted });
|
|
37
37
|
}
|
|
38
38
|
/** Carries `from`'s origin mark onto `to`, a copy of the same input: a copy without it would open or join a turn unmarked. */
|
|
39
39
|
export function copyInputTurnMark(from, to) {
|
|
@@ -58,11 +58,11 @@ export function recordIsDelegated() {
|
|
|
58
58
|
* the turn it continues. The user message that opens a turn sets its origin, a steer keeps it.
|
|
59
59
|
*/
|
|
60
60
|
export function noteRunStart(sessionManager) {
|
|
61
|
-
if (continuingTurns.
|
|
61
|
+
if (continuingTurns.delete(sessionManager))
|
|
62
62
|
return;
|
|
63
|
-
currentOrigins.set(sessionManager, recordScope.closeAtRunStart() === true ? "delegated" : "engine");
|
|
63
|
+
currentOrigins.set(sessionManager, { origin: recordScope.closeAtRunStart() === true ? "delegated" : "engine" });
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
65
|
+
/** The next retry or recovery run repeats this turn; its start consumes the continuation mark. */
|
|
66
66
|
export function noteTurnContinuation(sessionManager) {
|
|
67
67
|
continuingTurns.add(sessionManager);
|
|
68
68
|
}
|
|
@@ -71,12 +71,19 @@ export function endTurnContinuation(sessionManager) {
|
|
|
71
71
|
}
|
|
72
72
|
export function noteUserMessageStart(sessionManager, message) {
|
|
73
73
|
const mark = inputMarks.get(message);
|
|
74
|
-
if (mark === "join")
|
|
74
|
+
if (mark?.origin === "join")
|
|
75
75
|
return;
|
|
76
|
-
currentOrigins.set(sessionManager,
|
|
76
|
+
currentOrigins.set(sessionManager, {
|
|
77
|
+
origin: mark?.origin ?? "engine",
|
|
78
|
+
personTurn: mark?.personStarted ? {} : undefined,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** A person's admitted message owns this identity; only an explicit continuation preserves it across run starts. */
|
|
82
|
+
export function currentPersonTurn(sessionManager) {
|
|
83
|
+
return currentOrigins.get(sessionManager)?.personTurn;
|
|
77
84
|
}
|
|
78
85
|
/** Whether the deciding turn counts as delegated-origin: a cross-account device started this turn or this run. */
|
|
79
86
|
export function decidingTurnIsDelegated(sessionManager) {
|
|
80
|
-
return currentOrigins.get(sessionManager) === "delegated";
|
|
87
|
+
return currentOrigins.get(sessionManager)?.origin === "delegated";
|
|
81
88
|
}
|
|
82
89
|
//# sourceMappingURL=turn-origin.js.map
|
|
@@ -24,7 +24,7 @@ export async function runSessionControlCommand(session, controls, command) {
|
|
|
24
24
|
return success(id, type);
|
|
25
25
|
}
|
|
26
26
|
case "interrupt":
|
|
27
|
-
return success(id, type, await interruptRunningTurn(session, command.turnId, () => controls.interruptTurn()));
|
|
27
|
+
return success(id, type, await interruptRunningTurn(session, command.turnId, () => controls.interruptTurn(), command.background));
|
|
28
28
|
default:
|
|
29
29
|
return undefined;
|
|
30
30
|
}
|
|
@@ -1166,7 +1166,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
1166
1166
|
const stopped = await interruptRunningTurn(session, undefined, () => {
|
|
1167
1167
|
ClientAdmissions.forSession(session).noteAbort(effectContext().by);
|
|
1168
1168
|
return session.stop();
|
|
1169
|
-
});
|
|
1169
|
+
}, command.background);
|
|
1170
1170
|
if (!stopped.interrupted)
|
|
1171
1171
|
await session.stop();
|
|
1172
1172
|
return success(id, "interrupt", stopped);
|
|
@@ -1174,7 +1174,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
1174
1174
|
return success(id, "interrupt", await interruptRunningTurn(session, command.turnId, () => {
|
|
1175
1175
|
ClientAdmissions.forSession(session).noteAbort(effectContext().by);
|
|
1176
1176
|
return session.abort();
|
|
1177
|
-
}));
|
|
1177
|
+
}, command.background));
|
|
1178
1178
|
case "hold_input": {
|
|
1179
1179
|
const answer = runHoldInput(session, command, {
|
|
1180
1180
|
interactiveUser: hasRole(INTERACTIVE_USER_CAPABILITY),
|
|
@@ -315,10 +315,7 @@ export declare function runSetThinkingLevel(ctx: EffectCommandContext, command:
|
|
|
315
315
|
type: "response";
|
|
316
316
|
command: "interrupt";
|
|
317
317
|
success: true;
|
|
318
|
-
data:
|
|
319
|
-
interrupted: boolean;
|
|
320
|
-
turnId?: string;
|
|
321
|
-
};
|
|
318
|
+
data: import("./session-control-actions-data.ts").InterruptOutcome;
|
|
322
319
|
} | {
|
|
323
320
|
id?: string;
|
|
324
321
|
type: "response";
|
|
@@ -177,6 +177,7 @@ export declare const SESSION_RECORD_SCHEMAS: {
|
|
|
177
177
|
} & {
|
|
178
178
|
readonly turnId: Type.TOptional<Type.TString>;
|
|
179
179
|
readonly intent: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
180
|
+
readonly background: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
|
|
180
181
|
}>;
|
|
181
182
|
hold_input: Type.TObject<{
|
|
182
183
|
id: Type.TOptional<Type.TString>;
|
|
@@ -65,7 +65,11 @@ const PROMPTING_SCHEMAS = {
|
|
|
65
65
|
graceMs: OptNum,
|
|
66
66
|
intent: Opt(literals("stop", "abort")),
|
|
67
67
|
}),
|
|
68
|
-
interrupt: session("interrupt", {
|
|
68
|
+
interrupt: session("interrupt", {
|
|
69
|
+
turnId: OptId,
|
|
70
|
+
intent: Opt(literals("stop", "abort")),
|
|
71
|
+
background: Opt(literals("stop")),
|
|
72
|
+
}),
|
|
69
73
|
hold_input: session("hold_input", {
|
|
70
74
|
inputId: Id,
|
|
71
75
|
revision: Num,
|
|
@@ -650,6 +650,7 @@ export declare const RPC_INBOUND_SCHEMAS: {
|
|
|
650
650
|
} & {
|
|
651
651
|
readonly turnId: import("typebox").TOptional<import("typebox").TString>;
|
|
652
652
|
readonly intent: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
653
|
+
readonly background: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
|
|
653
654
|
}>;
|
|
654
655
|
readonly hold_input: import("typebox").TObject<{
|
|
655
656
|
id: import("typebox").TOptional<import("typebox").TString>;
|
|
@@ -12,6 +12,8 @@ export function validatePauseCommand(value) {
|
|
|
12
12
|
if (value.intent !== "stop" && value.intent !== "abort")
|
|
13
13
|
return 'intent must be "stop" or "abort".';
|
|
14
14
|
}
|
|
15
|
+
if (value.type === "interrupt" && value.background !== undefined && value.background !== "stop")
|
|
16
|
+
return 'background must be "stop".';
|
|
15
17
|
if (value.type === "resume_session") {
|
|
16
18
|
if (value.expectedSeq !== undefined && !seq(value.expectedSeq))
|
|
17
19
|
return "expectedSeq must be a non-negative integer.";
|
|
@@ -8,6 +8,7 @@ import type { ServiceTier } from "../../core/extensions/builtin/service-tier.ts"
|
|
|
8
8
|
import type { SessionControlAdmission } from "../../core/extensions/types.ts";
|
|
9
9
|
import type { PermissionModeReply } from "../../core/permission-mode.ts";
|
|
10
10
|
import type { ApiKeyVerification } from "../../core/verify-api-key.ts";
|
|
11
|
+
import type { InterruptOutcome } from "./session-control-actions-data.ts";
|
|
11
12
|
import type { ClientMessageAdmission } from "./client-admission-record.ts";
|
|
12
13
|
import type { RpcProjectFile } from "./project-file-commands.ts";
|
|
13
14
|
import type { RpcProjectSettings, RpcProjectTrust } from "./project-workspace-commands.ts";
|
|
@@ -99,10 +100,7 @@ export type RpcMutationResponse = {
|
|
|
99
100
|
type: "response";
|
|
100
101
|
command: "interrupt";
|
|
101
102
|
success: true;
|
|
102
|
-
data:
|
|
103
|
-
interrupted: boolean;
|
|
104
|
-
turnId?: string;
|
|
105
|
-
};
|
|
103
|
+
data: InterruptOutcome;
|
|
106
104
|
} | {
|
|
107
105
|
id?: string;
|
|
108
106
|
type: "response";
|
|
@@ -111,6 +111,7 @@ export type RpcSessionCommand = {
|
|
|
111
111
|
type: "interrupt";
|
|
112
112
|
turnId?: string;
|
|
113
113
|
intent?: "stop" | "abort";
|
|
114
|
+
background?: "stop";
|
|
114
115
|
}
|
|
115
116
|
/** Human input held for a paused session, delivered when it resumes; idempotent by inputId (senpi#3811). */
|
|
116
117
|
| {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentSession } from "../../core/agent-session.ts";
|
|
2
|
+
import type { RunBackgroundStopOutcome } from "../../core/run-background-jobs.ts";
|
|
2
3
|
export declare function availableModelsData(session: AgentSession): Promise<{
|
|
3
4
|
models: readonly object[];
|
|
4
5
|
}>;
|
|
@@ -7,11 +8,14 @@ export declare function unsupportedThinkingLevel(level: unknown): string;
|
|
|
7
8
|
export interface InterruptOutcome {
|
|
8
9
|
readonly interrupted: boolean;
|
|
9
10
|
readonly turnId?: string;
|
|
11
|
+
/** Present when the caller asked `background: "stop"`: the interrupted turn's background jobs it stopped. */
|
|
12
|
+
readonly background?: RunBackgroundStopOutcome;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
|
-
* `interrupt { turnId? }`: stops the running turn and only that. An idle session answers
|
|
15
|
+
* `interrupt { turnId?, background? }`: stops the running turn and only that. An idle session answers
|
|
13
16
|
* `interrupted: false`; so does a `turnId` naming a turn that is no longer the running one, which
|
|
14
|
-
* then answers the running turn's id. `stop` resolves once the turn has stopped
|
|
17
|
+
* then answers the running turn's id. `stop` resolves once the turn has stopped; with `background:
|
|
18
|
+
* "stop"` the background jobs that turn started are stopped after it, and the answer names them.
|
|
15
19
|
*/
|
|
16
|
-
export declare function interruptRunningTurn(session: AgentSession, requestedTurnId: unknown, stop: () => Promise<void
|
|
20
|
+
export declare function interruptRunningTurn(session: AgentSession, requestedTurnId: unknown, stop: () => Promise<void>, background?: unknown): Promise<InterruptOutcome>;
|
|
17
21
|
//# sourceMappingURL=session-control-actions-data.d.ts.map
|
|
@@ -30,18 +30,24 @@ export async function availableModelsData(session) {
|
|
|
30
30
|
export function unsupportedThinkingLevel(level) {
|
|
31
31
|
return `Thinking level ${String(level)} is not supported by the active model.`;
|
|
32
32
|
}
|
|
33
|
+
const NOTHING_STOPPED = { stopped: [], failed: [] };
|
|
33
34
|
/**
|
|
34
|
-
* `interrupt { turnId? }`: stops the running turn and only that. An idle session answers
|
|
35
|
+
* `interrupt { turnId?, background? }`: stops the running turn and only that. An idle session answers
|
|
35
36
|
* `interrupted: false`; so does a `turnId` naming a turn that is no longer the running one, which
|
|
36
|
-
* then answers the running turn's id. `stop` resolves once the turn has stopped
|
|
37
|
+
* then answers the running turn's id. `stop` resolves once the turn has stopped; with `background:
|
|
38
|
+
* "stop"` the background jobs that turn started are stopped after it, and the answer names them.
|
|
37
39
|
*/
|
|
38
|
-
export async function interruptRunningTurn(session, requestedTurnId, stop) {
|
|
40
|
+
export async function interruptRunningTurn(session, requestedTurnId, stop, background) {
|
|
41
|
+
const stopsBackground = background === "stop";
|
|
42
|
+
const nothing = stopsBackground ? { background: NOTHING_STOPPED } : {};
|
|
39
43
|
if (!session.isStreaming && session.retryAttempt === 0)
|
|
40
|
-
return { interrupted: false };
|
|
44
|
+
return { interrupted: false, ...nothing };
|
|
41
45
|
const turnId = String(session.externalAdmission.turnEpoch);
|
|
42
46
|
if (typeof requestedTurnId === "string" && requestedTurnId !== turnId)
|
|
43
|
-
return { interrupted: false, turnId };
|
|
47
|
+
return { interrupted: false, turnId, ...nothing };
|
|
44
48
|
await stop();
|
|
45
|
-
|
|
49
|
+
if (!stopsBackground)
|
|
50
|
+
return { interrupted: true, turnId };
|
|
51
|
+
return { interrupted: true, turnId, background: await session.stopRunBackgroundJobs(turnId) };
|
|
46
52
|
}
|
|
47
53
|
//# sourceMappingURL=session-control-actions-data.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type { ExecRequest as MachineExecRequest, ExecResult as MachineExecResult, ExecShell as MachineExecShell, MachineOps, OpContext, } from "../vendor/senpi-machine-ops/index.js";
|
|
2
|
+
export { type CoreBashToolOptions, createCoreBashTool, createCoreBashToolDefinition } from "./core/tools/bash-core.ts";
|
|
3
|
+
export type { BashToolDetails, BashToolInput, BashToolOutput } from "./core/tools/bash-schema.ts";
|
|
4
|
+
export { type CoreCodingToolsOptions, createCoreCodingTools } from "./core/tools/coding-tools-core.ts";
|
|
5
|
+
export { type CoreEditToolOptions, createCoreEditTool, createCoreEditToolDefinition, type EditOperations, type EditToolDetails, type EditToolInput, } from "./core/tools/edit-core.ts";
|
|
6
|
+
export type { FileMutationQueue, ToolPathCanonicalizer, ToolPathResolver } from "./core/tools/file-tool-host.ts";
|
|
7
|
+
export { createMachineOutputSpill } from "./core/tools/machine-output-spill.ts";
|
|
8
|
+
export type { FullOutput, OutputSpill, OutputSpillFactory } from "./core/tools/output-accumulator-core.ts";
|
|
9
|
+
export { type CoreReadToolOptions, createCoreReadTool, createCoreReadToolDefinition, type ReadImageProcessor, type ReadOperations, type ReadToolDetails, type ReadToolInput, } from "./core/tools/read-core.ts";
|
|
10
|
+
export { type BashOperations, createShellOperations, machineShellExecHost, type ShellExecHost, } from "./core/tools/shell-operations.ts";
|
|
11
|
+
export { createToolMachine, type ToolMachine, type ToolPathPolicy } from "./core/tools/tool-machine.ts";
|
|
12
|
+
export { type CoreWriteToolOptions, createCoreWriteTool, createCoreWriteToolDefinition, type WriteOperations, type WriteToolInput, } from "./core/tools/write-core.ts";
|
|
13
|
+
export type { WriteToolDetails } from "./core/tools/write-result.ts";
|
|
14
|
+
//# sourceMappingURL=tools-core.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createCoreBashTool, createCoreBashToolDefinition } from "./core/tools/bash-core.js";
|
|
2
|
+
export { createCoreCodingTools } from "./core/tools/coding-tools-core.js";
|
|
3
|
+
export { createCoreEditTool, createCoreEditToolDefinition, } from "./core/tools/edit-core.js";
|
|
4
|
+
export { createMachineOutputSpill } from "./core/tools/machine-output-spill.js";
|
|
5
|
+
export { createCoreReadTool, createCoreReadToolDefinition, } from "./core/tools/read-core.js";
|
|
6
|
+
export { createShellOperations, machineShellExecHost, } from "./core/tools/shell-operations.js";
|
|
7
|
+
export { createToolMachine } from "./core/tools/tool-machine.js";
|
|
8
|
+
export { createCoreWriteTool, createCoreWriteToolDefinition, } from "./core/tools/write-core.js";
|
|
9
|
+
//# sourceMappingURL=tools-core.js.map
|