@selesai/code 0.8.6 → 0.8.8
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 +31 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.js +11 -0
- package/dist/cli/args.test.d.ts +1 -0
- package/dist/cli/args.test.js +24 -0
- package/dist/core/agent-session.d.ts +4 -1
- package/dist/core/agent-session.js +18 -7
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.js +4 -0
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/keybindings.d.ts +24 -0
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.js +1 -0
- package/dist/core/project-trust.js +2 -2
- package/dist/core/provider-composer.js +17 -4
- package/dist/core/sdk.d.ts +5 -3
- package/dist/core/sdk.js +2 -1
- package/dist/core/session-manager.js +2 -2
- package/dist/core/settings-manager.d.ts +8 -0
- package/dist/core/settings-manager.js +15 -0
- package/dist/core/system-prompt.js +3 -9
- package/dist/core/system-prompt.test.js +6 -0
- package/dist/core/tools/bash.js +2 -0
- package/dist/core/tools/edit.js +2 -0
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/read.js +2 -0
- package/dist/core/tools/schema-prune.d.ts +16 -0
- package/dist/core/tools/schema-prune.js +39 -0
- package/dist/core/tools/schema-prune.test.d.ts +1 -0
- package/dist/core/tools/schema-prune.test.js +111 -0
- package/dist/core/tools/write.js +2 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/model-prompt-injector/config.json +10 -0
- package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
- package/dist/extensions/model-prompt-injector/index.ts +151 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
- package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
- package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
- package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/agents/worker.md +1 -1
- package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
- package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
- package/dist/extensions/pi-subagents/docs/missions.md +5 -3
- package/dist/extensions/pi-subagents/docs/models.md +1 -1
- package/dist/extensions/pi-subagents/docs/observability.md +42 -2
- package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
- package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
- package/dist/extensions/pi-subagents/install.mjs +2 -2
- package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
- package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
- package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
- package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
- package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
- package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +187 -41
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
- package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
- package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
- package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
- package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +395 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
- package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
- package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
- package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
- package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
- package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
- package/dist/extensions/question/index.ts +21 -6
- package/dist/extensions/question/question-list.ts +7 -1
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/exp.test.ts +70 -0
- package/dist/extensions/question/tests/exp2.test.ts +59 -0
- package/dist/extensions/question/tests/exp3.test.ts +47 -0
- package/dist/extensions/question/tests/helpers.test.ts +7 -0
- package/dist/extensions/question/tests/question-list.test.ts +140 -0
- package/dist/extensions/question/tests/row-layout.test.ts +13 -0
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
- package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
- package/dist/extensions/tokenin-onboarding.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/main.js +4 -0
- package/dist/modes/interactive/components/model-selector.js +2 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/tool-execution.js +10 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -2
- package/dist/modes/interactive/interactive-mode.js +81 -25
- package/dist/modes/interactive/model-catalog-refresh.d.ts +6 -0
- package/dist/modes/interactive/model-catalog-refresh.js +33 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +2 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.js +25 -11
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +5 -3
- package/dist/modes/interactive/theme/theme.js +12 -2
- package/dist/skills/pi-subagents/SKILL.md +1 -1
- package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/utils/abort.d.ts +4 -0
- package/dist/utils/abort.js +47 -0
- package/dist/utils/tools-manager.d.ts +5 -1
- package/dist/utils/tools-manager.js +12 -21
- package/docs/settings.md +6 -0
- package/package.json +6 -6
package/dist/core/tools/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { createFindTool, createFindToolDefinition, } from "./find.js";
|
|
|
5
5
|
export { createGrepTool, createGrepToolDefinition, } from "./grep.js";
|
|
6
6
|
export { createLsTool, createLsToolDefinition, } from "./ls.js";
|
|
7
7
|
export { createReadTool, createReadToolDefinition, } from "./read.js";
|
|
8
|
+
export { stripSchemaDescriptions, stripToolParameterDescriptions, } from "./schema-prune.js";
|
|
8
9
|
export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, truncateLine, truncateTail, } from "./truncate.js";
|
|
9
10
|
export { createWriteTool, createWriteToolDefinition, } from "./write.js";
|
|
10
11
|
import { createBashTool, createBashToolDefinition } from "./bash.js";
|
package/dist/core/tools/read.js
CHANGED
|
@@ -9,6 +9,7 @@ import { getLanguageFromPath, highlightCode } from "../../modes/interactive/them
|
|
|
9
9
|
import { processImage } from "../../utils/image-process.js";
|
|
10
10
|
import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
|
|
11
11
|
import { formatPathRelativeToCwdOrAbsolute } from "../../utils/paths.js";
|
|
12
|
+
import { getExperimentalToolSampling } from "../experimental.js";
|
|
12
13
|
import { resolveReadPathAsync, resolveToCwd } from "./path-utils.js";
|
|
13
14
|
import { getTextOutput, renderToolPath, replaceTabs, str } from "./render-utils.js";
|
|
14
15
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
@@ -137,6 +138,7 @@ export function createReadToolDefinition(cwd, options) {
|
|
|
137
138
|
promptSnippet: "Read file contents",
|
|
138
139
|
promptGuidelines: ["Use read to examine files instead of cat or sed."],
|
|
139
140
|
parameters: readSchema,
|
|
141
|
+
constrainedSampling: getExperimentalToolSampling(),
|
|
140
142
|
async execute(_toolCallId, { path, offset, limit }, signal, _onUpdate, ctx) {
|
|
141
143
|
return new Promise((resolve, reject) => {
|
|
142
144
|
if (signal?.aborted) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import type { TSchema } from "typebox";
|
|
3
|
+
/**
|
|
4
|
+
* Structural deep clone that omits every `description` key at any depth while
|
|
5
|
+
* preserving all other own keys (including TypeBox internals such as `~kind`
|
|
6
|
+
* and `~optional` symbols and function-valued keys). Uses Reflect.ownKeys +
|
|
7
|
+
* property descriptors so non-enumerable metadata survives; never mutates the
|
|
8
|
+
* input.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stripSchemaDescriptions<T>(value: T): T;
|
|
11
|
+
/**
|
|
12
|
+
* Returns a shallow copy of the tool with its parameter schema descriptions
|
|
13
|
+
* stripped. Top-level tool fields (name, description, execute, ...) are
|
|
14
|
+
* untouched.
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripToolParameterDescriptions<T extends TSchema>(tool: AgentTool<T>): AgentTool<T>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Memoized stripped clones, keyed by the original schema root. The input is
|
|
2
|
+
// never mutated; repeat calls return the same cached clone.
|
|
3
|
+
const strippedSchemaCache = new WeakMap();
|
|
4
|
+
/**
|
|
5
|
+
* Structural deep clone that omits every `description` key at any depth while
|
|
6
|
+
* preserving all other own keys (including TypeBox internals such as `~kind`
|
|
7
|
+
* and `~optional` symbols and function-valued keys). Uses Reflect.ownKeys +
|
|
8
|
+
* property descriptors so non-enumerable metadata survives; never mutates the
|
|
9
|
+
* input.
|
|
10
|
+
*/
|
|
11
|
+
export function stripSchemaDescriptions(value) {
|
|
12
|
+
if (!value || typeof value !== "object")
|
|
13
|
+
return value;
|
|
14
|
+
const cached = strippedSchemaCache.get(value);
|
|
15
|
+
if (cached !== undefined)
|
|
16
|
+
return cached;
|
|
17
|
+
const result = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
18
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
19
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
20
|
+
if (!descriptor)
|
|
21
|
+
continue;
|
|
22
|
+
if (key === "description")
|
|
23
|
+
continue;
|
|
24
|
+
if ("value" in descriptor) {
|
|
25
|
+
descriptor.value = stripSchemaDescriptions(descriptor.value);
|
|
26
|
+
}
|
|
27
|
+
Object.defineProperty(result, key, descriptor);
|
|
28
|
+
}
|
|
29
|
+
strippedSchemaCache.set(value, result);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns a shallow copy of the tool with its parameter schema descriptions
|
|
34
|
+
* stripped. Top-level tool fields (name, description, execute, ...) are
|
|
35
|
+
* untouched.
|
|
36
|
+
*/
|
|
37
|
+
export function stripToolParameterDescriptions(tool) {
|
|
38
|
+
return { ...tool, parameters: stripSchemaDescriptions(tool.parameters) };
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { Value } from "typebox/value";
|
|
4
|
+
import { SettingsManager } from "../settings-manager.js";
|
|
5
|
+
import { stripSchemaDescriptions, stripToolParameterDescriptions } from "./schema-prune.js";
|
|
6
|
+
describe("stripSchemaDescriptions", () => {
|
|
7
|
+
it("removes description keys at all depths (properties, anyOf arrays, items)", () => {
|
|
8
|
+
const schema = {
|
|
9
|
+
type: "object",
|
|
10
|
+
description: "root",
|
|
11
|
+
properties: {
|
|
12
|
+
name: { type: "string", description: "the name" },
|
|
13
|
+
tags: {
|
|
14
|
+
type: "array",
|
|
15
|
+
description: "the tags",
|
|
16
|
+
items: { type: "string", description: "a tag" },
|
|
17
|
+
},
|
|
18
|
+
choice: {
|
|
19
|
+
anyOf: [{ type: "string", description: "string branch" }, { type: "number" }],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const stripped = stripSchemaDescriptions(schema);
|
|
24
|
+
expect("description" in stripped).toBe(false);
|
|
25
|
+
expect("description" in stripped.properties).toBe(false);
|
|
26
|
+
expect("description" in stripped.properties.tags).toBe(false);
|
|
27
|
+
expect("description" in stripped.properties.tags.items).toBe(false);
|
|
28
|
+
expect("description" in stripped.properties.choice.anyOf[0]).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it("preserves non-description keys such as type, enum, required, minimum, additionalProperties", () => {
|
|
31
|
+
const schema = {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
level: { type: "string", enum: ["a", "b"], description: "level desc" },
|
|
35
|
+
count: { type: "integer", minimum: 1, description: "count desc" },
|
|
36
|
+
},
|
|
37
|
+
required: ["level"],
|
|
38
|
+
additionalProperties: false,
|
|
39
|
+
};
|
|
40
|
+
const stripped = stripSchemaDescriptions(schema);
|
|
41
|
+
expect(stripped).toEqual({
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
level: { type: "string", enum: ["a", "b"] },
|
|
45
|
+
count: { type: "integer", minimum: 1 },
|
|
46
|
+
},
|
|
47
|
+
required: ["level"],
|
|
48
|
+
additionalProperties: false,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it("never mutates the input schema", () => {
|
|
52
|
+
const schema = {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: { name: { type: "string", description: "the name" } },
|
|
55
|
+
};
|
|
56
|
+
const snapshot = structuredClone(schema);
|
|
57
|
+
stripSchemaDescriptions(schema);
|
|
58
|
+
expect(schema).toEqual(snapshot);
|
|
59
|
+
expect(schema.properties.name.description).toBe("the name");
|
|
60
|
+
});
|
|
61
|
+
it("memoizes stripped clones per original root", () => {
|
|
62
|
+
const schema = {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: { name: { type: "string", description: "the name" } },
|
|
65
|
+
};
|
|
66
|
+
const first = stripSchemaDescriptions(schema);
|
|
67
|
+
const second = stripSchemaDescriptions(schema);
|
|
68
|
+
expect(first).toBe(second);
|
|
69
|
+
});
|
|
70
|
+
it("keeps real TypeBox schemas valid after stripping (symbols survive)", () => {
|
|
71
|
+
const schema = Type.Object({
|
|
72
|
+
name: Type.String({ description: "the name" }),
|
|
73
|
+
age: Type.Optional(Type.Integer({ minimum: 0, description: "the age" })),
|
|
74
|
+
});
|
|
75
|
+
const stripped = stripSchemaDescriptions(schema);
|
|
76
|
+
expect(Value.Check(schema, { name: "pi", age: 3 })).toBe(true);
|
|
77
|
+
expect(Value.Check(stripped, { name: "pi", age: 3 })).toBe(true);
|
|
78
|
+
expect(Value.Check(stripped, { name: "pi", age: -1 })).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("stripToolParameterDescriptions", () => {
|
|
82
|
+
it("keeps the tool description and name while stripping parameter descriptions", () => {
|
|
83
|
+
const tool = {
|
|
84
|
+
name: "read",
|
|
85
|
+
label: "Read",
|
|
86
|
+
description: "Read a file",
|
|
87
|
+
parameters: {
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: { path: { type: "string", description: "file path" } },
|
|
90
|
+
},
|
|
91
|
+
execute: () => Promise.resolve({ content: [], details: {} }),
|
|
92
|
+
};
|
|
93
|
+
const stripped = stripToolParameterDescriptions(tool);
|
|
94
|
+
expect(stripped).not.toBe(tool);
|
|
95
|
+
expect(stripped.name).toBe("read");
|
|
96
|
+
expect(stripped.description).toBe("Read a file");
|
|
97
|
+
expect("description" in stripped.parameters.properties.path).toBe(false);
|
|
98
|
+
// Original tool is untouched.
|
|
99
|
+
expect("description" in tool.parameters.properties.path).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("pruneToolDescriptions setting", () => {
|
|
103
|
+
it("defaults to true", () => {
|
|
104
|
+
const manager = SettingsManager.inMemory();
|
|
105
|
+
expect(manager.getPruneToolDescriptions()).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
it("respects explicit true and false", () => {
|
|
108
|
+
expect(SettingsManager.inMemory({ pruneToolDescriptions: true }).getPruneToolDescriptions()).toBe(true);
|
|
109
|
+
expect(SettingsManager.inMemory({ pruneToolDescriptions: false }).getPruneToolDescriptions()).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
package/dist/core/tools/write.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname } from "path";
|
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
|
|
6
6
|
import { getLanguageFromPath, highlightCode } from "../../modes/interactive/theme/theme.js";
|
|
7
|
+
import { getExperimentalToolSampling } from "../experimental.js";
|
|
7
8
|
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
8
9
|
import { resolveToCwd } from "./path-utils.js";
|
|
9
10
|
import { normalizeDisplayText, renderToolPath, replaceTabs, str } from "./render-utils.js";
|
|
@@ -137,6 +138,7 @@ export function createWriteToolDefinition(cwd, options) {
|
|
|
137
138
|
promptSnippet: "Create or overwrite files",
|
|
138
139
|
promptGuidelines: ["Use write only for new files or complete rewrites."],
|
|
139
140
|
parameters: writeSchema,
|
|
141
|
+
constrainedSampling: getExperimentalToolSampling(),
|
|
140
142
|
async execute(_toolCallId, { path, content }, signal, _onUpdate, _ctx) {
|
|
141
143
|
const absolutePath = resolveToCwd(path, cwd);
|
|
142
144
|
const dir = dirname(absolutePath);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": [
|
|
3
|
+
{
|
|
4
|
+
"match": ["deepseek-v4-pro"],
|
|
5
|
+
"mode": "prepend",
|
|
6
|
+
"prompt": "text: You are a helpful software engineer assistant.\n\ndescription: Bootstrap with shell/read, then expose the full Standard tool catalog after the first durable tool call.\n\nwhen you thought, start with `we need...`",
|
|
7
|
+
"enabled": true
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { ExtensionAPI } from "@selesai/code";
|
|
3
|
+
import modelPromptInjector, {
|
|
4
|
+
findRule,
|
|
5
|
+
patternMatches,
|
|
6
|
+
type InjectConfig,
|
|
7
|
+
type InjectRule,
|
|
8
|
+
type ModelRef,
|
|
9
|
+
} from "./index.ts";
|
|
10
|
+
|
|
11
|
+
const model = (provider: string, id: string, name = id): ModelRef => ({ provider, id, name });
|
|
12
|
+
|
|
13
|
+
function harness(config: InjectConfig, activeModel: ModelRef | undefined) {
|
|
14
|
+
const handlers: Record<string, Function> = {};
|
|
15
|
+
const pi = {
|
|
16
|
+
on: vi.fn((event: string, handler: Function) => {
|
|
17
|
+
handlers[event] = handler;
|
|
18
|
+
}),
|
|
19
|
+
} as unknown as ExtensionAPI;
|
|
20
|
+
const ctx = {
|
|
21
|
+
model: activeModel,
|
|
22
|
+
ui: { setStatus: vi.fn() },
|
|
23
|
+
};
|
|
24
|
+
modelPromptInjector(pi, config);
|
|
25
|
+
return { handlers, ctx };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("patternMatches", () => {
|
|
29
|
+
it("matches provider/model exactly, case-insensitively", () => {
|
|
30
|
+
expect(patternMatches("deepseek/deepseek-v4-pro", model("DeepSeek", "deepseek-v4-pro"))).toBe(true);
|
|
31
|
+
expect(patternMatches("deepseek/deepseek-v4-pro", model("openrouter", "deepseek-v4-pro"))).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("supports wildcards in provider and id", () => {
|
|
35
|
+
expect(patternMatches("*/deepseek-v4-pro", model("openrouter", "deepseek-v4-pro"))).toBe(true);
|
|
36
|
+
expect(patternMatches("deepseek/*", model("deepseek", "deepseek-v4-pro"))).toBe(true);
|
|
37
|
+
expect(patternMatches("deepseek/*", model("deepseek", "deepseek-chat"))).toBe(true);
|
|
38
|
+
expect(patternMatches("deepseek/*", model("openai", "gpt-5"))).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("bare patterns match id or display name", () => {
|
|
42
|
+
expect(patternMatches("deepseek-v4-pro", model("deepseek", "deepseek-v4-pro"))).toBe(true);
|
|
43
|
+
expect(patternMatches("gpt-*", model("openai", "gpt-5", "GPT-5"))).toBe(true);
|
|
44
|
+
expect(patternMatches("deepseek*", model("deepseek", "deepseek-v4-pro"))).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("matches * against any model", () => {
|
|
48
|
+
expect(patternMatches("*", model("openai", "gpt-5"))).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("findRule", () => {
|
|
53
|
+
const rules: InjectRule[] = [
|
|
54
|
+
{ match: ["deepseek/*"], prompt: "A" },
|
|
55
|
+
{ match: ["*/deepseek-v4-pro"], prompt: "B" },
|
|
56
|
+
{ match: ["*"], prompt: "C", enabled: false },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
it("first matching rule wins", () => {
|
|
60
|
+
expect(findRule(rules, model("deepseek", "deepseek-v4-pro"))?.prompt).toBe("A");
|
|
61
|
+
expect(findRule(rules, model("openrouter", "deepseek-v4-pro"))?.prompt).toBe("B");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("skips disabled rules", () => {
|
|
65
|
+
expect(findRule([{ match: ["*"], prompt: "C", enabled: false }], model("openai", "gpt-5"))).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe("before_agent_start", () => {
|
|
70
|
+
it("appends the rule prompt to the system prompt", async () => {
|
|
71
|
+
const { handlers, ctx } = harness({ rules: [{ match: ["deepseek/*"], prompt: "EXTRA" }] }, model("deepseek", "deepseek-chat"));
|
|
72
|
+
const result = await handlers["before_agent_start"]({ systemPrompt: "BASE" }, ctx);
|
|
73
|
+
expect(result).toEqual({ systemPrompt: "BASE\n\nEXTRA" });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("prepends the rule prompt to the top of the system prompt", async () => {
|
|
77
|
+
const { handlers, ctx } = harness(
|
|
78
|
+
{ rules: [{ match: ["deepseek/*"], prompt: "TOP", mode: "prepend" }] },
|
|
79
|
+
model("deepseek", "deepseek-chat"),
|
|
80
|
+
);
|
|
81
|
+
const result = await handlers["before_agent_start"]({ systemPrompt: "BASE" }, ctx);
|
|
82
|
+
expect(result).toEqual({ systemPrompt: "TOP\n\nBASE" });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("replaces the system prompt in replace mode", async () => {
|
|
86
|
+
const { handlers, ctx } = harness(
|
|
87
|
+
{ rules: [{ match: ["deepseek/*"], prompt: "ONLY ME", mode: "replace" }] },
|
|
88
|
+
model("deepseek", "deepseek-chat"),
|
|
89
|
+
);
|
|
90
|
+
const result = await handlers["before_agent_start"]({ systemPrompt: "BASE" }, ctx);
|
|
91
|
+
expect(result).toEqual({ systemPrompt: "ONLY ME" });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("returns undefined when no rule matches", async () => {
|
|
95
|
+
const { handlers, ctx } = harness(
|
|
96
|
+
{ rules: [{ match: ["deepseek/*"], prompt: "EXTRA" }] },
|
|
97
|
+
model("openai", "gpt-5"),
|
|
98
|
+
);
|
|
99
|
+
const result = await handlers["before_agent_start"]({ systemPrompt: "BASE" }, ctx);
|
|
100
|
+
expect(result).toBeUndefined();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe("model_select", () => {
|
|
105
|
+
it("shows status when the selected model matches, clears otherwise", async () => {
|
|
106
|
+
const { handlers, ctx } = harness({ rules: [{ match: ["deepseek/*"], prompt: "EXTRA" }] }, undefined);
|
|
107
|
+
await handlers["model_select"]({ model: model("deepseek", "deepseek-chat") }, ctx);
|
|
108
|
+
expect(ctx.ui.setStatus).toHaveBeenLastCalledWith("model-prompt-injector", "prompt-inject: active");
|
|
109
|
+
await handlers["model_select"]({ model: model("openai", "gpt-5") }, ctx);
|
|
110
|
+
expect(ctx.ui.setStatus).toHaveBeenLastCalledWith("model-prompt-injector", undefined);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* model-prompt-injector
|
|
3
|
+
*
|
|
4
|
+
* Injects a model-specific prompt into the system prompt whenever the active
|
|
5
|
+
* model matches a rule in config.json (sibling of this file).
|
|
6
|
+
*
|
|
7
|
+
* Config lives only here in host code — nothing is exposed to user settings.
|
|
8
|
+
* `/reload` re-reads it.
|
|
9
|
+
*
|
|
10
|
+
* config.json format:
|
|
11
|
+
* {
|
|
12
|
+
* "rules": [
|
|
13
|
+
* {
|
|
14
|
+
* "match": ["provider/model", "provider/*", "<any>/model", "bare-name", "*"],
|
|
15
|
+
* "mode": "prepend" | "append" | "replace", // default: "append"
|
|
16
|
+
* "prompt": "...",
|
|
17
|
+
* "enabled": true // default: true
|
|
18
|
+
* }
|
|
19
|
+
* ]
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* Matching (case-insensitive, "*" is a wildcard):
|
|
23
|
+
* - "provider/model" — glob against `<provider>/<id>`.
|
|
24
|
+
* - bare pattern (no "/") — glob against model id OR display name.
|
|
25
|
+
* - First matching rule wins; later rules are ignored.
|
|
26
|
+
* - mode "prepend" puts the prompt at the very top of the system prompt;
|
|
27
|
+
* mode "append" adds it to the end; mode "replace" replaces the whole system prompt.
|
|
28
|
+
*/
|
|
29
|
+
import { readFileSync } from "node:fs";
|
|
30
|
+
import { dirname, join } from "node:path";
|
|
31
|
+
import { fileURLToPath } from "node:url";
|
|
32
|
+
import type { ExtensionAPI } from "@selesai/code";
|
|
33
|
+
|
|
34
|
+
export type InjectMode = "prepend" | "append" | "replace";
|
|
35
|
+
|
|
36
|
+
export interface InjectRule {
|
|
37
|
+
match: string[];
|
|
38
|
+
prompt: string;
|
|
39
|
+
mode?: InjectMode;
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface InjectConfig {
|
|
44
|
+
rules: InjectRule[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Model shape needed for matching (structurally compatible with pi's Model). */
|
|
48
|
+
export interface ModelRef {
|
|
49
|
+
provider: string;
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const CONFIG_PATH = join(dirname(fileURLToPath(import.meta.url)), "config.json");
|
|
55
|
+
|
|
56
|
+
function globToRegex(glob: string): RegExp {
|
|
57
|
+
const escaped = glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
58
|
+
return new RegExp(`^${escaped}$`, "i");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function patternMatches(pattern: string, model: ModelRef): boolean {
|
|
62
|
+
const slash = pattern.indexOf("/");
|
|
63
|
+
if (slash >= 0) {
|
|
64
|
+
return (
|
|
65
|
+
globToRegex(pattern.slice(0, slash)).test(model.provider) &&
|
|
66
|
+
globToRegex(pattern.slice(slash + 1)).test(model.id)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return globToRegex(pattern).test(model.id) || globToRegex(pattern).test(model.name);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function findRule(rules: readonly InjectRule[], model: ModelRef): InjectRule | undefined {
|
|
73
|
+
for (const rule of rules) {
|
|
74
|
+
if (rule.enabled === false) continue;
|
|
75
|
+
if (rule.match.some((pattern) => patternMatches(pattern, model))) return rule;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function loadConfig(path: string = CONFIG_PATH): InjectConfig {
|
|
81
|
+
const fail = (message: string): InjectConfig => {
|
|
82
|
+
console.error(`[model-prompt-injector] ${message}`);
|
|
83
|
+
return { rules: [] };
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
let raw: unknown;
|
|
87
|
+
try {
|
|
88
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return fail(`cannot load ${path}: ${(error as Error).message}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (typeof raw !== "object" || raw === null || !Array.isArray((raw as { rules?: unknown }).rules)) {
|
|
94
|
+
return fail(`invalid config: expected { "rules": [...] }`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const rules: InjectRule[] = [];
|
|
98
|
+
for (const [index, entry] of (raw as { rules: unknown[] }).rules.entries()) {
|
|
99
|
+
const label = `rule #${index + 1}`;
|
|
100
|
+
if (typeof entry !== "object" || entry === null) {
|
|
101
|
+
console.error(`[model-prompt-injector] ${label} is not an object — skipped`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const rule = entry as Partial<InjectRule>;
|
|
105
|
+
if (!Array.isArray(rule.match) || rule.match.length === 0 || !rule.match.every((m) => typeof m === "string")) {
|
|
106
|
+
console.error(`[model-prompt-injector] ${label} needs a non-empty "match" string array — skipped`);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (typeof rule.prompt !== "string" || rule.prompt.trim() === "") {
|
|
110
|
+
console.error(`[model-prompt-injector] ${label} needs a non-empty "prompt" string — skipped`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (rule.mode !== undefined && rule.mode !== "prepend" && rule.mode !== "append" && rule.mode !== "replace") {
|
|
114
|
+
console.error(`[model-prompt-injector] ${label}: "mode" must be "prepend", "append" or "replace" — skipped`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
rules.push({
|
|
118
|
+
match: rule.match,
|
|
119
|
+
prompt: rule.prompt,
|
|
120
|
+
mode: rule.mode ?? "append",
|
|
121
|
+
enabled: rule.enabled ?? true,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return { rules };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default function modelPromptInjector(pi: ExtensionAPI, config: InjectConfig = loadConfig()) {
|
|
128
|
+
const ruleFor = (model: ModelRef | undefined): InjectRule | undefined =>
|
|
129
|
+
model ? findRule(config.rules, model) : undefined;
|
|
130
|
+
|
|
131
|
+
const active = config.rules.filter((rule) => rule.enabled !== false);
|
|
132
|
+
if (active.length > 0) {
|
|
133
|
+
console.log(
|
|
134
|
+
`[model-prompt-injector] ${active.length} rule(s) active: ${active
|
|
135
|
+
.map((rule) => rule.match.join(","))
|
|
136
|
+
.join(" | ")}`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
141
|
+
const rule = ruleFor(ctx.model);
|
|
142
|
+
if (!rule) return;
|
|
143
|
+
if (rule.mode === "replace") return { systemPrompt: rule.prompt };
|
|
144
|
+
if (rule.mode === "prepend") return { systemPrompt: `${rule.prompt}\n\n${event.systemPrompt}` };
|
|
145
|
+
return { systemPrompt: `${event.systemPrompt}\n\n${rule.prompt}` };
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
pi.on("model_select", async (event, ctx) => {
|
|
149
|
+
ctx.ui.setStatus("model-prompt-injector", ruleFor(event.model) ? "prompt-inject: active" : undefined);
|
|
150
|
+
});
|
|
151
|
+
}
|