@oh-my-pi/pi-coding-agent 16.0.5 → 16.0.6
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 +53 -0
- package/dist/cli.js +1927 -1376
- package/dist/types/advisor/advise-tool.d.ts +22 -19
- package/dist/types/autoresearch/tools/init-experiment.d.ts +13 -17
- package/dist/types/autoresearch/tools/log-experiment.d.ts +17 -19
- package/dist/types/autoresearch/tools/run-experiment.d.ts +3 -4
- package/dist/types/autoresearch/tools/update-notes.d.ts +4 -5
- package/dist/types/cli/ttsr-cli.d.ts +39 -0
- package/dist/types/commands/ttsr.d.ts +57 -0
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +4 -5
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +4 -5
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +5 -6
- package/dist/types/commit/agentic/tools/git-overview.d.ts +4 -5
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +23 -24
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +11 -32
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +3 -4
- package/dist/types/commit/agentic/tools/schemas.d.ts +6 -27
- package/dist/types/commit/agentic/tools/split-commit.d.ts +28 -49
- package/dist/types/commit/changelog/generate.d.ts +12 -13
- package/dist/types/commit/shared-llm.d.ts +10 -37
- package/dist/types/config/config-file.d.ts +4 -4
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/models-config-schema.d.ts +625 -990
- package/dist/types/config/models-config.d.ts +229 -217
- package/dist/types/config/settings-schema.d.ts +53 -23
- package/dist/types/edit/hashline/params.d.ts +7 -11
- package/dist/types/edit/index.d.ts +2 -1
- package/dist/types/edit/modes/apply-patch.d.ts +4 -5
- package/dist/types/edit/modes/patch.d.ts +15 -24
- package/dist/types/edit/modes/replace.d.ts +16 -17
- package/dist/types/eval/js/index.d.ts +1 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +6 -3
- package/dist/types/extensibility/custom-tools/types.d.ts +8 -5
- package/dist/types/extensibility/extensions/types.d.ts +6 -3
- package/dist/types/extensibility/hooks/types.d.ts +7 -4
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +13 -5
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +17 -0
- package/dist/types/extensibility/typebox.d.ts +80 -58
- package/dist/types/goals/tools/goal-tool.d.ts +11 -24
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lsp/index.d.ts +11 -26
- package/dist/types/lsp/types.d.ts +12 -28
- package/dist/types/mcp/client.d.ts +8 -0
- package/dist/types/modes/components/btw-panel.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -1
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/setup-wizard/index.d.ts +1 -0
- package/dist/types/modes/setup-wizard/startup-splash.d.ts +7 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +3 -0
- package/dist/types/sdk.d.ts +5 -0
- package/dist/types/session/agent-session.d.ts +4 -0
- package/dist/types/startup-splash.d.ts +12 -0
- package/dist/types/task/types.d.ts +47 -48
- package/dist/types/tools/ask.d.ts +26 -27
- package/dist/types/tools/ast-edit.d.ts +17 -17
- package/dist/types/tools/ast-grep.d.ts +12 -13
- package/dist/types/tools/bash.d.ts +20 -17
- package/dist/types/tools/browser.d.ts +46 -71
- package/dist/types/tools/checkpoint.d.ts +14 -15
- package/dist/types/tools/debug.d.ts +82 -145
- package/dist/types/tools/eval.d.ts +30 -40
- package/dist/types/tools/find.d.ts +17 -18
- package/dist/types/tools/gh.d.ts +49 -78
- package/dist/types/tools/image-gen.d.ts +20 -36
- package/dist/types/tools/inspect-image.d.ts +10 -11
- package/dist/types/tools/irc.d.ts +22 -33
- package/dist/types/tools/job.d.ts +11 -12
- package/dist/types/tools/learn.d.ts +21 -28
- package/dist/types/tools/manage-skill.d.ts +13 -22
- package/dist/types/tools/memory-edit.d.ts +15 -24
- package/dist/types/tools/memory-recall.d.ts +7 -8
- package/dist/types/tools/memory-reflect.d.ts +9 -10
- package/dist/types/tools/memory-retain.d.ts +13 -14
- package/dist/types/tools/read.d.ts +7 -8
- package/dist/types/tools/resolve.d.ts +11 -18
- package/dist/types/tools/review.d.ts +9 -15
- package/dist/types/tools/search-tool-bm25.d.ts +9 -10
- package/dist/types/tools/search.d.ts +16 -17
- package/dist/types/tools/ssh.d.ts +14 -15
- package/dist/types/tools/todo.d.ts +27 -43
- package/dist/types/tools/tts.d.ts +8 -9
- package/dist/types/tools/write.d.ts +9 -10
- package/dist/types/tui/index.d.ts +1 -0
- package/dist/types/tui/width-aware-text.d.ts +23 -0
- package/dist/types/utils/markit.d.ts +10 -1
- package/dist/types/web/search/index.d.ts +17 -28
- package/dist/types/web/search/providers/perplexity.d.ts +0 -2
- package/dist/types/web/search/types.d.ts +32 -26
- package/package.json +14 -13
- package/scripts/omp +1 -1
- package/src/advisor/__tests__/advisor.test.ts +44 -1
- package/src/advisor/advise-tool.ts +34 -11
- package/src/autoresearch/tools/init-experiment.ts +13 -16
- package/src/autoresearch/tools/log-experiment.ts +15 -18
- package/src/autoresearch/tools/run-experiment.ts +3 -3
- package/src/autoresearch/tools/update-notes.ts +4 -4
- package/src/cli/ttsr-cli.ts +995 -0
- package/src/cli-commands.ts +1 -0
- package/src/cli.ts +7 -1
- package/src/commands/ttsr.ts +125 -0
- package/src/commit/agentic/tools/analyze-file.ts +4 -4
- package/src/commit/agentic/tools/git-file-diff.ts +4 -4
- package/src/commit/agentic/tools/git-hunk.ts +7 -5
- package/src/commit/agentic/tools/git-overview.ts +4 -4
- package/src/commit/agentic/tools/propose-changelog.ts +18 -15
- package/src/commit/agentic/tools/propose-commit.ts +6 -6
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/schemas.ts +8 -20
- package/src/commit/agentic/tools/split-commit.ts +19 -23
- package/src/commit/analysis/summary.ts +7 -5
- package/src/commit/changelog/generate.ts +15 -11
- package/src/commit/shared-llm.ts +17 -24
- package/src/config/config-file.ts +13 -15
- package/src/config/keybindings.ts +6 -0
- package/src/config/models-config-schema.ts +206 -179
- package/src/config/settings-schema.ts +34 -0
- package/src/discovery/builtin-rules/index.ts +2 -0
- package/src/discovery/builtin-rules/ts-import-type.md +2 -2
- package/src/discovery/builtin-rules/ts-no-any.md +11 -2
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +55 -0
- package/src/edit/hashline/params.ts +12 -11
- package/src/edit/index.ts +5 -4
- package/src/edit/modes/apply-patch.ts +4 -4
- package/src/edit/modes/patch.ts +15 -18
- package/src/edit/modes/replace.ts +13 -17
- package/src/edit/renderer.ts +0 -1
- package/src/eval/agent-bridge.ts +11 -13
- package/src/eval/completion-bridge.ts +25 -17
- package/src/eval/js/context-manager.ts +17 -2
- package/src/eval/js/index.ts +1 -1
- package/src/eval/py/executor.ts +2 -2
- package/src/extensibility/custom-commands/loader.ts +5 -3
- package/src/extensibility/custom-commands/types.ts +6 -3
- package/src/extensibility/custom-tools/loader.ts +4 -2
- package/src/extensibility/custom-tools/types.ts +8 -5
- package/src/extensibility/extensions/loader.ts +4 -2
- package/src/extensibility/extensions/types.ts +6 -3
- package/src/extensibility/hooks/loader.ts +5 -2
- package/src/extensibility/hooks/types.ts +7 -4
- package/src/extensibility/legacy-pi-ai-shim.ts +42 -5
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +113 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +13 -13
- package/src/extensibility/tool-proxy.ts +4 -1
- package/src/extensibility/typebox.ts +778 -251
- package/src/goals/guided-setup.ts +12 -3
- package/src/goals/tools/goal-tool.ts +6 -6
- package/src/index.ts +2 -0
- package/src/internal-urls/docs-index.generated.ts +11 -9
- package/src/lsp/types.ts +13 -27
- package/src/main.ts +19 -18
- package/src/mcp/client.ts +38 -13
- package/src/mcp/render.ts +102 -89
- package/src/modes/components/agent-hub.ts +11 -4
- package/src/modes/components/btw-panel.ts +5 -1
- package/src/modes/components/custom-editor.ts +18 -0
- package/src/modes/components/status-line/component.ts +8 -1
- package/src/modes/components/tool-execution.ts +17 -10
- package/src/modes/controllers/btw-controller.ts +69 -1
- package/src/modes/controllers/input-controller.ts +29 -0
- package/src/modes/interactive-mode.ts +38 -8
- package/src/modes/setup-wizard/index.ts +1 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +77 -5
- package/src/modes/setup-wizard/startup-splash.ts +107 -0
- package/src/modes/theme/theme.ts +133 -143
- package/src/modes/types.ts +3 -0
- package/src/modes/utils/context-usage.ts +9 -5
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/sdk.ts +21 -4
- package/src/session/agent-session.ts +160 -33
- package/src/session/session-history-format.ts +11 -2
- package/src/session/snapcompact-inline.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +4 -11
- package/src/startup-splash.ts +19 -0
- package/src/task/executor.ts +11 -6
- package/src/task/types.ts +44 -41
- package/src/tool-discovery/tool-index.ts +17 -4
- package/src/tools/ask.ts +14 -14
- package/src/tools/ast-edit.ts +17 -14
- package/src/tools/ast-grep.ts +10 -9
- package/src/tools/bash.ts +15 -10
- package/src/tools/browser/launch.ts +13 -0
- package/src/tools/browser.ts +26 -32
- package/src/tools/checkpoint.ts +7 -7
- package/src/tools/debug.ts +72 -69
- package/src/tools/eval.ts +18 -19
- package/src/tools/find.ts +20 -13
- package/src/tools/gh.ts +29 -49
- package/src/tools/image-gen.ts +27 -32
- package/src/tools/inspect-image.ts +8 -9
- package/src/tools/irc.ts +12 -12
- package/src/tools/job.ts +6 -6
- package/src/tools/learn.ts +11 -14
- package/src/tools/manage-skill.ts +19 -23
- package/src/tools/memory-edit.ts +8 -8
- package/src/tools/memory-recall.ts +4 -4
- package/src/tools/memory-reflect.ts +5 -5
- package/src/tools/memory-retain.ts +9 -11
- package/src/tools/puppeteer/02_stealth_hairline.txt +1 -1
- package/src/tools/puppeteer/04_stealth_iframe.txt +4 -4
- package/src/tools/puppeteer/05_stealth_webgl.txt +1 -1
- package/src/tools/puppeteer/10_stealth_plugins.txt +6 -4
- package/src/tools/puppeteer/12_stealth_codecs.txt +2 -2
- package/src/tools/puppeteer/13_stealth_worker.txt +1 -1
- package/src/tools/read.ts +169 -13
- package/src/tools/report-tool-issue.ts +6 -6
- package/src/tools/resolve.ts +6 -6
- package/src/tools/review.ts +10 -12
- package/src/tools/search-tool-bm25.ts +5 -5
- package/src/tools/search.ts +20 -29
- package/src/tools/ssh.ts +8 -8
- package/src/tools/todo.ts +16 -19
- package/src/tools/tts.ts +16 -15
- package/src/tools/write.ts +5 -5
- package/src/tui/index.ts +1 -0
- package/src/tui/width-aware-text.ts +58 -0
- package/src/utils/markit.ts +17 -2
- package/src/web/search/index.ts +9 -9
- package/src/web/search/providers/perplexity.ts +373 -126
- package/src/web/search/types.ts +28 -48
|
@@ -1,73 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type } from "arktype";
|
|
2
2
|
|
|
3
|
-
const OpenRouterRoutingSchema =
|
|
4
|
-
only:
|
|
5
|
-
order:
|
|
3
|
+
const OpenRouterRoutingSchema = type({
|
|
4
|
+
"only?": "string[]",
|
|
5
|
+
"order?": "string[]",
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
const VercelGatewayRoutingSchema =
|
|
9
|
-
only:
|
|
10
|
-
order:
|
|
8
|
+
const VercelGatewayRoutingSchema = type({
|
|
9
|
+
"only?": "string[]",
|
|
10
|
+
"order?": "string[]",
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
const ReasoningEffortMapSchema =
|
|
14
|
-
minimal:
|
|
15
|
-
low:
|
|
16
|
-
medium:
|
|
17
|
-
high:
|
|
18
|
-
xhigh:
|
|
13
|
+
const ReasoningEffortMapSchema = type({
|
|
14
|
+
"minimal?": "string",
|
|
15
|
+
"low?": "string",
|
|
16
|
+
"medium?": "string",
|
|
17
|
+
"high?": "string",
|
|
18
|
+
"xhigh?": "string",
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
supportsStore:
|
|
23
|
-
supportsDeveloperRole:
|
|
24
|
-
supportsMultipleSystemMessages:
|
|
25
|
-
supportsReasoningEffort:
|
|
26
|
-
reasoningEffortMap: ReasoningEffortMapSchema
|
|
27
|
-
maxTokensField:
|
|
28
|
-
supportsUsageInStreaming:
|
|
29
|
-
requiresToolResultName:
|
|
30
|
-
requiresMistralToolIds:
|
|
31
|
-
requiresAssistantAfterToolResult:
|
|
32
|
-
requiresThinkingAsText:
|
|
33
|
-
reasoningContentField:
|
|
34
|
-
requiresReasoningContentForToolCalls:
|
|
35
|
-
allowsSyntheticReasoningContentForToolCalls:
|
|
36
|
-
requiresAssistantContentForToolCalls:
|
|
37
|
-
supportsToolChoice:
|
|
38
|
-
supportsForcedToolChoice:
|
|
39
|
-
disableReasoningOnForcedToolChoice:
|
|
40
|
-
disableReasoningOnToolChoice:
|
|
41
|
-
thinkingFormat:
|
|
42
|
-
openRouterRouting: OpenRouterRoutingSchema
|
|
43
|
-
vercelGatewayRouting: VercelGatewayRoutingSchema
|
|
44
|
-
extraBody:
|
|
45
|
-
cacheControlFormat:
|
|
46
|
-
supportsStrictMode:
|
|
47
|
-
toolStrictMode:
|
|
48
|
-
streamIdleTimeoutMs:
|
|
49
|
-
supportsLongPromptCacheRetention:
|
|
50
|
-
supportsReasoningParams:
|
|
51
|
-
alwaysSendMaxTokens:
|
|
52
|
-
strictResponsesPairing:
|
|
21
|
+
const OpenAICompatFields = {
|
|
22
|
+
"supportsStore?": "boolean",
|
|
23
|
+
"supportsDeveloperRole?": "boolean",
|
|
24
|
+
"supportsMultipleSystemMessages?": "boolean",
|
|
25
|
+
"supportsReasoningEffort?": "boolean",
|
|
26
|
+
"reasoningEffortMap?": ReasoningEffortMapSchema,
|
|
27
|
+
"maxTokensField?": '"max_completion_tokens" | "max_tokens"',
|
|
28
|
+
"supportsUsageInStreaming?": "boolean",
|
|
29
|
+
"requiresToolResultName?": "boolean",
|
|
30
|
+
"requiresMistralToolIds?": "boolean",
|
|
31
|
+
"requiresAssistantAfterToolResult?": "boolean",
|
|
32
|
+
"requiresThinkingAsText?": "boolean",
|
|
33
|
+
"reasoningContentField?": '"reasoning_content" | "reasoning" | "reasoning_text"',
|
|
34
|
+
"requiresReasoningContentForToolCalls?": "boolean",
|
|
35
|
+
"allowsSyntheticReasoningContentForToolCalls?": "boolean",
|
|
36
|
+
"requiresAssistantContentForToolCalls?": "boolean",
|
|
37
|
+
"supportsToolChoice?": "boolean",
|
|
38
|
+
"supportsForcedToolChoice?": "boolean",
|
|
39
|
+
"disableReasoningOnForcedToolChoice?": "boolean",
|
|
40
|
+
"disableReasoningOnToolChoice?": "boolean",
|
|
41
|
+
"thinkingFormat?": '"openai" | "openrouter" | "zai" | "qwen" | "qwen-chat-template"',
|
|
42
|
+
"openRouterRouting?": OpenRouterRoutingSchema,
|
|
43
|
+
"vercelGatewayRouting?": VercelGatewayRoutingSchema,
|
|
44
|
+
"extraBody?": { "[string]": "unknown" },
|
|
45
|
+
"cacheControlFormat?": '"anthropic"',
|
|
46
|
+
"supportsStrictMode?": "boolean",
|
|
47
|
+
"toolStrictMode?": '"all_strict" | "none"',
|
|
48
|
+
"streamIdleTimeoutMs?": "number >= 0",
|
|
49
|
+
"supportsLongPromptCacheRetention?": "boolean",
|
|
50
|
+
"supportsReasoningParams?": "boolean",
|
|
51
|
+
"alwaysSendMaxTokens?": "boolean",
|
|
52
|
+
"strictResponsesPairing?": "boolean",
|
|
53
53
|
// anthropic-messages compat flags (same `compat` slot, per-api interpretation)
|
|
54
|
-
requiresToolResultId:
|
|
55
|
-
replayUnsignedThinking:
|
|
56
|
-
}
|
|
54
|
+
"requiresToolResultId?": "boolean",
|
|
55
|
+
"replayUnsignedThinking?": "boolean",
|
|
56
|
+
} as const;
|
|
57
|
+
|
|
58
|
+
const OpenAICompatFieldsSchema = type(OpenAICompatFields);
|
|
57
59
|
|
|
58
|
-
export const OpenAICompatSchema =
|
|
59
|
-
|
|
60
|
+
export const OpenAICompatSchema = type({
|
|
61
|
+
...OpenAICompatFields,
|
|
62
|
+
"whenThinking?": OpenAICompatFieldsSchema,
|
|
60
63
|
});
|
|
61
64
|
|
|
62
|
-
const EffortSchema =
|
|
65
|
+
const EffortSchema = type('"minimal" | "low" | "medium" | "high" | "xhigh"');
|
|
63
66
|
|
|
64
|
-
const ThinkingControlModeSchema =
|
|
65
|
-
"effort",
|
|
66
|
-
|
|
67
|
-
"google-level",
|
|
68
|
-
"anthropic-adaptive",
|
|
69
|
-
"anthropic-budget-effort",
|
|
70
|
-
]);
|
|
67
|
+
const ThinkingControlModeSchema = type(
|
|
68
|
+
'"effort" | "budget" | "google-level" | "anthropic-adaptive" | "anthropic-budget-effort"',
|
|
69
|
+
);
|
|
71
70
|
|
|
72
71
|
const EFFORT_ORDER = ["minimal", "low", "medium", "high", "xhigh"] as const;
|
|
73
72
|
|
|
@@ -77,137 +76,141 @@ const EFFORT_ORDER = ["minimal", "low", "medium", "high", "xhigh"] as const;
|
|
|
77
76
|
* `ThinkingConfig` (ordered `efforts`, never empty). Precedence mirrors the
|
|
78
77
|
* old runtime: explicit `levels` beat the min..max range; `efforts` beats both.
|
|
79
78
|
*/
|
|
80
|
-
const ModelThinkingSchema =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
value =>
|
|
79
|
+
const ModelThinkingSchema = type({
|
|
80
|
+
mode: ThinkingControlModeSchema,
|
|
81
|
+
"efforts?": EffortSchema.array(),
|
|
82
|
+
"defaultLevel?": EffortSchema,
|
|
83
|
+
"effortMap?": ReasoningEffortMapSchema,
|
|
84
|
+
"supportsDisplay?": "boolean",
|
|
85
|
+
// Legacy range vocabulary (pre-efforts configs).
|
|
86
|
+
"minLevel?": EffortSchema,
|
|
87
|
+
"maxLevel?": EffortSchema,
|
|
88
|
+
"levels?": EffortSchema.array(),
|
|
89
|
+
})
|
|
90
|
+
.narrow(
|
|
91
|
+
(value, ctx) =>
|
|
94
92
|
value.efforts !== undefined ||
|
|
95
93
|
value.levels !== undefined ||
|
|
96
|
-
(value.minLevel !== undefined && value.maxLevel !== undefined)
|
|
97
|
-
|
|
98
|
-
message: "thinking requires `efforts` (or legacy `levels`/`minLevel`+`maxLevel`)",
|
|
99
|
-
},
|
|
94
|
+
(value.minLevel !== undefined && value.maxLevel !== undefined) ||
|
|
95
|
+
ctx.mustBe("thinking with `efforts` (or legacy `levels`/`minLevel`+`maxLevel`)"),
|
|
100
96
|
)
|
|
101
|
-
.
|
|
102
|
-
let resolved = efforts ?? levels;
|
|
97
|
+
.pipe((value: any) => {
|
|
98
|
+
let resolved = value.efforts ?? value.levels;
|
|
103
99
|
if (!resolved) {
|
|
104
|
-
const minIndex = EFFORT_ORDER.indexOf(minLevel!);
|
|
105
|
-
const maxIndex = EFFORT_ORDER.indexOf(maxLevel!);
|
|
100
|
+
const minIndex = EFFORT_ORDER.indexOf(value.minLevel!);
|
|
101
|
+
const maxIndex = EFFORT_ORDER.indexOf(value.maxLevel!);
|
|
106
102
|
resolved = EFFORT_ORDER.slice(minIndex, Math.max(minIndex, maxIndex) + 1);
|
|
107
103
|
}
|
|
108
104
|
return {
|
|
109
|
-
mode,
|
|
105
|
+
mode: value.mode,
|
|
110
106
|
efforts: resolved,
|
|
111
|
-
...(defaultLevel !== undefined && { defaultLevel }),
|
|
112
|
-
...(effortMap !== undefined && { effortMap }),
|
|
113
|
-
...(supportsDisplay !== undefined && { supportsDisplay }),
|
|
107
|
+
...(value.defaultLevel !== undefined && { defaultLevel: value.defaultLevel }),
|
|
108
|
+
...(value.effortMap !== undefined && { effortMap: value.effortMap }),
|
|
109
|
+
...(value.supportsDisplay !== undefined && { supportsDisplay: value.supportsDisplay }),
|
|
114
110
|
};
|
|
115
111
|
});
|
|
116
112
|
|
|
117
|
-
const ModelDefinitionSchema =
|
|
118
|
-
id:
|
|
119
|
-
name:
|
|
120
|
-
api:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
113
|
+
const ModelDefinitionSchema = type({
|
|
114
|
+
id: "string",
|
|
115
|
+
"name?": "string",
|
|
116
|
+
"api?":
|
|
117
|
+
'"openai-completions" | "openai-responses" | "openai-codex-responses" | "azure-openai-responses" | "anthropic-messages" | "google-generative-ai" | "google-gemini-cli" | "google-vertex"',
|
|
118
|
+
"baseUrl?": "string",
|
|
119
|
+
"reasoning?": "boolean",
|
|
120
|
+
"thinking?": ModelThinkingSchema,
|
|
121
|
+
"input?": '("text" | "image")[]',
|
|
122
|
+
"supportsTools?": "boolean",
|
|
123
|
+
"cost?": {
|
|
124
|
+
input: "number",
|
|
125
|
+
output: "number",
|
|
126
|
+
cacheRead: "number",
|
|
127
|
+
cacheWrite: "number",
|
|
128
|
+
},
|
|
129
|
+
"premiumMultiplier?": "number",
|
|
130
|
+
"contextWindow?": "number",
|
|
131
|
+
"maxTokens?": "number",
|
|
132
|
+
"omitMaxOutputTokens?": "boolean",
|
|
133
|
+
"headers?": { "[string]": "string" },
|
|
134
|
+
"compat?": OpenAICompatSchema,
|
|
135
|
+
"contextPromotionTarget?": "string",
|
|
136
|
+
}).narrow((value, ctx) => {
|
|
137
|
+
// Enforce id non-empty
|
|
138
|
+
if (typeof value.id === "string" && value.id.length === 0) {
|
|
139
|
+
return ctx.mustBe("id a non-empty string");
|
|
140
|
+
}
|
|
141
|
+
if (value.name !== undefined && typeof value.name === "string" && value.name.length === 0) {
|
|
142
|
+
return ctx.mustBe("name a non-empty string");
|
|
143
|
+
}
|
|
144
|
+
if (value.baseUrl !== undefined && typeof value.baseUrl === "string" && value.baseUrl.length === 0) {
|
|
145
|
+
return ctx.mustBe("baseUrl a non-empty string");
|
|
146
|
+
}
|
|
147
|
+
if (
|
|
148
|
+
value.contextPromotionTarget !== undefined &&
|
|
149
|
+
typeof value.contextPromotionTarget === "string" &&
|
|
150
|
+
value.contextPromotionTarget.length === 0
|
|
151
|
+
) {
|
|
152
|
+
return ctx.mustBe("contextPromotionTarget a non-empty string");
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
152
155
|
});
|
|
153
156
|
|
|
154
|
-
export const ModelOverrideSchema =
|
|
155
|
-
name:
|
|
156
|
-
reasoning:
|
|
157
|
-
thinking: ModelThinkingSchema
|
|
158
|
-
input:
|
|
159
|
-
supportsTools:
|
|
160
|
-
cost:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
157
|
+
export const ModelOverrideSchema = type({
|
|
158
|
+
"name?": "string",
|
|
159
|
+
"reasoning?": "boolean",
|
|
160
|
+
"thinking?": ModelThinkingSchema,
|
|
161
|
+
"input?": '("text" | "image")[]',
|
|
162
|
+
"supportsTools?": "boolean",
|
|
163
|
+
"cost?": {
|
|
164
|
+
"input?": "number",
|
|
165
|
+
"output?": "number",
|
|
166
|
+
"cacheRead?": "number",
|
|
167
|
+
"cacheWrite?": "number",
|
|
168
|
+
},
|
|
169
|
+
"premiumMultiplier?": "number",
|
|
170
|
+
"contextWindow?": "number",
|
|
171
|
+
"maxTokens?": "number",
|
|
172
|
+
"omitMaxOutputTokens?": "boolean",
|
|
173
|
+
"headers?": { "[string]": "string" },
|
|
174
|
+
"compat?": OpenAICompatSchema,
|
|
175
|
+
"contextPromotionTarget?": "string",
|
|
176
|
+
}).narrow((value, ctx) => {
|
|
177
|
+
if (value.name !== undefined && typeof value.name === "string" && value.name.length === 0) {
|
|
178
|
+
return ctx.mustBe("name a non-empty string");
|
|
179
|
+
}
|
|
180
|
+
if (
|
|
181
|
+
value.contextPromotionTarget !== undefined &&
|
|
182
|
+
typeof value.contextPromotionTarget === "string" &&
|
|
183
|
+
value.contextPromotionTarget.length === 0
|
|
184
|
+
) {
|
|
185
|
+
return ctx.mustBe("contextPromotionTarget a non-empty string");
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
175
188
|
});
|
|
176
189
|
|
|
177
|
-
export type ModelOverride =
|
|
190
|
+
export type ModelOverride = typeof ModelOverrideSchema.infer;
|
|
178
191
|
|
|
179
|
-
export const ProviderDiscoverySchema =
|
|
180
|
-
type:
|
|
192
|
+
export const ProviderDiscoverySchema = type({
|
|
193
|
+
type: '"ollama" | "llama.cpp" | "lm-studio" | "openai-models-list" | "proxy"',
|
|
181
194
|
});
|
|
182
195
|
|
|
183
|
-
export const ProviderAuthSchema =
|
|
184
|
-
|
|
185
|
-
export type ProviderAuthMode =
|
|
186
|
-
export type ProviderDiscovery =
|
|
187
|
-
|
|
188
|
-
const ProviderConfigSchema =
|
|
189
|
-
baseUrl:
|
|
190
|
-
apiKey:
|
|
191
|
-
api:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
])
|
|
202
|
-
.optional(),
|
|
203
|
-
headers: z.record(z.string(), z.string()).optional(),
|
|
204
|
-
compat: OpenAICompatSchema.optional(),
|
|
205
|
-
authHeader: z.boolean().optional(),
|
|
206
|
-
auth: ProviderAuthSchema.optional(),
|
|
207
|
-
discovery: ProviderDiscoverySchema.optional(),
|
|
208
|
-
models: z.array(ModelDefinitionSchema).optional(),
|
|
209
|
-
modelOverrides: z.record(z.string(), ModelOverrideSchema).optional(),
|
|
210
|
-
disableStrictTools: z.boolean().optional(),
|
|
196
|
+
export const ProviderAuthSchema = type('"apiKey" | "none" | "oauth"');
|
|
197
|
+
|
|
198
|
+
export type ProviderAuthMode = typeof ProviderAuthSchema.infer;
|
|
199
|
+
export type ProviderDiscovery = typeof ProviderDiscoverySchema.infer;
|
|
200
|
+
|
|
201
|
+
const ProviderConfigSchema = type({
|
|
202
|
+
"baseUrl?": "string",
|
|
203
|
+
"apiKey?": "string",
|
|
204
|
+
"api?":
|
|
205
|
+
'"openai-completions" | "openai-responses" | "openai-codex-responses" | "azure-openai-responses" | "anthropic-messages" | "google-generative-ai" | "google-gemini-cli" | "google-vertex"',
|
|
206
|
+
"headers?": { "[string]": "string" },
|
|
207
|
+
"compat?": OpenAICompatSchema,
|
|
208
|
+
"authHeader?": "boolean",
|
|
209
|
+
"auth?": ProviderAuthSchema,
|
|
210
|
+
"discovery?": ProviderDiscoverySchema,
|
|
211
|
+
"models?": ModelDefinitionSchema.array(),
|
|
212
|
+
"modelOverrides?": { "[string]": ModelOverrideSchema },
|
|
213
|
+
"disableStrictTools?": "boolean",
|
|
211
214
|
/**
|
|
212
215
|
* Streaming transport override. When set to `"pi-native"`, omp dispatches
|
|
213
216
|
* every model under this provider via the auth-gateway's
|
|
@@ -215,17 +218,41 @@ const ProviderConfigSchema = z.object({
|
|
|
215
218
|
* provider's `baseUrl` must point at a compatible `omp auth-gateway`
|
|
216
219
|
* and `apiKey` must carry the gateway bearer.
|
|
217
220
|
*/
|
|
218
|
-
transport:
|
|
221
|
+
"transport?": '"pi-native"',
|
|
222
|
+
}).narrow((value, ctx) => {
|
|
223
|
+
if (value.baseUrl !== undefined && typeof value.baseUrl === "string" && value.baseUrl.length === 0) {
|
|
224
|
+
return ctx.mustBe("baseUrl a non-empty string");
|
|
225
|
+
}
|
|
226
|
+
if (value.apiKey !== undefined && typeof value.apiKey === "string" && value.apiKey.length === 0) {
|
|
227
|
+
return ctx.mustBe("apiKey a non-empty string");
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
219
230
|
});
|
|
220
231
|
|
|
221
|
-
const EquivalenceConfigSchema =
|
|
222
|
-
overrides:
|
|
223
|
-
exclude:
|
|
232
|
+
const EquivalenceConfigSchema = type({
|
|
233
|
+
"overrides?": { "[string]": "string" },
|
|
234
|
+
"exclude?": "string[]",
|
|
235
|
+
}).narrow((value, ctx) => {
|
|
236
|
+
if (value.overrides !== undefined) {
|
|
237
|
+
for (const [, v] of Object.entries(value.overrides)) {
|
|
238
|
+
if (typeof v === "string" && v.length === 0) {
|
|
239
|
+
return ctx.mustBe("overrides values non-empty strings");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (value.exclude !== undefined && Array.isArray(value.exclude)) {
|
|
244
|
+
for (const item of value.exclude) {
|
|
245
|
+
if (typeof item === "string" && item.length === 0) {
|
|
246
|
+
return ctx.mustBe("exclude items non-empty strings");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
224
251
|
});
|
|
225
252
|
|
|
226
|
-
export const ModelsConfigSchema =
|
|
227
|
-
providers:
|
|
228
|
-
equivalence: EquivalenceConfigSchema
|
|
253
|
+
export const ModelsConfigSchema = type({
|
|
254
|
+
"providers?": { "[string]": ProviderConfigSchema },
|
|
255
|
+
"equivalence?": EquivalenceConfigSchema,
|
|
229
256
|
});
|
|
230
257
|
|
|
231
|
-
export type ModelsConfig =
|
|
258
|
+
export type ModelsConfig = typeof ModelsConfigSchema.infer;
|
|
@@ -897,6 +897,28 @@ export const SETTINGS_SCHEMA = {
|
|
|
897
897
|
},
|
|
898
898
|
},
|
|
899
899
|
|
|
900
|
+
"model.loopGuard.enabled": {
|
|
901
|
+
type: "boolean",
|
|
902
|
+
default: true,
|
|
903
|
+
ui: {
|
|
904
|
+
tab: "model",
|
|
905
|
+
group: "Thinking",
|
|
906
|
+
label: "Loop Guard",
|
|
907
|
+
description: "Enable automatic stream loop detection for Gemini and DeepSeek models",
|
|
908
|
+
},
|
|
909
|
+
},
|
|
910
|
+
|
|
911
|
+
"model.loopGuard.checkAssistantContent": {
|
|
912
|
+
type: "boolean",
|
|
913
|
+
default: true,
|
|
914
|
+
ui: {
|
|
915
|
+
tab: "model",
|
|
916
|
+
group: "Thinking",
|
|
917
|
+
label: "Loop Guard Scan Prose",
|
|
918
|
+
description: "Apply loop guard to assistant prose messages in addition to thinking logs",
|
|
919
|
+
},
|
|
920
|
+
},
|
|
921
|
+
|
|
900
922
|
repeatToolDescriptions: {
|
|
901
923
|
type: "boolean",
|
|
902
924
|
default: false,
|
|
@@ -1336,6 +1358,18 @@ export const SETTINGS_SCHEMA = {
|
|
|
1336
1358
|
},
|
|
1337
1359
|
},
|
|
1338
1360
|
|
|
1361
|
+
"startup.showSplash": {
|
|
1362
|
+
type: "boolean",
|
|
1363
|
+
default: false,
|
|
1364
|
+
ui: {
|
|
1365
|
+
tab: "interaction",
|
|
1366
|
+
group: "Startup & Updates",
|
|
1367
|
+
label: "Show Startup Splash",
|
|
1368
|
+
description:
|
|
1369
|
+
"Show the full animated setup splash on normal interactive startup without rerunning setup. Quiet Startup still suppresses it.",
|
|
1370
|
+
},
|
|
1371
|
+
},
|
|
1372
|
+
|
|
1339
1373
|
"startup.setupWizard": {
|
|
1340
1374
|
type: "boolean",
|
|
1341
1375
|
default: true,
|
|
@@ -19,6 +19,7 @@ import tsImportType from "./ts-import-type.md" with { type: "text" };
|
|
|
19
19
|
import tsNoAny from "./ts-no-any.md" with { type: "text" };
|
|
20
20
|
import tsNoDeprecatedLeftovers from "./ts-no-deprecated-leftovers.md" with { type: "text" };
|
|
21
21
|
import tsNoDynamicImport from "./ts-no-dynamic-import.md" with { type: "text" };
|
|
22
|
+
import tsNoInlineCastAccess from "./ts-no-inline-cast-access.md" with { type: "text" };
|
|
22
23
|
import tsNoReturnType from "./ts-no-return-type.md" with { type: "text" };
|
|
23
24
|
import tsNoTestTimers from "./ts-no-test-timers.md" with { type: "text" };
|
|
24
25
|
import tsNoTinyFunctions from "./ts-no-tiny-functions.md" with { type: "text" };
|
|
@@ -45,6 +46,7 @@ export const BUILTIN_RULE_SOURCES: readonly BuiltinRuleSource[] = [
|
|
|
45
46
|
{ name: "ts-no-any", content: tsNoAny },
|
|
46
47
|
{ name: "ts-no-deprecated-leftovers", content: tsNoDeprecatedLeftovers },
|
|
47
48
|
{ name: "ts-no-dynamic-import", content: tsNoDynamicImport },
|
|
49
|
+
{ name: "ts-no-inline-cast-access", content: tsNoInlineCastAccess },
|
|
48
50
|
{ name: "ts-no-return-type", content: tsNoReturnType },
|
|
49
51
|
{ name: "ts-no-test-timers", content: tsNoTestTimers },
|
|
50
52
|
{ name: "ts-no-tiny-functions", content: tsNoTinyFunctions },
|
|
@@ -17,7 +17,7 @@ Use top-level `import type` declarations for type-only dependencies. NEVER write
|
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
19
|
// Bad — inline imports hide dependencies in signatures.
|
|
20
|
-
function run(client: import("some-sdk").Client, input: import("
|
|
20
|
+
function run(client: import("some-sdk").Client, input: import("arktype").infer<Schema>): Promise<Output>;
|
|
21
21
|
|
|
22
22
|
// Bad — annotations become path dumps.
|
|
23
23
|
const options: import("some-sdk/config").ClientOptions = { ... };
|
|
@@ -28,7 +28,7 @@ const options: import("some-sdk/config").ClientOptions = { ... };
|
|
|
28
28
|
```typescript
|
|
29
29
|
import type { Client } from "some-sdk";
|
|
30
30
|
import type { ClientOptions } from "some-sdk/config";
|
|
31
|
-
import type { infer as Infer } from "
|
|
31
|
+
import type { infer as Infer } from "arktype";
|
|
32
32
|
|
|
33
33
|
function run(client: Client, input: Infer<Schema>): Promise<Output>;
|
|
34
34
|
const options: ClientOptions = { ... };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Never use `any` in TypeScript annotations or assertions — use `unknown`, generics, or the actual type"
|
|
2
|
+
description: "Never use `any` in TypeScript annotations or assertions — use `unknown`, generics, a schema parse at trust boundaries, or the actual type"
|
|
3
3
|
condition: ": any|as any"
|
|
4
4
|
scope: "tool:edit(*.ts), tool:edit(*.tsx), tool:write(*.ts), tool:write(*.tsx)"
|
|
5
5
|
---
|
|
@@ -9,6 +9,7 @@ Never use `: any` or `as any`. They disable type checking exactly where the boun
|
|
|
9
9
|
## Use instead
|
|
10
10
|
|
|
11
11
|
- `unknown` for unvalidated input.
|
|
12
|
+
- A schema parse (Zod, Valibot, …; e.g. Zod v4 when it is already in the project) for untrusted or external input — validate once, then consume a typed value.
|
|
12
13
|
- A domain type when the shape is known.
|
|
13
14
|
- A generic when the caller supplies the shape.
|
|
14
15
|
- A type guard when runtime checks establish shape.
|
|
@@ -25,7 +26,7 @@ function readId(value: any): any {
|
|
|
25
26
|
// Good — validate unknown input.
|
|
26
27
|
function readId(value: unknown): string | undefined {
|
|
27
28
|
if (value && typeof value === "object" && "id" in value) {
|
|
28
|
-
const candidate =
|
|
29
|
+
const candidate = value.id; // `in` narrowing types this as unknown — no cast needed
|
|
29
30
|
return typeof candidate === "string" ? candidate : undefined;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -53,4 +54,12 @@ const config = { port: 3000 } as any as ServerConfig;
|
|
|
53
54
|
const config = { port: 3000 } satisfies ServerConfig;
|
|
54
55
|
```
|
|
55
56
|
|
|
57
|
+
## Choosing: guard vs schema vs unchecked cast
|
|
58
|
+
|
|
59
|
+
| Situation | Reach for |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| Data from outside your control — network/RPC, parsed JSON, config files, env vars, CLI/IPC, persisted blobs — or a shape reused across the codebase | **Schema parse** (Zod/Valibot/…): runtime validation, typed output, and a clear error on bad shape |
|
|
62
|
+
| In-process value the compiler merely lost track of — an `unknown` from a generic, a union to discriminate, a one-off read of a field or two | **Type guard** (`in` / `typeof`): no dependency, but it only checks what you write, so keep the checked surface small |
|
|
63
|
+
| You genuinely know more than the compiler *and* a runtime check is impossible or meaningless — a well-known DOM node (`as HTMLElement`), structurally-identical types inference can't unify, a library type that is wrong or unexpressible, `as const` | **Unchecked cast** (`as` / `as unknown as T`): assign to a named const with a one-line reason; never for raw external input |
|
|
64
|
+
|
|
56
65
|
If a library boundary truly requires an unchecked cast, use `as unknown as T` with a short reason. Never leave a bare `any`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Don't assert an inline object type and immediately read a property — `(x as { y: T }).y` trusts an unchecked shape; validate with a schema parse at trust boundaries, narrow with `in`/`typeof`, or use a validated named type"
|
|
3
|
+
scope: "tool:edit(*.{ts,tsx,mts,cts}), tool:write(*.{ts,tsx,mts,cts})"
|
|
4
|
+
interruptMode: tool-only
|
|
5
|
+
astCondition:
|
|
6
|
+
- "($X as { $$$BODY }).$PROP"
|
|
7
|
+
- "($X as { $$$BODY })?.$PROP"
|
|
8
|
+
- "($X as { $$$BODY })[$IDX]"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**Don't assert an inline object type just to read a property.** `(value as { content: unknown }).content` fabricates a shape the compiler never verified, then trusts it for exactly one access. If `value` isn't that shape, the read is silently wrong and no type error ever fires.
|
|
12
|
+
|
|
13
|
+
## Why it's wrong
|
|
14
|
+
|
|
15
|
+
- The cast is an unchecked assertion — it suppresses the type error instead of proving the shape.
|
|
16
|
+
- It localizes the lie to one expression, so the next reader can't tell whether the value was ever validated.
|
|
17
|
+
- It almost always stands in for the real fix: runtime narrowing or a validated type at the boundary.
|
|
18
|
+
|
|
19
|
+
## Avoid
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const content = (value as { content: unknown }).content;
|
|
23
|
+
const id = (resp as { data: { id: string } }).data.id;
|
|
24
|
+
const name = (payload as { name?: string })?.name;
|
|
25
|
+
const flag = (opts as { enabled: boolean })["enabled"];
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Use
|
|
29
|
+
|
|
30
|
+
Prefer a schema parse at the boundary when a validator is available (Zod, Valibot, …) — validate once, then read from a fully typed value. If Zod is already in the project (e.g. Zod v4):
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { z } from "zod/v4";
|
|
34
|
+
|
|
35
|
+
const Resp = z.object({ data: z.object({ id: z.string() }) });
|
|
36
|
+
|
|
37
|
+
const resp = Resp.parse(raw); // throws on bad input; resp.data.id is typed string
|
|
38
|
+
const id = resp.data.id;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For a one-off read of a single field, narrow with `in` / `typeof` so the access is actually checked — TypeScript infers `unknown` for the property after `"content" in value`:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
if (value && typeof value === "object" && "content" in value) {
|
|
45
|
+
const content = value.content; // unknown — validate before use
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Choosing: guard vs schema vs unchecked cast
|
|
50
|
+
|
|
51
|
+
| Situation | Reach for |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| Data from outside your control — network/RPC, parsed JSON, config files, env vars, CLI/IPC, persisted blobs — or a shape reused across the codebase | **Schema parse** (Zod/Valibot/…): runtime validation, typed output, and a clear error on bad shape |
|
|
54
|
+
| In-process value the compiler merely lost track of — an `unknown` from a generic, a union to discriminate, a one-off read of a field or two | **Type guard** (`in` / `typeof`): no dependency, but it only checks what you write, so keep the checked surface small |
|
|
55
|
+
| You genuinely know more than the compiler *and* a runtime check is impossible or meaningless — a well-known DOM node (`as HTMLElement`), structurally-identical types inference can't unify, a library type that's wrong or unexpressible, `as const` | **Unchecked cast** (`as`): assign to a named const with a one-line reason; never for raw external input, never inlined into a member access |
|