@oh-my-pi/pi-coding-agent 16.2.6 → 16.2.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 +46 -0
- package/dist/cli.js +2781 -2660
- package/dist/types/cli/bench-cli.d.ts +3 -3
- package/dist/types/commands/bench.d.ts +1 -1
- package/dist/types/config/service-tier.d.ts +39 -24
- package/dist/types/config/settings-schema.d.ts +92 -36
- package/dist/types/edit/hashline/filesystem.d.ts +1 -0
- package/dist/types/mcp/config-writer.d.ts +48 -0
- package/dist/types/mcp/types.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +33 -13
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -7
- package/dist/types/session/session-entries.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +2 -2
- package/dist/types/session/settings-stream-fn.d.ts +2 -2
- package/dist/types/system-prompt.test.d.ts +1 -0
- package/dist/types/task/executor.d.ts +6 -6
- package/dist/types/task/types.d.ts +6 -0
- package/dist/types/task/worktree.d.ts +32 -6
- package/dist/types/tiny/title-client.d.ts +5 -1
- package/dist/types/tools/index.d.ts +3 -3
- package/dist/types/tools/output-schema-validator.d.ts +10 -0
- package/dist/types/utils/git.d.ts +17 -0
- package/package.json +12 -12
- package/src/cli/bench-cli.ts +19 -12
- package/src/cli/tiny-models-cli.ts +18 -4
- package/src/commands/bench.ts +3 -3
- package/src/config/mcp-schema.json +10 -1
- package/src/config/service-tier.ts +85 -56
- package/src/config/settings-schema.ts +81 -37
- package/src/config/settings.ts +47 -0
- package/src/discovery/builtin-rules/go-add-cleanup.md +32 -0
- package/src/discovery/builtin-rules/go-bench-loop.md +36 -0
- package/src/discovery/builtin-rules/go-exp-promoted.md +39 -0
- package/src/discovery/builtin-rules/go-ioutil.md +36 -0
- package/src/discovery/builtin-rules/go-join-hostport.md +29 -0
- package/src/discovery/builtin-rules/go-new-expr.md +44 -0
- package/src/discovery/builtin-rules/go-rand-v2.md +40 -0
- package/src/discovery/builtin-rules/go-range-int.md +45 -0
- package/src/discovery/builtin-rules/index.ts +16 -0
- package/src/edit/hashline/filesystem.ts +12 -0
- package/src/eval/agent-bridge.ts +4 -2
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/main.ts +1 -1
- package/src/mcp/config-writer.ts +121 -0
- package/src/mcp/config.ts +10 -6
- package/src/mcp/types.ts +3 -0
- package/src/modes/components/extensions/extension-dashboard.ts +46 -0
- package/src/modes/components/extensions/state-manager.ts +24 -3
- package/src/modes/controllers/event-controller.ts +7 -0
- package/src/modes/controllers/tool-args-reveal.ts +1 -1
- package/src/modes/utils/transcript-render-helpers.ts +2 -2
- package/src/prompts/tools/bash.md +1 -4
- package/src/sdk.ts +12 -11
- package/src/session/agent-session.ts +294 -82
- package/src/session/messages.ts +1 -1
- package/src/session/session-context.ts +17 -6
- package/src/session/session-entries.ts +2 -2
- package/src/session/session-manager.ts +9 -2
- package/src/session/settings-stream-fn.ts +12 -2
- package/src/slash-commands/builtin-registry.ts +2 -10
- package/src/system-prompt.test.ts +158 -0
- package/src/system-prompt.ts +69 -26
- package/src/task/executor.ts +23 -16
- package/src/task/index.ts +7 -5
- package/src/task/isolation-runner.ts +15 -1
- package/src/task/types.ts +6 -0
- package/src/task/worktree.ts +219 -38
- package/src/tiny/title-client.ts +19 -13
- package/src/tools/grep.ts +19 -1
- package/src/tools/index.ts +3 -3
- package/src/tools/irc.ts +9 -3
- package/src/tools/output-schema-validator.ts +38 -0
- package/src/tools/read.ts +28 -28
- package/src/tools/yield.ts +52 -15
- package/src/utils/file-mentions.ts +10 -1
- package/src/utils/git.ts +38 -0
- package/src/web/search/providers/duckduckgo.ts +17 -3
|
@@ -80,11 +80,32 @@ export declare function cleanupIsolation(handle: IsolationHandle): Promise<void>
|
|
|
80
80
|
export interface CommitToBranchResult {
|
|
81
81
|
branchName?: string;
|
|
82
82
|
nestedPatches: NestedRepoPatch[];
|
|
83
|
+
/**
|
|
84
|
+
* SHA of the parent-repo commit the task branch was created on top of, so
|
|
85
|
+
* {@link mergeTaskBranches} can cherry-pick the range `baseSha..branchName`
|
|
86
|
+
* and preserve every agent commit's message and author.
|
|
87
|
+
*/
|
|
88
|
+
baseSha?: string;
|
|
83
89
|
}
|
|
84
90
|
/**
|
|
85
|
-
*
|
|
86
|
-
* Only root
|
|
87
|
-
* separately
|
|
91
|
+
* Capture task-only changes from the isolation worktree onto a parent-repo
|
|
92
|
+
* branch named `omp/task/${taskId}`. Only root-repo changes go on the branch;
|
|
93
|
+
* nested-repo patches are returned separately because the parent git can't
|
|
94
|
+
* track files inside gitlinks.
|
|
95
|
+
*
|
|
96
|
+
* If the agent committed inside isolation (HEAD moved past
|
|
97
|
+
* `baseline.root.headCommit`), clean-baseline runs fetch the raw commit range
|
|
98
|
+
* into the parent repo and later cherry-pick `baseSha..branchName`, preserving
|
|
99
|
+
* every message and author verbatim. Dirty-baseline runs rewrite each agent
|
|
100
|
+
* commit against the captured baseline WIP before committing it to the task
|
|
101
|
+
* branch, so user staged/unstaged/untracked changes present at isolation
|
|
102
|
+
* start are not replayed into the parent commit history.
|
|
103
|
+
*
|
|
104
|
+
* If the agent did not commit, the captured delta is collapsed onto a single
|
|
105
|
+
* branch commit with an AI-generated (or fallback) message — the legacy
|
|
106
|
+
* behaviour.
|
|
107
|
+
*
|
|
108
|
+
* Returns `null` when no root or nested changes exist.
|
|
88
109
|
*/
|
|
89
110
|
export declare function commitToBranch(isolationDir: string, baseline: WorktreeBaseline, taskId: string, description: string | undefined, commitMessage?: (diff: string) => Promise<string | null>): Promise<CommitToBranchResult | null>;
|
|
90
111
|
export interface MergeBranchResult {
|
|
@@ -95,14 +116,19 @@ export interface MergeBranchResult {
|
|
|
95
116
|
stashConflict?: string;
|
|
96
117
|
}
|
|
97
118
|
/**
|
|
98
|
-
* Cherry-pick task branch commits sequentially onto HEAD.
|
|
99
|
-
*
|
|
100
|
-
*
|
|
119
|
+
* Cherry-pick task branch commits sequentially onto HEAD. When `baseSha` is
|
|
120
|
+
* provided the cherry-pick uses the inclusive range `baseSha..branchName`,
|
|
121
|
+
* replaying every commit individually and preserving each commit's message
|
|
122
|
+
* and author. When omitted, the branch is cherry-picked as a single commit
|
|
123
|
+
* (legacy callers).
|
|
124
|
+
*
|
|
125
|
+
* Stops on the first conflict and reports which branches succeeded.
|
|
101
126
|
*/
|
|
102
127
|
export declare function mergeTaskBranches(repoRoot: string, branches: Array<{
|
|
103
128
|
branchName: string;
|
|
104
129
|
taskId: string;
|
|
105
130
|
description?: string;
|
|
131
|
+
baseSha?: string;
|
|
106
132
|
}>): Promise<MergeBranchResult>;
|
|
107
133
|
/** Clean up temporary task branches. */
|
|
108
134
|
export declare function cleanupTaskBranches(repoRoot: string, branches: string[]): Promise<void>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type RefCountedWorkerHandle, type SpawnedSubprocess } from "../subprocess/worker-client";
|
|
2
2
|
import type { TinyTitleProgressEvent, TinyTitleWorkerInbound, TinyTitleWorkerOutbound } from "./title-protocol";
|
|
3
|
+
export interface TinyTitleDownloadResult {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
3
7
|
export interface TinyTitleDownloadOptions {
|
|
4
8
|
signal?: AbortSignal;
|
|
5
9
|
onProgress?: (event: TinyTitleProgressEvent) => void;
|
|
@@ -52,7 +56,7 @@ export declare class TinyTitleClient {
|
|
|
52
56
|
maxTokens?: number;
|
|
53
57
|
signal?: AbortSignal;
|
|
54
58
|
}): Promise<string | null>;
|
|
55
|
-
downloadModel(modelKey: string, options?: TinyTitleDownloadOptions): Promise<
|
|
59
|
+
downloadModel(modelKey: string, options?: TinyTitleDownloadOptions): Promise<TinyTitleDownloadResult>;
|
|
56
60
|
terminate(): Promise<void>;
|
|
57
61
|
}
|
|
58
62
|
export declare const tinyTitleClient: TinyTitleClient;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
2
2
|
import type { AgentTelemetryConfig, AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
3
|
-
import type { FetchImpl, ImageContent, Model,
|
|
3
|
+
import type { FetchImpl, ImageContent, Model, ServiceTierByFamily, ToolChoice } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { AsyncJobManager } from "../async/job-manager";
|
|
5
5
|
import type { Rule } from "../capability/rule";
|
|
6
6
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
@@ -191,8 +191,8 @@ export interface ToolSession {
|
|
|
191
191
|
getActiveModelString?: () => string | undefined;
|
|
192
192
|
/** Get the current session model object (provider/api capabilities), regardless of how it was chosen. */
|
|
193
193
|
getActiveModel?: () => Model | undefined;
|
|
194
|
-
/** Get the session's live
|
|
195
|
-
|
|
194
|
+
/** Get the session's live per-family service tiers (undefined = none). Source of truth for subagent `tier.subagent: inherit`. */
|
|
195
|
+
getServiceTierByFamily?: () => ServiceTierByFamily | undefined;
|
|
196
196
|
/** Auth storage for passing to subagents (avoids re-discovery) */
|
|
197
197
|
authStorage?: import("../session/auth-storage").AuthStorage;
|
|
198
198
|
/** Model registry for passing to subagents (avoids re-discovery) */
|
|
@@ -14,6 +14,16 @@ export interface OutputValidator {
|
|
|
14
14
|
validate(value: unknown): JsonSchemaValidationResult;
|
|
15
15
|
/** Top-level required property names. Empty if the schema has no `required` array at root. */
|
|
16
16
|
readonly requiredFields: readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Per-label validators for incremental yields (`type: ["<label>"]`). Each entry validates the
|
|
19
|
+
* `data` payload of a single section against the matching top-level property's sub-schema —
|
|
20
|
+
* array-typed properties (e.g. `findings`) use the items schema since each yield contributes
|
|
21
|
+
* one element, while scalar properties use the property schema directly. Unknown labels (not
|
|
22
|
+
* top-level properties) have no entry and skip per-call validation. Lets the yield tool give
|
|
23
|
+
* the model retry feedback on a section as soon as it arrives, instead of deferring every
|
|
24
|
+
* mismatch to the parent's post-mortem `schema_violation`.
|
|
25
|
+
*/
|
|
26
|
+
readonly validateSection: ReadonlyMap<string, (value: unknown) => JsonSchemaValidationResult>;
|
|
17
27
|
}
|
|
18
28
|
export interface BuildOutputValidatorResult {
|
|
19
29
|
/** Present when the schema produced a usable validator (i.e. constraining schemas). Absent for missing/unconstrained schemas. */
|
|
@@ -63,8 +63,18 @@ export interface StatusOptions {
|
|
|
63
63
|
readonly untrackedFiles?: "all" | "no" | "normal";
|
|
64
64
|
readonly z?: boolean;
|
|
65
65
|
}
|
|
66
|
+
export interface CommitAuthor {
|
|
67
|
+
readonly date?: string;
|
|
68
|
+
readonly email: string;
|
|
69
|
+
readonly name: string;
|
|
70
|
+
}
|
|
71
|
+
export interface CommitDetails {
|
|
72
|
+
readonly author: CommitAuthor;
|
|
73
|
+
readonly message: string;
|
|
74
|
+
}
|
|
66
75
|
export interface CommitOptions {
|
|
67
76
|
readonly allowEmpty?: boolean;
|
|
77
|
+
readonly author?: CommitAuthor;
|
|
68
78
|
readonly files?: readonly string[];
|
|
69
79
|
readonly signal?: AbortSignal;
|
|
70
80
|
}
|
|
@@ -78,6 +88,7 @@ export interface PatchOptions {
|
|
|
78
88
|
readonly cached?: boolean;
|
|
79
89
|
readonly check?: boolean;
|
|
80
90
|
readonly env?: Record<string, string | undefined>;
|
|
91
|
+
readonly threeWay?: boolean;
|
|
81
92
|
readonly signal?: AbortSignal;
|
|
82
93
|
}
|
|
83
94
|
export interface RestoreOptions {
|
|
@@ -195,12 +206,18 @@ export declare const show: ((cwd: string, revision: string, options?: {
|
|
|
195
206
|
/** Get the path prefix of the current directory relative to the repo root. */
|
|
196
207
|
prefix(cwd: string, signal?: AbortSignal): Promise<string>;
|
|
197
208
|
};
|
|
209
|
+
/** Read commit message and author metadata for replay/rewrite flows. */
|
|
210
|
+
export declare function commitDetails(cwd: string, revision: string, signal?: AbortSignal): Promise<CommitDetails>;
|
|
198
211
|
export declare const log: {
|
|
199
212
|
/** Recent commit subjects (one-line each). */
|
|
200
213
|
subjects(cwd: string, count: number, signal?: AbortSignal): Promise<string[]>;
|
|
201
214
|
/** Recent commits as `<short-sha> <subject>` onelines. */
|
|
202
215
|
onelines(cwd: string, count: number, signal?: AbortSignal): Promise<string[]>;
|
|
203
216
|
};
|
|
217
|
+
export declare const revList: {
|
|
218
|
+
/** Commits in `base..head`, oldest first. */
|
|
219
|
+
range(cwd: string, base: string, head: string, signal?: AbortSignal): Promise<string[]>;
|
|
220
|
+
};
|
|
204
221
|
export declare const branch: {
|
|
205
222
|
/** Current branch name, or null if detached/unavailable. */
|
|
206
223
|
current(cwd: string, signal?: AbortSignal): Promise<string | null>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "16.2.
|
|
4
|
+
"version": "16.2.8",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"@agentclientprotocol/sdk": "0.25.0",
|
|
56
56
|
"@babel/parser": "^7.29.7",
|
|
57
57
|
"@mozilla/readability": "^0.6.0",
|
|
58
|
-
"@oh-my-pi/hashline": "16.2.
|
|
59
|
-
"@oh-my-pi/omp-stats": "16.2.
|
|
60
|
-
"@oh-my-pi/pi-agent-core": "16.2.
|
|
61
|
-
"@oh-my-pi/pi-ai": "16.2.
|
|
62
|
-
"@oh-my-pi/pi-catalog": "16.2.
|
|
63
|
-
"@oh-my-pi/pi-mnemopi": "16.2.
|
|
64
|
-
"@oh-my-pi/pi-natives": "16.2.
|
|
65
|
-
"@oh-my-pi/pi-tui": "16.2.
|
|
66
|
-
"@oh-my-pi/pi-utils": "16.2.
|
|
67
|
-
"@oh-my-pi/pi-wire": "16.2.
|
|
68
|
-
"@oh-my-pi/snapcompact": "16.2.
|
|
58
|
+
"@oh-my-pi/hashline": "16.2.8",
|
|
59
|
+
"@oh-my-pi/omp-stats": "16.2.8",
|
|
60
|
+
"@oh-my-pi/pi-agent-core": "16.2.8",
|
|
61
|
+
"@oh-my-pi/pi-ai": "16.2.8",
|
|
62
|
+
"@oh-my-pi/pi-catalog": "16.2.8",
|
|
63
|
+
"@oh-my-pi/pi-mnemopi": "16.2.8",
|
|
64
|
+
"@oh-my-pi/pi-natives": "16.2.8",
|
|
65
|
+
"@oh-my-pi/pi-tui": "16.2.8",
|
|
66
|
+
"@oh-my-pi/pi-utils": "16.2.8",
|
|
67
|
+
"@oh-my-pi/pi-wire": "16.2.8",
|
|
68
|
+
"@oh-my-pi/snapcompact": "16.2.8",
|
|
69
69
|
"@opentelemetry/api": "^1.9.1",
|
|
70
70
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
71
71
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|
package/src/cli/bench-cli.ts
CHANGED
|
@@ -10,9 +10,10 @@ import type {
|
|
|
10
10
|
Model,
|
|
11
11
|
ProviderSessionState,
|
|
12
12
|
ServiceTier,
|
|
13
|
+
ServiceTierByFamily,
|
|
13
14
|
SimpleStreamOptions,
|
|
14
15
|
} from "@oh-my-pi/pi-ai";
|
|
15
|
-
import { streamSimple } from "@oh-my-pi/pi-ai";
|
|
16
|
+
import { resolveModelServiceTier, streamSimple } from "@oh-my-pi/pi-ai";
|
|
16
17
|
import { buildModelProviderPriorityRank, type CanonicalModelVariant } from "@oh-my-pi/pi-catalog/identity";
|
|
17
18
|
import { replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
18
19
|
import { formatDuration, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
getModelMatchPreferences,
|
|
26
27
|
resolveCliModel,
|
|
27
28
|
} from "../config/model-resolver";
|
|
28
|
-
import {
|
|
29
|
+
import { buildServiceTierByFamily, serviceTierForAllFamilies, serviceTierSettingToTier } from "../config/service-tier";
|
|
29
30
|
import { Settings } from "../config/settings";
|
|
30
31
|
import benchPrompt from "../prompts/bench.md" with { type: "text" };
|
|
31
32
|
import { discoverAuthStorage, loadCliExtensionProviders } from "../sdk";
|
|
@@ -106,8 +107,8 @@ export interface BenchSummary {
|
|
|
106
107
|
maxTokens: number;
|
|
107
108
|
models: BenchModelReport[];
|
|
108
109
|
failures: number;
|
|
109
|
-
/** Requested service
|
|
110
|
-
|
|
110
|
+
/** Requested per-family service tiers, resolved per model before reaching the wire. */
|
|
111
|
+
serviceTierByFamily?: ServiceTierByFamily;
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
type BenchStreamSimple = (
|
|
@@ -518,12 +519,18 @@ export async function runBenchCommand(command: BenchCommandArgs, deps: BenchDepe
|
|
|
518
519
|
const runtime = await (deps.createRuntime ?? createDefaultRuntime)();
|
|
519
520
|
try {
|
|
520
521
|
const targets = resolveBenchModels(command.models, runtime.modelRegistry, runtime.settings, writeStderr);
|
|
521
|
-
// Explicit `--service-tier`
|
|
522
|
-
//
|
|
523
|
-
//
|
|
524
|
-
const
|
|
525
|
-
const
|
|
526
|
-
|
|
522
|
+
// Explicit `--service-tier` (a single value broadcast across families) wins;
|
|
523
|
+
// otherwise fall back to the configured per-family `tier.*` settings. Each
|
|
524
|
+
// model resolves its own family's tier below before reaching the wire.
|
|
525
|
+
const flagTier = command.flags.serviceTier ? serviceTierSettingToTier(command.flags.serviceTier) : undefined;
|
|
526
|
+
const serviceTierByFamily = command.flags.serviceTier
|
|
527
|
+
? serviceTierForAllFamilies(flagTier)
|
|
528
|
+
: buildServiceTierByFamily(
|
|
529
|
+
runtime.settings?.get("tier.openai") ?? "none",
|
|
530
|
+
runtime.settings?.get("tier.anthropic") ?? "none",
|
|
531
|
+
runtime.settings?.get("tier.google") ?? "none",
|
|
532
|
+
);
|
|
533
|
+
if (!json && flagTier) writeStdout(`${chalk.dim(`service tier: ${flagTier}`)}\n`);
|
|
527
534
|
const reports: BenchModelReport[] = [];
|
|
528
535
|
for (const { selector, model, thinking } of targets) {
|
|
529
536
|
if (!json) {
|
|
@@ -564,7 +571,7 @@ export async function runBenchCommand(command: BenchCommandArgs, deps: BenchDepe
|
|
|
564
571
|
maxTokens,
|
|
565
572
|
reasoning: toReasoningEffort(thinking),
|
|
566
573
|
disableReasoning: shouldDisableReasoning(thinking) ? true : undefined,
|
|
567
|
-
serviceTier,
|
|
574
|
+
serviceTier: resolveModelServiceTier(serviceTierByFamily, model),
|
|
568
575
|
},
|
|
569
576
|
streamFn,
|
|
570
577
|
now,
|
|
@@ -606,7 +613,7 @@ export async function runBenchCommand(command: BenchCommandArgs, deps: BenchDepe
|
|
|
606
613
|
reports.push(buildModelReport(selector, model, thinking, results));
|
|
607
614
|
}
|
|
608
615
|
const failures = reports.reduce((sum, report) => sum + report.results.filter(result => !result.ok).length, 0);
|
|
609
|
-
const summary: BenchSummary = { runs, maxTokens, models: reports, failures,
|
|
616
|
+
const summary: BenchSummary = { runs, maxTokens, models: reports, failures, serviceTierByFamily };
|
|
610
617
|
if (json) {
|
|
611
618
|
writeStdout(`${JSON.stringify(summary, null, 2)}\n`);
|
|
612
619
|
} else if (reports.length > 1 || runs > 1) {
|
|
@@ -28,12 +28,21 @@ interface ProgressReporter {
|
|
|
28
28
|
interface DownloadResult {
|
|
29
29
|
model: TinyLocalModelKey;
|
|
30
30
|
ok: boolean;
|
|
31
|
+
error?: string;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
function writeLine(text = ""): void {
|
|
34
35
|
process.stdout.write(`${text}\n`);
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
function downloadErrorSummary(error: string | undefined): string | undefined {
|
|
39
|
+
return error
|
|
40
|
+
?.split(/\r?\n/)
|
|
41
|
+
.map(line => line.trim())
|
|
42
|
+
.find(line => line.length > 0)
|
|
43
|
+
?.replace(/^Error:\s*/, "");
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
export function resolveModels(model: string | undefined): TinyLocalModelKey[] {
|
|
38
47
|
if (!model) return [DEFAULT_TINY_TITLE_LOCAL_MODEL_KEY];
|
|
39
48
|
// `all` is a prefetch convenience: skip models that fail before load (unsupported
|
|
@@ -101,10 +110,15 @@ async function downloadOne(modelKey: TinyLocalModelKey, json: boolean | undefine
|
|
|
101
110
|
const label = getTinyLocalModelSpec(modelKey)?.label ?? modelKey;
|
|
102
111
|
if (!json && !process.stdout.isTTY) writeLine(`Downloading ${label} (${modelKey})...`);
|
|
103
112
|
const progress = makeProgressReporter(modelKey, json);
|
|
104
|
-
const
|
|
105
|
-
progress.finish(ok);
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
const result = await tinyTitleClient.downloadModel(modelKey, { onProgress: progress.onProgress });
|
|
114
|
+
progress.finish(result.ok);
|
|
115
|
+
const error = downloadErrorSummary(result.error);
|
|
116
|
+
if (!json && !process.stdout.isTTY) {
|
|
117
|
+
writeLine(result.ok ? `Downloaded ${label}.` : `Failed to download ${label}${error ? `: ${error}` : ""}.`);
|
|
118
|
+
} else if (!json && !result.ok && error) {
|
|
119
|
+
writeLine(`${label} failed: ${error}`);
|
|
120
|
+
}
|
|
121
|
+
return result.error ? { model: modelKey, ok: result.ok, error: result.error } : { model: modelKey, ok: result.ok };
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
export async function runTinyModelsCommand(command: TinyModelsCommandArgs): Promise<void> {
|
package/src/commands/bench.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
2
2
|
import { runBenchCommand } from "../cli/bench-cli";
|
|
3
|
-
import {
|
|
3
|
+
import { SERVICE_TIER_OPENAI_VALUES } from "../config/service-tier";
|
|
4
4
|
|
|
5
5
|
export default class Bench extends Command {
|
|
6
6
|
static description =
|
|
@@ -19,8 +19,8 @@ export default class Bench extends Command {
|
|
|
19
19
|
"max-tokens": Flags.integer({ description: "Max output tokens per request", default: 512 }),
|
|
20
20
|
prompt: Flags.string({ description: "Custom prompt text (default: bundled bench prompt)" }),
|
|
21
21
|
"service-tier": Flags.string({
|
|
22
|
-
description: "Service tier
|
|
23
|
-
options:
|
|
22
|
+
description: "Service tier applied per model family (default: configured `tier.*` settings; `none` omits it)",
|
|
23
|
+
options: SERVICE_TIER_OPENAI_VALUES,
|
|
24
24
|
}),
|
|
25
25
|
json: Flags.boolean({ description: "Output JSON" }),
|
|
26
26
|
par: Flags.integer({ description: "Execute runs with N parallel queries/requests", default: 4 }),
|
|
@@ -22,7 +22,16 @@
|
|
|
22
22
|
},
|
|
23
23
|
"disabledServers": {
|
|
24
24
|
"type": "array",
|
|
25
|
-
"description": "User-level denylist for disabling discovered servers by name.",
|
|
25
|
+
"description": "User-level denylist for disabling discovered servers by name. Highest precedence: a server here is hidden regardless of any other source.",
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"minLength": 1
|
|
29
|
+
},
|
|
30
|
+
"uniqueItems": true
|
|
31
|
+
},
|
|
32
|
+
"enabledServers": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"description": "User-level allowlist that overrides a discovered server's `enabled: false` flag (e.g. when the source config is owned by another tool such as opencode.json). The denylist still wins.",
|
|
26
35
|
"items": {
|
|
27
36
|
"type": "string",
|
|
28
37
|
"minLength": 1
|
|
@@ -1,87 +1,116 @@
|
|
|
1
|
-
import type { ServiceTier } from "@oh-my-pi/pi-ai";
|
|
1
|
+
import type { ServiceTier, ServiceTierByFamily } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import type { SubmenuOption } from "./settings-schema";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Per-family service-tier setting values. `"none"` is the omit-the-parameter
|
|
6
|
+
* sentinel; the rest mirror the wire {@link ServiceTier} values each provider
|
|
7
|
+
* family actually realizes. OpenAI accepts the full set; Anthropic realizes
|
|
8
|
+
* only `priority` (fast mode); Google (Gemini API + Vertex) realizes
|
|
9
|
+
* `flex`/`priority`.
|
|
8
10
|
*/
|
|
9
|
-
export const
|
|
11
|
+
export const SERVICE_TIER_OPENAI_VALUES = ["none", "auto", "default", "flex", "scale", "priority"] as const;
|
|
12
|
+
export const SERVICE_TIER_ANTHROPIC_VALUES = ["none", "priority"] as const;
|
|
13
|
+
export const SERVICE_TIER_GOOGLE_VALUES = ["none", "flex", "priority"] as const;
|
|
14
|
+
|
|
15
|
+
export type ServiceTierOpenAISettingValue = (typeof SERVICE_TIER_OPENAI_VALUES)[number];
|
|
16
|
+
export type ServiceTierAnthropicSettingValue = (typeof SERVICE_TIER_ANTHROPIC_VALUES)[number];
|
|
17
|
+
export type ServiceTierGoogleSettingValue = (typeof SERVICE_TIER_GOOGLE_VALUES)[number];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Inherit-capable single value for the subagent/advisor tiers. The chosen tier
|
|
21
|
+
* is broadcast across families and applied to whichever family the spawned
|
|
22
|
+
* model belongs to (clamped to what that family realizes); `"inherit"` defers
|
|
23
|
+
* to the main agent's live per-family selection.
|
|
24
|
+
*/
|
|
25
|
+
export const SERVICE_TIER_INHERIT_SETTING_VALUES = [
|
|
26
|
+
"inherit",
|
|
10
27
|
"none",
|
|
11
28
|
"auto",
|
|
12
29
|
"default",
|
|
13
30
|
"flex",
|
|
14
31
|
"scale",
|
|
15
32
|
"priority",
|
|
16
|
-
"openai-only",
|
|
17
|
-
"claude-only",
|
|
18
33
|
] as const;
|
|
19
34
|
|
|
20
|
-
export type ServiceTierSettingValue = (typeof SERVICE_TIER_SETTING_VALUES)[number];
|
|
21
|
-
|
|
22
|
-
/** Variant value set for scoped service-tier settings (subagent/advisor) that can defer to the main agent. */
|
|
23
|
-
export const SERVICE_TIER_INHERIT_SETTING_VALUES = ["inherit", ...SERVICE_TIER_SETTING_VALUES] as const;
|
|
24
|
-
|
|
25
35
|
export type ServiceTierInheritSettingValue = (typeof SERVICE_TIER_INHERIT_SETTING_VALUES)[number];
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{ value: "
|
|
30
|
-
{ value: "
|
|
31
|
-
{ value: "
|
|
32
|
-
{ value: "
|
|
33
|
-
{ value: "
|
|
37
|
+
export const SERVICE_TIER_OPENAI_OPTIONS: ReadonlyArray<SubmenuOption<ServiceTierOpenAISettingValue>> = [
|
|
38
|
+
{ value: "none", label: "None", description: "Omit service_tier (standard processing)" },
|
|
39
|
+
{ value: "auto", label: "Auto", description: "Provider default tier selection" },
|
|
40
|
+
{ value: "default", label: "Default", description: "Standard priority processing" },
|
|
41
|
+
{ value: "flex", label: "Flex", description: "Lower cost, higher latency when available" },
|
|
42
|
+
{ value: "scale", label: "Scale", description: "Scale Tier credits when available" },
|
|
43
|
+
{ value: "priority", label: "Priority", description: "Faster, higher cost (premium request)" },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
export const SERVICE_TIER_ANTHROPIC_OPTIONS: ReadonlyArray<SubmenuOption<ServiceTierAnthropicSettingValue>> = [
|
|
47
|
+
{ value: "none", label: "None", description: "Standard processing" },
|
|
34
48
|
{
|
|
35
49
|
value: "priority",
|
|
36
50
|
label: "Priority",
|
|
37
|
-
description: "
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
value: "openai-only",
|
|
41
|
-
label: "Priority (OpenAI only)",
|
|
42
|
-
description: "Priority on OpenAI/OpenAI-Codex requests; ignored elsewhere",
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
value: "claude-only",
|
|
46
|
-
label: "Priority (Claude only)",
|
|
47
|
-
description: "Anthropic fast mode on direct Claude requests; ignored elsewhere (incl. Bedrock/Vertex)",
|
|
51
|
+
description: 'Fast mode (`speed: "fast"`) on supported direct Claude models; ignored on Bedrock/Vertex',
|
|
48
52
|
},
|
|
49
53
|
];
|
|
50
54
|
|
|
51
|
-
|
|
55
|
+
export const SERVICE_TIER_GOOGLE_OPTIONS: ReadonlyArray<SubmenuOption<ServiceTierGoogleSettingValue>> = [
|
|
56
|
+
{ value: "none", label: "None", description: "Standard processing" },
|
|
57
|
+
{ value: "flex", label: "Flex", description: "Lower cost, higher latency (Gemini API + Vertex)" },
|
|
58
|
+
{ value: "priority", label: "Priority", description: "Faster, higher reliability (Gemini API + Vertex)" },
|
|
59
|
+
];
|
|
60
|
+
|
|
52
61
|
export const SERVICE_TIER_INHERIT_OPTIONS: ReadonlyArray<SubmenuOption<ServiceTierInheritSettingValue>> = [
|
|
53
|
-
{ value: "inherit", label: "Inherit", description: "
|
|
54
|
-
|
|
62
|
+
{ value: "inherit", label: "Inherit", description: "Match the main agent's live per-family tiers" },
|
|
63
|
+
{ value: "none", label: "None", description: "Standard processing" },
|
|
64
|
+
{ value: "auto", label: "Auto", description: "Provider default tier selection (OpenAI family)" },
|
|
65
|
+
{ value: "default", label: "Default", description: "Standard priority processing (OpenAI family)" },
|
|
66
|
+
{ value: "flex", label: "Flex", description: "Flexible capacity tier (OpenAI/Google families)" },
|
|
67
|
+
{ value: "scale", label: "Scale", description: "Scale Tier credits (OpenAI family)" },
|
|
68
|
+
{ value: "priority", label: "Priority", description: "Priority on every supported family of the spawned model" },
|
|
55
69
|
];
|
|
56
70
|
|
|
71
|
+
/** Map a per-family setting value to a wire {@link ServiceTier}, or `undefined` to omit. */
|
|
72
|
+
export function serviceTierSettingToTier(value: string): ServiceTier | undefined {
|
|
73
|
+
if (value === "none" || value === "" || value === "inherit") return undefined;
|
|
74
|
+
return value as ServiceTier;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Assemble the live per-family tier map from the three `tier.*` setting values. */
|
|
78
|
+
export function buildServiceTierByFamily(openai: string, anthropic: string, google: string): ServiceTierByFamily {
|
|
79
|
+
const out: ServiceTierByFamily = {};
|
|
80
|
+
const o = serviceTierSettingToTier(openai);
|
|
81
|
+
if (o) out.openai = o;
|
|
82
|
+
const a = serviceTierSettingToTier(anthropic);
|
|
83
|
+
if (a) out.anthropic = a;
|
|
84
|
+
const g = serviceTierSettingToTier(google);
|
|
85
|
+
if (g) out.google = g;
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
57
89
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
90
|
+
* Broadcast a single chosen tier across families, clamped to what each family
|
|
91
|
+
* realizes: OpenAI takes any tier, Anthropic only `priority`, Google only
|
|
92
|
+
* `flex`/`priority`. Used by the subagent/advisor single-value settings and the
|
|
93
|
+
* `omp bench --service-tier` flag, which apply one tier to whatever family the
|
|
94
|
+
* target model belongs to.
|
|
60
95
|
*/
|
|
61
|
-
export function
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
96
|
+
export function serviceTierForAllFamilies(tier: ServiceTier | undefined): ServiceTierByFamily {
|
|
97
|
+
if (!tier) return {};
|
|
98
|
+
const out: ServiceTierByFamily = { openai: tier };
|
|
99
|
+
if (tier === "priority") out.anthropic = "priority";
|
|
100
|
+
if (tier === "flex" || tier === "priority") out.google = tier;
|
|
101
|
+
return out;
|
|
65
102
|
}
|
|
66
103
|
|
|
67
104
|
/**
|
|
68
|
-
* Resolve
|
|
69
|
-
* snapshot.
|
|
105
|
+
* Resolve a subagent/advisor service-tier setting to a per-family map.
|
|
70
106
|
*
|
|
71
|
-
* - A concrete
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* back to the parent's configured `serviceTier` setting so behavior matches a
|
|
77
|
-
* plain settings snapshot.
|
|
107
|
+
* - A concrete tier is broadcast across families (see
|
|
108
|
+
* {@link serviceTierForAllFamilies}).
|
|
109
|
+
* - `"none"` yields an empty map.
|
|
110
|
+
* - `"inherit"` defers to `inherited` — the parent's live per-family tiers when
|
|
111
|
+
* a live session supplied them, else the empty map.
|
|
78
112
|
*/
|
|
79
|
-
export function resolveSubagentServiceTier(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
inherited: ServiceTier | null | undefined,
|
|
83
|
-
): ServiceTierSettingValue {
|
|
84
|
-
if (subagentSetting !== "inherit") return subagentSetting as ServiceTierSettingValue;
|
|
85
|
-
if (inherited === undefined) return configuredTier;
|
|
86
|
-
return inherited ?? "none";
|
|
113
|
+
export function resolveSubagentServiceTier(setting: string, inherited: ServiceTierByFamily): ServiceTierByFamily {
|
|
114
|
+
if (setting === "inherit") return inherited;
|
|
115
|
+
return serviceTierForAllFamilies(serviceTierSettingToTier(setting));
|
|
87
116
|
}
|