Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/coding-agent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Changed

- `ExtensionContext.kernelTools` is typed as the shipped kernel-tools surface: `invoke(request, options?)` accepts `{ signal?, scope? }` (a bare `AbortSignal` still works) and `capabilities.invokeScope` is present. Coding-agent owns `ExtensionKernelTools`, `KernelToolInvokeOptions`, and `KernelToolInvokeScope`; senpi-codemode binds its implementation to those types so they cannot drift ([#1731](https://github.com/code-yeongyu/senpi/issues/1731)).

### Fixed

### Removed
Expand Down
18 changes: 18 additions & 0 deletions packages/coding-agent/src/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# changes

## 2026-09-16 - Type kernelTools as the shipped invoke-scope surface (senpi#1731)

### What changed

- `packages/coding-agent/src/index.ts` exports `ExtensionKernelTools`, `KernelToolInvokeOptions`, and `KernelToolInvokeScope` as the public shipped kernel-tools surface.

### Why

- `packages/coding-agent/src/index.ts` is the public `@code-yeongyu/senpi` surface; typed consumers of `kernelTools` were still on the pre-#1765 `AbortSignal`-only declaration.

### Why an extension could not handle it

- Package index re-exports are owned by coding-agent; an extension cannot change the published host type.

### Expected merge conflict zones

- `packages/coding-agent/src/index.ts` adjacent to the `kernelToolsStorage` export.

## 2026-09-16 - Answer `--help` without booting the engine (oh-my-openagent#8371)

### What changed
Expand Down
19 changes: 19 additions & 0 deletions packages/coding-agent/src/core/extensions/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Core Extensions Changes

## 2026-09-16 - Type kernelTools as the shipped invoke-scope surface (senpi#1731)

### What changed

- `packages/coding-agent/src/core/extensions/types.ts` types `ExtensionContext.kernelTools` as `ExtensionKernelTools` instead of a hand-written `invoke(request, signal?: AbortSignal)` copy.
- `packages/coding-agent/src/core/extensions/kernel-tools-context.ts` owns `ExtensionKernelTools`, `KernelToolInvokeOptions`, and `KernelToolInvokeScope`: `invoke` accepts `{ signal?, scope? }` (bare `AbortSignal` still typed) and `capabilities.invokeScope` is present.

### Why

- `packages/coding-agent/src/core/extensions/types.ts` is the public `ExtensionContext` contract; coding-agent is the lower layer and must declare the shipped kernel-tools surface rather than import it from senpi-codemode.

### Why an extension could not handle it

- `packages/coding-agent/src/core/extensions/types.ts` owns `ExtensionContext`; an extension cannot replace the host's published type.

### Expected merge conflict zones

- `packages/coding-agent/src/core/extensions/types.ts` after `steeringSignal`; `packages/coding-agent/src/core/extensions/kernel-tools-context.ts` `ExtensionKernelTools` declaration.

## 2026-09-16 - Host budget for session_shutdown handlers (senpi#1732)

### What changed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { AsyncLocalStorage } from "node:async_hooks";

/** Host tools a kernel-tool invocation's nested calls may reach. `deny` wins when both name the same tool. */
export type KernelToolInvokeScope = {
tools?: {
allow?: string[];
deny?: string[];
};
};

export type KernelToolInvokeOptions = {
signal?: AbortSignal;
scope?: KernelToolInvokeScope;
};

export type ExtensionKernelTools = {
readonly capabilities: {
readonly invokeScope: boolean;
};
describe(names: readonly string[]): Promise<unknown>;
invoke(
request: {
Expand All @@ -10,7 +26,7 @@ export type ExtensionKernelTools = {
args: unknown;
call_id: string;
},
signal?: AbortSignal,
options?: AbortSignal | KernelToolInvokeOptions,
): Promise<unknown>;
};

Expand Down
15 changes: 2 additions & 13 deletions packages/coding-agent/src/core/extensions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import type {
} from "../tools/index.ts";
import type { ReadClassifier } from "../tools/read-classifiers.ts";
import type { McpServerDeclaration } from "./builtin/mcp/config-schema.ts";
import type { ExtensionKernelTools } from "./kernel-tools-context.ts";

export type { ExecOptions, ExecResult } from "../exec.ts";
export type { AppKeybinding, KeybindingsManager } from "../keybindings.ts";
Expand Down Expand Up @@ -489,19 +490,7 @@ export interface ExtensionContext {
* Transient parent JS kernel-tool capability. Present only while a supported
* JavaScript eval owns the host-tool context; absent on older runtimes.
*/
readonly kernelTools?: {
describe(names: readonly string[]): Promise<unknown>;
invoke(
request: {
name: string;
kernel_generation: number;
definition_revision: number;
args: unknown;
call_id: string;
},
signal?: AbortSignal,
): Promise<unknown>;
};
readonly kernelTools?: ExtensionKernelTools;
/** Abort the current agent operation */
abort(source?: "user" | "system"): void;
/** Whether there are queued messages waiting */
Expand Down
7 changes: 6 additions & 1 deletion packages/coding-agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,12 @@ export {
wrapRegisteredTool,
wrapRegisteredTools,
} from "./core/extensions/index.ts";
export { type ExtensionKernelTools, kernelToolsStorage } from "./core/extensions/kernel-tools-context.ts";
export {
type ExtensionKernelTools,
type KernelToolInvokeOptions,
type KernelToolInvokeScope,
kernelToolsStorage,
} from "./core/extensions/kernel-tools-context.ts";
// Notice primitives
export {
buildNoticeBox,
Expand Down
22 changes: 22 additions & 0 deletions packages/coding-agent/test/extension-kernel-tools-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Compile-only fixture: `ExtensionContext.kernelTools` must match the shipped
* kernel-tools surface (invoke scope options + capabilities.invokeScope).
*/
import type { ExtensionContext } from "../src/core/extensions/types.ts";

const request = {
name: "fn",
kernel_generation: 0,
definition_revision: 0,
args: {},
call_id: "call",
};

export function assertShippedKernelToolsSurface(ctx: ExtensionContext): void {
const kernelTools = ctx.kernelTools;
if (!kernelTools) return;
void kernelTools.invoke(request, { scope: { tools: { deny: ["write"] } } });
void kernelTools.invoke(request, AbortSignal.abort());
const invokeScope: boolean = kernelTools.capabilities.invokeScope;
void invokeScope;
}
2 changes: 2 additions & 0 deletions packages/senpi-codemode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

### Changed

- Kernel-tools types bind to coding-agent's `ExtensionKernelTools` / `KernelToolInvokeOptions` / `KernelToolInvokeScope` (`KERNEL_TOOLS_CAPABILITIES satisfies ExtensionKernelTools["capabilities"]`) so the implementation cannot drift from the host declaration ([#1731](https://github.com/code-yeongyu/senpi/issues/1731)).

### Fixed

### Removed
Expand Down
19 changes: 19 additions & 0 deletions packages/senpi-codemode/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# senpi-codemode fork changes

## 2026-09-16 - Bind kernel-tools types to the host declaration (senpi#1731)

### What changed

- `src/kernels/js/kernel-tools-types.ts` aliases `KernelToolsInvokeOptions` / `KernelToolsInvokeScope` / `KernelToolsHostScope` from `@code-yeongyu/senpi`'s `KernelToolInvokeOptions` / `KernelToolInvokeScope`, types `KernelToolsCapability` as `ExtensionKernelTools`, and `KERNEL_TOOLS_CAPABILITIES satisfies ExtensionKernelTools["capabilities"]`.
- `src/tool/run-eval-cell.ts` types the cell capability object with `satisfies ExtensionKernelTools`.

### Why

- Coding-agent owns the public `ExtensionContext.kernelTools` declaration; this package implements it. Importing the host types here is the drift check (#1731).

### Why an extension could not handle it

- The capability object is constructed by the codemode kernel and published onto the host `kernelToolsStorage`; only this package can bind that object to the host type.

### Expected merge conflict zones

- LOW: `src/kernels/js/kernel-tools-types.ts`, `src/tool/run-eval-cell.ts`.

## 2026-09-16 - Call-scoped host-tool policy for kernel-tool invoke (#1731)

### What changed
Expand Down
35 changes: 11 additions & 24 deletions packages/senpi-codemode/src/kernels/js/kernel-tools-types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ExtensionKernelTools, KernelToolInvokeOptions, KernelToolInvokeScope } from "@code-yeongyu/senpi";
import type { KernelToolErrorCode, KernelToolHostDenial, KernelToolHostDenialReason } from "./kernel-tools-errors.ts";

export type { KernelToolErrorCode, KernelToolHostDenial, KernelToolHostDenialReason };
Expand Down Expand Up @@ -31,36 +32,22 @@ export type KernelToolsDescribeResult = {
readonly results: readonly KernelToolsDescribeEntry[];
};

/**
* Host tools a kernel-tool invocation's nested calls may reach: `allow` narrows to exactly those
* names, `deny` refuses the named ones, and `deny` wins where both name the same tool.
*/
export type KernelToolsHostScope = {
readonly allow?: readonly string[];
readonly deny?: readonly string[];
};

/** Execution scope for one `invoke`; never persisted, dropped when that call settles (#1731). */
export type KernelToolsInvokeScope = {
readonly tools?: KernelToolsHostScope;
};

export type KernelToolsInvokeOptions = {
readonly signal?: AbortSignal;
readonly scope?: KernelToolsInvokeScope;
};
/** Host declaration (#1731); aliases so this package cannot drift from `@code-yeongyu/senpi`. */
export type KernelToolsHostScope = NonNullable<KernelToolInvokeScope["tools"]>;
export type KernelToolsInvokeScope = KernelToolInvokeScope;
export type KernelToolsInvokeOptions = KernelToolInvokeOptions;

/** Stable capability markers a consumer gates on before sending an option this runtime may not know. */
export type KernelToolsCapabilities = {
readonly invokeScope: true;
};
export type KernelToolsCapabilities = ExtensionKernelTools["capabilities"];

export const KERNEL_TOOLS_CAPABILITIES: KernelToolsCapabilities = Object.freeze({ invokeScope: true });
export const KERNEL_TOOLS_CAPABILITIES = Object.freeze({
invokeScope: true as const,
}) satisfies ExtensionKernelTools["capabilities"];

export type KernelToolsCapability = {
readonly capabilities: KernelToolsCapabilities;
readonly capabilities: ExtensionKernelTools["capabilities"];
describe(names: readonly string[]): Promise<KernelToolsDescribeResult>;
invoke(request: KernelToolsInvokeRequest, options?: AbortSignal | KernelToolsInvokeOptions): Promise<unknown>;
invoke: ExtensionKernelTools["invoke"];
};

export const KERNEL_TOOLS_UNSUPPORTED = {
Expand Down
19 changes: 14 additions & 5 deletions packages/senpi-codemode/src/tool/run-eval-cell.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { randomUUID } from "node:crypto";
import { join } from "node:path";
import { type AgentToolResult, type ExtensionContext, kernelToolsStorage } from "@code-yeongyu/senpi";
import {
type AgentToolResult,
type ExtensionContext,
type ExtensionKernelTools,
kernelToolsStorage,
} from "@code-yeongyu/senpi";
import { DEFAULT_FOREGROUND_WINDOW_SECONDS, defaultCodemodeSettings } from "../config/settings.ts";
import { KERNEL_TOOLS_CAPABILITIES, type KernelToolsCapability } from "../kernels/js/kernel-tools-types.ts";
import {
KERNEL_TOOLS_CAPABILITIES,
type KernelToolsCapability,
type KernelToolsDescribeResult,
} from "../kernels/js/kernel-tools-types.ts";
import { TIMEOUT_PAUSE_OP, TIMEOUT_RESUME_OP } from "../timeouts/bridge-timeout.ts";
import { abortError, CellExecution, defaultTimeoutFactory } from "./cell-execution.ts";
import { CellHandler, type CellState } from "./cell-handler.ts";
Expand Down Expand Up @@ -220,12 +229,12 @@ function jsKernelTools(kernel: EvalKernel, language: string): KernelToolsCapabil
if (language !== "js") return undefined;
if (!("describeKernelTools" in kernel) || typeof kernel.describeKernelTools !== "function") return undefined;
const js = kernel as EvalKernel & {
describeKernelTools: KernelToolsCapability["describe"];
invokeKernelTool: KernelToolsCapability["invoke"];
describeKernelTools: (names: readonly string[]) => Promise<KernelToolsDescribeResult>;
invokeKernelTool: ExtensionKernelTools["invoke"];
};
return {
capabilities: KERNEL_TOOLS_CAPABILITIES,
describe: (names) => js.describeKernelTools(names),
invoke: (request, options) => js.invokeKernelTool(request, options),
};
} satisfies ExtensionKernelTools;
}