@oh-my-pi/pi-coding-agent 16.1.1 → 16.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/dist/cli.js +3090 -3115
- package/dist/types/cli/bench-cli.d.ts +2 -1
- package/dist/types/config/model-resolver.d.ts +3 -3
- package/dist/types/config/settings-schema.d.ts +1 -1
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mnemopi/embed-client.d.ts +70 -0
- package/dist/types/mnemopi/embed-protocol.d.ts +52 -0
- package/dist/types/mnemopi/embed-worker.d.ts +12 -0
- package/dist/types/mnemopi/state.d.ts +9 -1
- package/dist/types/modes/components/assistant-message.d.ts +12 -0
- package/dist/types/modes/components/welcome.d.ts +1 -1
- package/dist/types/sdk.d.ts +19 -2
- package/dist/types/session/agent-storage.d.ts +2 -0
- package/dist/types/session/auth-broker-config.d.ts +34 -6
- package/dist/types/session/history-storage.d.ts +1 -1
- package/dist/types/system-prompt.d.ts +5 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/tools/find.d.ts +0 -2
- package/dist/types/tools/image-gen.d.ts +2 -2
- package/dist/types/tools/search.d.ts +3 -3
- package/dist/types/utils/image-loading.d.ts +1 -1
- package/dist/types/utils/ipc.d.ts +22 -0
- package/dist/types/web/search/providers/perplexity-auth.d.ts +37 -0
- package/package.json +12 -12
- package/scripts/measure-prompt-tokens.ts +63 -0
- package/src/cli/bench-cli.ts +64 -3
- package/src/cli/startup-cwd.ts +3 -13
- package/src/cli.ts +8 -0
- package/src/commands/token.ts +52 -33
- package/src/config/append-only-context-mode.ts +45 -0
- package/src/config/model-discovery.ts +3 -0
- package/src/config/model-registry.ts +21 -3
- package/src/config/model-resolver.ts +31 -8
- package/src/config/settings-schema.ts +1 -1
- package/src/cursor.ts +1 -1
- package/src/debug/raw-sse-buffer.ts +31 -10
- package/src/discovery/builtin-rules/ts-no-return-type.md +0 -1
- package/src/eval/py/prelude.py +1 -1
- package/src/export/html/tool-views.generated.js +1 -1
- package/src/extensibility/extensions/runner.ts +8 -2
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/lsp/client.ts +24 -0
- package/src/main.ts +29 -9
- package/src/mnemopi/backend.ts +49 -3
- package/src/mnemopi/embed-client.ts +401 -0
- package/src/mnemopi/embed-protocol.ts +35 -0
- package/src/mnemopi/embed-worker.ts +113 -0
- package/src/mnemopi/state.ts +29 -1
- package/src/modes/components/assistant-message.ts +86 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/welcome.ts +87 -9
- package/src/modes/controllers/event-controller.ts +9 -1
- package/src/modes/controllers/selector-controller.ts +2 -2
- package/src/modes/theme/theme.ts +69 -0
- package/src/prompts/system/personalities/default.md +8 -16
- package/src/prompts/system/system-prompt.md +101 -115
- package/src/prompts/tools/ast-edit.md +10 -12
- package/src/prompts/tools/ast-grep.md +14 -18
- package/src/prompts/tools/bash.md +19 -21
- package/src/prompts/tools/browser.md +24 -24
- package/src/prompts/tools/checkpoint.md +0 -1
- package/src/prompts/tools/debug.md +11 -15
- package/src/prompts/tools/eval.md +27 -27
- package/src/prompts/tools/find.md +6 -10
- package/src/prompts/tools/github.md +11 -15
- package/src/prompts/tools/goal.md +0 -7
- package/src/prompts/tools/inspect-image.md +0 -1
- package/src/prompts/tools/irc.md +15 -24
- package/src/prompts/tools/job.md +5 -8
- package/src/prompts/tools/learn.md +2 -2
- package/src/prompts/tools/lsp.md +27 -30
- package/src/prompts/tools/manage-skill.md +4 -4
- package/src/prompts/tools/read.md +21 -23
- package/src/prompts/tools/replace.md +0 -1
- package/src/prompts/tools/resolve.md +4 -9
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search.md +8 -10
- package/src/prompts/tools/task.md +33 -38
- package/src/prompts/tools/todo.md +14 -18
- package/src/prompts/tools/web-search.md +0 -4
- package/src/prompts/tools/write.md +1 -1
- package/src/sdk.ts +53 -102
- package/src/session/agent-session.ts +25 -2
- package/src/session/agent-storage.ts +14 -0
- package/src/session/auth-broker-config.ts +37 -76
- package/src/session/history-storage.ts +13 -1
- package/src/session/session-history-format.ts +1 -1
- package/src/session/session-manager.ts +33 -6
- package/src/stt/asr-client.ts +2 -7
- package/src/system-prompt.ts +28 -8
- package/src/task/executor.ts +57 -0
- package/src/task/index.ts +15 -1
- package/src/tiny/title-client.ts +2 -7
- package/src/tools/browser.ts +1 -1
- package/src/tools/eval.ts +1 -1
- package/src/tools/find.ts +4 -17
- package/src/tools/image-gen.ts +4 -8
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/render-utils.ts +4 -1
- package/src/tools/search.ts +5 -5
- package/src/tts/tts-client.ts +2 -7
- package/src/utils/image-loading.ts +12 -2
- package/src/utils/ipc.ts +38 -0
- package/src/web/search/providers/perplexity-auth.ts +133 -0
- package/src/web/search/providers/perplexity.ts +2 -125
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ResolvedThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Api, ApiKeyResolver, AssistantMessageEventStream, Context, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import type
|
|
3
|
+
import { type CanonicalModelVariant } from "@oh-my-pi/pi-catalog/identity";
|
|
4
4
|
import type { ApiKeyResolverModel } from "../config/api-key-resolver";
|
|
5
5
|
import { type CanonicalModelQueryOptions } from "../config/model-registry";
|
|
6
6
|
import { Settings } from "../config/settings";
|
|
@@ -20,6 +20,7 @@ export interface BenchModelRegistry {
|
|
|
20
20
|
resolveCanonicalModel?(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
|
|
21
21
|
getCanonicalVariants?(canonicalId: string, options?: CanonicalModelQueryOptions): CanonicalModelVariant[];
|
|
22
22
|
getCanonicalId?(model: Model<Api>): string | undefined;
|
|
23
|
+
hasConfiguredAuth?(model: Model<Api>): boolean;
|
|
23
24
|
}
|
|
24
25
|
export interface BenchRuntime {
|
|
25
26
|
modelRegistry: BenchModelRegistry;
|
|
@@ -201,9 +201,9 @@ export declare function resolveModelScope(patterns: string[], modelRegistry: Pic
|
|
|
201
201
|
* the result to models matching those patterns.
|
|
202
202
|
*
|
|
203
203
|
* Returns the unfiltered available list when `enabledModels` is empty.
|
|
204
|
-
* Returns an empty list when `enabledModels` is configured but no
|
|
205
|
-
*
|
|
206
|
-
*
|
|
204
|
+
* Returns an empty list when `enabledModels` is configured but no model matches
|
|
205
|
+
* any pattern — callers MUST treat this as "no usable model" rather than
|
|
206
|
+
* falling back to the global default (see issue #1022).
|
|
207
207
|
*/
|
|
208
208
|
export declare function resolveAllowedModels(modelRegistry: Pick<ModelRegistry, "getAvailable" | "getCanonicalVariants">, settings: Settings | undefined, preferences?: ModelMatchPreferences): Promise<Model<Api>[]>;
|
|
209
209
|
/**
|
package/dist/types/main.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export declare class SessionResolutionError extends Error {
|
|
|
54
54
|
}
|
|
55
55
|
/** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
|
|
56
56
|
export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: SessionPrompt, askToMoveSession?: SessionPrompt): Promise<SessionManager | undefined>;
|
|
57
|
+
/** Apply resolved CLI/discovered prompt files without bypassing system prompt templates. */
|
|
58
|
+
export declare function applyResolvedSystemPromptInputs(options: CreateAgentSessionOptions, resolvedSystemPrompt: string | undefined, resolvedAppendPrompt: string | undefined): void;
|
|
57
59
|
interface RunRootCommandDependencies {
|
|
58
60
|
createAgentSession?: typeof createAgentSession;
|
|
59
61
|
discoverAuthStorage?: typeof discoverAuthStorage;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Subprocess } from "bun";
|
|
2
|
+
import type { MnemopiEmbedModelId, MnemopiEmbedWorkerInbound, MnemopiEmbedWorkerOutbound } from "./embed-protocol";
|
|
3
|
+
/**
|
|
4
|
+
* Abstraction over the mnemopi embeddings subprocess. The runtime
|
|
5
|
+
* implementation is a Bun child process so `onnxruntime-node`'s NAPI
|
|
6
|
+
* constructor + finalizer never run inside the main agent address space —
|
|
7
|
+
* those destructors segfault Bun on Windows when mnemopi's local embedding
|
|
8
|
+
* provider loads fastembed in the main process (issue #3031; the mnemopi
|
|
9
|
+
* sibling of the tiny-model fix from #1606 / #1607).
|
|
10
|
+
*/
|
|
11
|
+
export interface MnemopiEmbedWorkerHandle {
|
|
12
|
+
send(message: MnemopiEmbedWorkerInbound): void;
|
|
13
|
+
onMessage(handler: (message: MnemopiEmbedWorkerOutbound) => void): () => void;
|
|
14
|
+
onError(handler: (error: Error) => void): () => void;
|
|
15
|
+
terminate(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hidden subcommand on the main CLI that boots the mnemopi embeddings worker
|
|
19
|
+
* in the spawned subprocess. Kept in sync with the dispatch in `cli.ts`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MNEMOPI_EMBED_WORKER_ARG = "__omp_worker_mnemopi_embed";
|
|
22
|
+
interface SpawnedSubprocess {
|
|
23
|
+
proc: Subprocess<"ignore", "ignore", "ignore">;
|
|
24
|
+
inbound: Set<(message: MnemopiEmbedWorkerOutbound) => void>;
|
|
25
|
+
errors: Set<(error: Error) => void>;
|
|
26
|
+
/**
|
|
27
|
+
* Flipped to `true` right before the deliberate SIGKILL so `onExit` can
|
|
28
|
+
* distinguish the expected hard-kill from a crash (SIGSEGV from a native
|
|
29
|
+
* fault, OOM SIGKILL, operator `kill -9`). Only the latter surfaces as a
|
|
30
|
+
* worker error so callers don't await forever.
|
|
31
|
+
*/
|
|
32
|
+
intentionalExit: {
|
|
33
|
+
value: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Spawn the mnemopi embeddings worker as a subprocess. Exported for tests and
|
|
38
|
+
* the smoke probe; production callers go through {@link spawnMnemopiEmbedWorker}.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createMnemopiEmbedSubprocess(): SpawnedSubprocess;
|
|
41
|
+
/**
|
|
42
|
+
* Per-model wrapper produced by {@link MnemopiEmbedClient.initialize}.
|
|
43
|
+
* `embed()` round-trips one batch of texts through the worker subprocess and
|
|
44
|
+
* yields the resulting vectors in a single asynchronous batch — fastembed's
|
|
45
|
+
* own iterator was emitting batches that we collect on the child side anyway,
|
|
46
|
+
* and serializing per-batch over IPC would not improve throughput.
|
|
47
|
+
*/
|
|
48
|
+
export interface MnemopiSubprocessEmbeddingModel {
|
|
49
|
+
embed(texts: string[], batchSize?: number): AsyncIterable<number[][]>;
|
|
50
|
+
}
|
|
51
|
+
export declare class MnemopiEmbedClient {
|
|
52
|
+
#private;
|
|
53
|
+
constructor(spawnWorker?: () => MnemopiEmbedWorkerHandle);
|
|
54
|
+
/**
|
|
55
|
+
* Load the named fastembed model inside the subprocess. Resolves to a
|
|
56
|
+
* thin wrapper whose `embed()` round-trips through the same worker, or
|
|
57
|
+
* `null` when the worker cannot init the model (missing peer, native
|
|
58
|
+
* load failure, etc.). Multiple calls with the same model reuse the
|
|
59
|
+
* single in-flight worker; calling with a different model loads it on
|
|
60
|
+
* the child without restarting the process.
|
|
61
|
+
*/
|
|
62
|
+
initialize(model: MnemopiEmbedModelId, cacheDir: string | undefined): Promise<MnemopiSubprocessEmbeddingModel | null>;
|
|
63
|
+
terminate(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
export declare const mnemopiEmbedClient: MnemopiEmbedClient;
|
|
66
|
+
export declare function shutdownMnemopiEmbedClient(): Promise<void>;
|
|
67
|
+
export declare function smokeTestMnemopiEmbedWorker({ timeoutMs, }?: {
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
}): Promise<void>;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types between the parent (`MnemopiEmbedClient`) and the local
|
|
3
|
+
* embeddings subprocess. The parent owns the subprocess lifecycle (graceful
|
|
4
|
+
* work, hard `SIGKILL` on shutdown); the protocol carries no explicit close
|
|
5
|
+
* handshake — once the parent decides to terminate, it signals the OS to reap
|
|
6
|
+
* the child so `onnxruntime-node`'s NAPI finalizer never runs in the main
|
|
7
|
+
* agent address space (it crashes Bun on Windows shutdown — issue #3031, the
|
|
8
|
+
* mnemopi sibling of the tiny-model fix from #1606/#1607). See
|
|
9
|
+
* `embed-client.ts` for the spawn/kill glue.
|
|
10
|
+
*/
|
|
11
|
+
/** Identifier of the fastembed model the worker should load (e.g. `fast-bge-base-en-v1.5`). */
|
|
12
|
+
export type MnemopiEmbedModelId = string;
|
|
13
|
+
export type MnemopiEmbedWorkerInbound = {
|
|
14
|
+
type: "ping";
|
|
15
|
+
id: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: "init";
|
|
18
|
+
id: string;
|
|
19
|
+
model: MnemopiEmbedModelId;
|
|
20
|
+
cacheDir?: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "embed";
|
|
23
|
+
id: string;
|
|
24
|
+
model: MnemopiEmbedModelId;
|
|
25
|
+
cacheDir?: string;
|
|
26
|
+
texts: string[];
|
|
27
|
+
batchSize?: number;
|
|
28
|
+
};
|
|
29
|
+
export type MnemopiEmbedWorkerOutbound = {
|
|
30
|
+
type: "pong";
|
|
31
|
+
id: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "ready";
|
|
34
|
+
id: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: "vectors";
|
|
37
|
+
id: string;
|
|
38
|
+
vectors: number[][];
|
|
39
|
+
} | {
|
|
40
|
+
type: "error";
|
|
41
|
+
id: string;
|
|
42
|
+
error: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: "log";
|
|
45
|
+
level: "debug" | "warn" | "error";
|
|
46
|
+
msg: string;
|
|
47
|
+
meta?: Record<string, unknown>;
|
|
48
|
+
};
|
|
49
|
+
export interface MnemopiEmbedTransport {
|
|
50
|
+
send(message: MnemopiEmbedWorkerOutbound): void;
|
|
51
|
+
onMessage(handler: (message: MnemopiEmbedWorkerInbound) => void): () => void;
|
|
52
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mnemopi local-embeddings worker. Loaded inside the dedicated subprocess
|
|
3
|
+
* spawned by `embed-client.ts` (re-entered through the agent CLI's hidden
|
|
4
|
+
* `__omp_worker_mnemopi_embed` selector). The whole point of this module is
|
|
5
|
+
* that `loadFastembed()` — and therefore `onnxruntime-node`'s NAPI
|
|
6
|
+
* constructor + finalizer — only ever runs in this child address space. The
|
|
7
|
+
* parent `SIGKILL`s us on shutdown so the destructor that crashes Bun on
|
|
8
|
+
* Windows shutdown (issue #3031, mnemopi sibling of #1606/#1607) never runs
|
|
9
|
+
* in either process.
|
|
10
|
+
*/
|
|
11
|
+
import type { MnemopiEmbedTransport } from "./embed-protocol";
|
|
12
|
+
export declare function startMnemopiEmbedWorker(transport: MnemopiEmbedTransport): void;
|
|
@@ -4,7 +4,15 @@ import type { Mnemopi, RecallResult } from "@oh-my-pi/pi-mnemopi";
|
|
|
4
4
|
import type * as MnemopiCoreNs from "@oh-my-pi/pi-mnemopi/core";
|
|
5
5
|
import type { AgentSession } from "../session/agent-session";
|
|
6
6
|
import type { MnemopiBackendConfig } from "./config";
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Lazily load `@oh-my-pi/pi-mnemopi` (memoized) and route fastembed loads
|
|
9
|
+
* through the dedicated embeddings subprocess. The override is installed once
|
|
10
|
+
* — before any consumer gets the chance to call `embed()` — so
|
|
11
|
+
* `onnxruntime-node`'s NAPI constructor + finalizer never run inside the
|
|
12
|
+
* agent's address space (issue #3031). Test seams that swap the initializer
|
|
13
|
+
* with `setLocalModelInitializerForTests` still win because both go through
|
|
14
|
+
* the same module-level slot.
|
|
15
|
+
*/
|
|
8
16
|
export declare function loadMnemopi(): Promise<typeof MnemopiNs>;
|
|
9
17
|
/** Lazily load `@oh-my-pi/pi-mnemopi/core` (memoized). */
|
|
10
18
|
export declare function loadMnemopiCore(): Promise<typeof MnemopiCoreNs>;
|
|
@@ -28,6 +28,18 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
28
28
|
*/
|
|
29
29
|
setErrorPinned(pinned: boolean): void;
|
|
30
30
|
isTranscriptBlockFinalized(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Whether this still-live block's scrolled-off rows may be committed to
|
|
33
|
+
* immutable native scrollback (the {@link TranscriptContainer} durable-
|
|
34
|
+
* snapshot path). Reflowing Markdown — a streaming mermaid diagram or a GFM
|
|
35
|
+
* table — re-lays-out its body as source arrives (the diagram reshapes, the
|
|
36
|
+
* table re-aligns its columns), so committing an intermediate layout strands
|
|
37
|
+
* a stale fragment in native scrollback that only a full repaint (Ctrl+L) can
|
|
38
|
+
* clear. While such content is still streaming the block therefore stays
|
|
39
|
+
* wholly in the repaintable live region and commits once, at its final
|
|
40
|
+
* layout, when the turn finalizes.
|
|
41
|
+
*/
|
|
42
|
+
isTranscriptBlockCommitStable(): boolean;
|
|
31
43
|
getTranscriptBlockVersion(): number;
|
|
32
44
|
markTranscriptBlockFinalized(): void;
|
|
33
45
|
setToolResultImages(toolCallId: string, images: ImageContent[]): void;
|
|
@@ -9,7 +9,7 @@ export declare const WELCOME_SESSION_SLOTS = 4;
|
|
|
9
9
|
* the box height is constant regardless of how many servers a project has.
|
|
10
10
|
*/
|
|
11
11
|
export declare const WELCOME_LSP_SLOTS = 4;
|
|
12
|
-
export declare function renderWelcomeTip(tip: string, boxWidth: number): string[];
|
|
12
|
+
export declare function renderWelcomeTip(tip: string, boxWidth: number, phase?: number): string[];
|
|
13
13
|
export interface RecentSession {
|
|
14
14
|
name: string;
|
|
15
15
|
timeAgo: string;
|
package/dist/types/sdk.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
|
18
18
|
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
19
19
|
import { AgentRegistry } from "./registry/agent-registry";
|
|
20
20
|
import { AgentSession } from "./session/agent-session";
|
|
21
|
-
import { AuthStorage } from "./session/auth-storage";
|
|
21
|
+
import type { AuthStorage } from "./session/auth-storage";
|
|
22
22
|
import { SessionManager } from "./session/session-manager";
|
|
23
23
|
import { type BuildSystemPromptResult } from "./system-prompt";
|
|
24
24
|
import { type ConfiguredThinkingLevel } from "./thinking";
|
|
@@ -48,8 +48,12 @@ export interface CreateAgentSessionOptions {
|
|
|
48
48
|
model: Model;
|
|
49
49
|
thinkingLevel?: ThinkingLevel;
|
|
50
50
|
}>;
|
|
51
|
-
/**
|
|
51
|
+
/** Provider-facing system prompt override. Replaces the fully rendered default blocks. */
|
|
52
52
|
systemPrompt?: string | string[] | ((defaultPrompt: string[]) => string | string[]);
|
|
53
|
+
/** Already-loaded custom prompt text rendered through the bundled custom system prompt template. */
|
|
54
|
+
customSystemPrompt?: string;
|
|
55
|
+
/** Already-loaded text appended through the bundled system prompt templates. */
|
|
56
|
+
appendSystemPrompt?: string;
|
|
53
57
|
/** Optional provider-facing session identifier for prompt caches and sticky auth selection.
|
|
54
58
|
* Keeps persisted session files isolated while reusing provider-side caches. */
|
|
55
59
|
providerSessionId?: string;
|
|
@@ -179,6 +183,15 @@ export interface CreateAgentSessionOptions {
|
|
|
179
183
|
* `@opentelemetry/api` package returns a no-op tracer in that case.
|
|
180
184
|
*/
|
|
181
185
|
telemetry?: AgentTelemetryConfig;
|
|
186
|
+
/**
|
|
187
|
+
* Fired once, when the agent loop hands its first request to the provider
|
|
188
|
+
* transport (i.e. the `streamFn` wrapper is first invoked). Used to measure
|
|
189
|
+
* subagent launch latency — the boundary between "session built" and "model
|
|
190
|
+
* call dispatched". This is the loop's dispatch point, slightly before the
|
|
191
|
+
* actual provider HTTP call (per-request prep, identical across all
|
|
192
|
+
* requests, follows it), which is the right granularity for launch timing.
|
|
193
|
+
*/
|
|
194
|
+
onFirstChatDispatch?: () => void;
|
|
182
195
|
/** Whether to auto-approve all tool calls (--auto-approve CLI flag). Default: false */
|
|
183
196
|
autoApprove?: boolean;
|
|
184
197
|
}
|
|
@@ -222,6 +235,9 @@ export { BashTool, BUILTIN_TOOLS, createTools, EditTool, EvalTool, FindTool, HID
|
|
|
222
235
|
* the client receives access tokens with `refresh = "__remote__"` and calls
|
|
223
236
|
* back into the broker through the {@link AuthStorageOptions.refreshOAuthCredential}
|
|
224
237
|
* override to re-mint access tokens when needed.
|
|
238
|
+
*
|
|
239
|
+
* Delegates to {@link ./session/auth-broker-config} so the TUI and the catalog
|
|
240
|
+
* generator share the same credential-discovery logic.
|
|
225
241
|
*/
|
|
226
242
|
export declare function discoverAuthStorage(agentDir?: string): Promise<AuthStorage>;
|
|
227
243
|
/**
|
|
@@ -287,6 +303,7 @@ export interface BuildSystemPromptOptions {
|
|
|
287
303
|
content: string;
|
|
288
304
|
}>;
|
|
289
305
|
cwd?: string;
|
|
306
|
+
customPrompt?: string;
|
|
290
307
|
appendPrompt?: string;
|
|
291
308
|
inlineToolDescriptors?: boolean;
|
|
292
309
|
}
|
|
@@ -16,6 +16,8 @@ export declare class AgentStorage {
|
|
|
16
16
|
* @returns AgentStorage instance for the given path
|
|
17
17
|
*/
|
|
18
18
|
static open(dbPath?: string): Promise<AgentStorage>;
|
|
19
|
+
/** @internal Reset all singletons and close their databases — test-only. */
|
|
20
|
+
static resetInstance(): void;
|
|
19
21
|
/**
|
|
20
22
|
* Reads legacy settings persisted in the agent.db `settings` table.
|
|
21
23
|
* The canonical settings store is `config.yml`; this accessor only
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Resolve auth-broker connection configuration for the local omp client.
|
|
3
|
+
*
|
|
4
|
+
* This is a thin coding-agent wrapper around the shared resolver in
|
|
5
|
+
* `@oh-my-pi/pi-ai/auth-broker/discover` that preserves the process-lifetime
|
|
6
|
+
* memoization expected by the CLI and injects the full `resolveConfigValue`
|
|
7
|
+
* (including `!command` config indirection) from coding-agent's config layer.
|
|
8
|
+
*
|
|
9
|
+
* Precedence (highest first):
|
|
10
|
+
* 1. `OMP_AUTH_BROKER_URL` / `OMP_AUTH_BROKER_TOKEN` env vars.
|
|
11
|
+
* 2. `auth.broker.url` / `auth.broker.token` in `~/.omp/agent/config.yml`
|
|
12
|
+
* (hidden from the settings UI; `!command` resolution supported).
|
|
13
|
+
* 3. Token file `~/.omp/auth-broker.token` (paired with URL from env or config).
|
|
14
|
+
*
|
|
15
|
+
* Returns null when no broker URL is configured — caller falls back to the
|
|
16
|
+
* local SQLite store.
|
|
17
|
+
*
|
|
18
|
+
* Reads config.yml directly (instead of going through `Settings.init`) because
|
|
19
|
+
* `discoverAuthStorage` runs before the settings singleton is initialized in
|
|
20
|
+
* `runRootCommand`, and we want hand-edited config entries to be honoured at
|
|
21
|
+
* boot without forcing a startup reorder.
|
|
22
|
+
*/
|
|
23
|
+
import { type AuthBrokerClientConfig, type DiscoverAuthStorageOptions, getAuthBrokerTokenFilePath } from "@oh-my-pi/pi-ai/auth-broker/discover";
|
|
24
|
+
import type { AuthStorage } from "./auth-storage";
|
|
25
|
+
export { type AuthBrokerClientConfig, getAuthBrokerTokenFilePath };
|
|
7
26
|
/**
|
|
8
27
|
* Read broker configuration. Returns null when the URL is missing
|
|
9
28
|
* (broker disabled — local store is used). Throws when URL is set but no
|
|
@@ -15,3 +34,12 @@ export declare function getAuthBrokerTokenFilePath(): string;
|
|
|
15
34
|
* retried. Concurrent callers share one in-flight resolution.
|
|
16
35
|
*/
|
|
17
36
|
export declare function resolveAuthBrokerConfig(): Promise<AuthBrokerClientConfig | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Create an AuthStorage instance, using the broker when configured and falling
|
|
39
|
+
* back to the local SQLite store otherwise. Delegates to the shared resolver in
|
|
40
|
+
* pi-ai so the CLI, subagents, and the catalog generator all see the same
|
|
41
|
+
* credentials.
|
|
42
|
+
*
|
|
43
|
+
* Default `agentDir` is the current configured agent directory.
|
|
44
|
+
*/
|
|
45
|
+
export declare function discoverAuthStorage(agentDir?: string, options?: Omit<DiscoverAuthStorageOptions, "agentDir" | "configValueResolver">): Promise<AuthStorage>;
|
|
@@ -10,7 +10,7 @@ export declare class HistoryStorage {
|
|
|
10
10
|
#private;
|
|
11
11
|
private constructor();
|
|
12
12
|
static open(dbPath?: string): HistoryStorage;
|
|
13
|
-
/** @internal Reset the singleton — test-only. */
|
|
13
|
+
/** @internal Reset the singleton and close its database — test-only. */
|
|
14
14
|
static resetInstance(): void;
|
|
15
15
|
/**
|
|
16
16
|
* Register a resolver that supplies the current session ID for prompts added
|
|
@@ -48,13 +48,17 @@ export declare function buildSystemPromptToolMetadata(tools: Map<string, AgentTo
|
|
|
48
48
|
export interface BuildSystemPromptOptions {
|
|
49
49
|
/** Custom system prompt (replaces default). */
|
|
50
50
|
customPrompt?: string;
|
|
51
|
+
/** Already-loaded custom system prompt text; bypasses path resolution. */
|
|
52
|
+
resolvedCustomPrompt?: string;
|
|
51
53
|
/** Tools to include in prompt. */
|
|
52
54
|
tools?: Map<string, SystemPromptToolMetadata>;
|
|
53
55
|
/** Tool names to include in prompt. */
|
|
54
56
|
toolNames?: string[];
|
|
55
57
|
/** Text to append to system prompt. */
|
|
56
58
|
appendSystemPrompt?: string;
|
|
57
|
-
/**
|
|
59
|
+
/** Already-loaded append prompt text; bypasses path resolution. */
|
|
60
|
+
resolvedAppendSystemPrompt?: string;
|
|
61
|
+
/** Inline full tool descriptors in the system prompt. Default: false */
|
|
58
62
|
inlineToolDescriptors?: boolean;
|
|
59
63
|
/**
|
|
60
64
|
* Whether provider-native tool calling is active (no owned/in-band syntax).
|
|
@@ -83,6 +83,16 @@ export interface ExecutorOptions {
|
|
|
83
83
|
enableLsp?: boolean;
|
|
84
84
|
signal?: AbortSignal;
|
|
85
85
|
onProgress?: (progress: AgentProgress) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Epochs (ms, `Date.now()`) bracketing the concurrency-semaphore wait:
|
|
88
|
+
* `invokedAt` is stamped at the spawn boundary before `acquire()`,
|
|
89
|
+
* `acquiredAt` immediately after. {@link runSubprocess} reports true queue
|
|
90
|
+
* wait (`acquiredAt - invokedAt`) and pre-run setup (`startTime - acquiredAt`)
|
|
91
|
+
* separately in the launch-timing debug log. Undefined for callers that
|
|
92
|
+
* bypass the semaphore path.
|
|
93
|
+
*/
|
|
94
|
+
invokedAt?: number;
|
|
95
|
+
acquiredAt?: number;
|
|
86
96
|
sessionFile?: string | null;
|
|
87
97
|
persistArtifacts?: boolean;
|
|
88
98
|
artifactsDir?: string;
|
|
@@ -11,7 +11,6 @@ declare const findSchema: import("arktype/internal/variants/object.ts").ObjectTy
|
|
|
11
11
|
hidden?: boolean | undefined;
|
|
12
12
|
gitignore?: boolean | undefined;
|
|
13
13
|
limit?: number | undefined;
|
|
14
|
-
timeout?: number | undefined;
|
|
15
14
|
}, {}>;
|
|
16
15
|
export type FindToolInput = typeof findSchema.infer;
|
|
17
16
|
export interface FindToolDetails {
|
|
@@ -70,7 +69,6 @@ export declare class FindTool implements AgentTool<typeof findSchema, FindToolDe
|
|
|
70
69
|
hidden?: boolean | undefined;
|
|
71
70
|
gitignore?: boolean | undefined;
|
|
72
71
|
limit?: number | undefined;
|
|
73
|
-
timeout?: number | undefined;
|
|
74
72
|
}, {}>;
|
|
75
73
|
readonly examples: readonly ToolExample<typeof findSchema.infer>[];
|
|
76
74
|
readonly strict = true;
|
|
@@ -61,6 +61,6 @@ export declare function isImageProviderPreference(value: unknown): value is Imag
|
|
|
61
61
|
/** Set the preferred image provider from settings */
|
|
62
62
|
export declare function setPreferredImageProvider(provider: ImageProviderPreference): void;
|
|
63
63
|
export declare const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails>;
|
|
64
|
-
export declare function getImageGenTools(
|
|
65
|
-
export declare function getImageGenToolsWithRegistry(
|
|
64
|
+
export declare function getImageGenTools(_modelRegistry?: ModelRegistry, _activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
|
|
65
|
+
export declare function getImageGenToolsWithRegistry(_modelRegistry: ModelRegistry, _activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
|
|
66
66
|
export {};
|
|
@@ -8,7 +8,7 @@ import type { OutputMeta } from "./output-meta";
|
|
|
8
8
|
declare const searchSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
9
9
|
pattern: string;
|
|
10
10
|
paths?: string | string[] | undefined;
|
|
11
|
-
|
|
11
|
+
case?: boolean | undefined;
|
|
12
12
|
gitignore?: boolean | undefined;
|
|
13
13
|
skip?: number | null | undefined;
|
|
14
14
|
}, {}>;
|
|
@@ -67,7 +67,7 @@ export declare class SearchTool implements AgentTool<typeof searchSchema, Search
|
|
|
67
67
|
readonly parameters: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
68
68
|
pattern: string;
|
|
69
69
|
paths?: string | string[] | undefined;
|
|
70
|
-
|
|
70
|
+
case?: boolean | undefined;
|
|
71
71
|
gitignore?: boolean | undefined;
|
|
72
72
|
skip?: number | null | undefined;
|
|
73
73
|
}, {}>;
|
|
@@ -78,7 +78,7 @@ export declare class SearchTool implements AgentTool<typeof searchSchema, Search
|
|
|
78
78
|
interface SearchRenderArgs {
|
|
79
79
|
pattern: string;
|
|
80
80
|
paths?: string | string[];
|
|
81
|
-
|
|
81
|
+
case?: boolean;
|
|
82
82
|
gitignore?: boolean;
|
|
83
83
|
skip?: number;
|
|
84
84
|
}
|
|
@@ -8,7 +8,7 @@ export declare const SUPPORTED_INPUT_IMAGE_MIME_TYPES: Set<string>;
|
|
|
8
8
|
* with an opaque HTTP 400. Detect those models so the resize pipeline encodes
|
|
9
9
|
* to PNG/JPEG instead — the automatic equivalent of `OMP_NO_WEBP=1`.
|
|
10
10
|
*/
|
|
11
|
-
export declare function modelLacksWebpSupport(model: Pick<Model, "provider" | "api"> | undefined): boolean;
|
|
11
|
+
export declare function modelLacksWebpSupport(model: Pick<Model, "provider" | "api" | "imageInputDecoder"> | undefined): boolean;
|
|
12
12
|
/**
|
|
13
13
|
* `true` when `model` cannot decode WebP, otherwise `undefined` so the
|
|
14
14
|
* `OMP_NO_WEBP` env fallback in {@link resizeImage} still applies. Feed straight
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrow a value to a thenable so a rejection handler can be attached.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the local helper in `mcp/transports/stdio.ts` (kept separate because
|
|
5
|
+
* that copy serves the FileSink stdin-write path and is battle-tested there).
|
|
6
|
+
* This shared copy is the home for the IPC `send()` sites.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isThenable(value: unknown): value is PromiseLike<unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Send a message to a Bun subprocess over IPC, neutralizing both the
|
|
11
|
+
* synchronous throw ("cannot be used after the process has exited") and any
|
|
12
|
+
* asynchronous rejection (EPIPE from a pipe that broke between exit being
|
|
13
|
+
* observed and the next `send()`). The dead worker is detected separately via
|
|
14
|
+
* `onExit`/`onError` and respawned or disabled by the owning client; an
|
|
15
|
+
* un-awaited EPIPE rejection must not escape as a fatal unhandled rejection
|
|
16
|
+
* that takes down the whole session. See issue #2997.
|
|
17
|
+
*
|
|
18
|
+
* `label` prefixes the debug log on synchronous failure (e.g. "tts").
|
|
19
|
+
*/
|
|
20
|
+
export declare function safeSend(proc: {
|
|
21
|
+
send(message: unknown): unknown;
|
|
22
|
+
}, message: unknown, label: string): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AuthStorage, OAuthAccess } from "@oh-my-pi/pi-ai";
|
|
2
|
+
export declare const PERPLEXITY_CHAT_BASE_URL = "https://api.perplexity.ai";
|
|
3
|
+
export declare const PERPLEXITY_RESPONSES_BASE_URL = "https://api.perplexity.ai/v1";
|
|
4
|
+
export declare const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
5
|
+
export declare const OAUTH_EXPIRY_BUFFER_MS: number;
|
|
6
|
+
export interface ApiConfig {
|
|
7
|
+
type: "api_key";
|
|
8
|
+
apiKey: string;
|
|
9
|
+
provider: "perplexity" | "openrouter";
|
|
10
|
+
chatBaseUrl: string;
|
|
11
|
+
responsesBaseUrl: string;
|
|
12
|
+
modelPrefix: string;
|
|
13
|
+
useResponses: boolean;
|
|
14
|
+
}
|
|
15
|
+
export type PerplexityAuth = ApiConfig | {
|
|
16
|
+
type: "oauth";
|
|
17
|
+
access: OAuthAccess;
|
|
18
|
+
} | {
|
|
19
|
+
type: "cookies";
|
|
20
|
+
cookies: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "anonymous";
|
|
23
|
+
};
|
|
24
|
+
export interface PerplexityAuthOptions {
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
forceRefresh?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Detect API-key endpoints to try in priority order (Perplexity direct, then OpenRouter). */
|
|
29
|
+
export declare function getApiConfigs(authStorage: AuthStorage, sessionId: string | undefined, options?: PerplexityAuthOptions): Promise<ApiConfig[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Decode a Perplexity JWT's `exp` claim, in ms. Returns `undefined` when the
|
|
32
|
+
* token has no `exp` (which is the common case — Perplexity sessions are
|
|
33
|
+
* server-side and effectively non-expiring from the client's POV).
|
|
34
|
+
*/
|
|
35
|
+
export declare function jwtExpiryMs(token: string): number | undefined;
|
|
36
|
+
/** Collect all available auth methods to try in priority order */
|
|
37
|
+
export declare function getAvailableAuthMethods(authStorage: AuthStorage, sessionId: string | undefined, options?: PerplexityAuthOptions): Promise<PerplexityAuth[]>;
|
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.1.
|
|
4
|
+
"version": "16.1.3",
|
|
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",
|
|
@@ -48,17 +48,17 @@
|
|
|
48
48
|
"@agentclientprotocol/sdk": "0.25.0",
|
|
49
49
|
"@babel/parser": "^7.29.7",
|
|
50
50
|
"@mozilla/readability": "^0.6.0",
|
|
51
|
-
"@oh-my-pi/hashline": "16.1.
|
|
52
|
-
"@oh-my-pi/omp-stats": "16.1.
|
|
53
|
-
"@oh-my-pi/pi-agent-core": "16.1.
|
|
54
|
-
"@oh-my-pi/pi-ai": "16.1.
|
|
55
|
-
"@oh-my-pi/pi-catalog": "16.1.
|
|
56
|
-
"@oh-my-pi/pi-mnemopi": "16.1.
|
|
57
|
-
"@oh-my-pi/pi-natives": "16.1.
|
|
58
|
-
"@oh-my-pi/pi-tui": "16.1.
|
|
59
|
-
"@oh-my-pi/pi-utils": "16.1.
|
|
60
|
-
"@oh-my-pi/pi-wire": "16.1.
|
|
61
|
-
"@oh-my-pi/snapcompact": "16.1.
|
|
51
|
+
"@oh-my-pi/hashline": "16.1.3",
|
|
52
|
+
"@oh-my-pi/omp-stats": "16.1.3",
|
|
53
|
+
"@oh-my-pi/pi-agent-core": "16.1.3",
|
|
54
|
+
"@oh-my-pi/pi-ai": "16.1.3",
|
|
55
|
+
"@oh-my-pi/pi-catalog": "16.1.3",
|
|
56
|
+
"@oh-my-pi/pi-mnemopi": "16.1.3",
|
|
57
|
+
"@oh-my-pi/pi-natives": "16.1.3",
|
|
58
|
+
"@oh-my-pi/pi-tui": "16.1.3",
|
|
59
|
+
"@oh-my-pi/pi-utils": "16.1.3",
|
|
60
|
+
"@oh-my-pi/pi-wire": "16.1.3",
|
|
61
|
+
"@oh-my-pi/snapcompact": "16.1.3",
|
|
62
62
|
"@opentelemetry/api": "^1.9.1",
|
|
63
63
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
64
64
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { countTokens } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
|
3
|
+
import { estimateToolSchemaTokens } from "@oh-my-pi/pi-coding-agent/modes/utils/context-usage";
|
|
4
|
+
import { buildSystemPrompt } from "@oh-my-pi/pi-coding-agent/system-prompt";
|
|
5
|
+
import { createTools, type Tool, type ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
|
6
|
+
|
|
7
|
+
function bytes(s: string): number {
|
|
8
|
+
return Buffer.byteLength(s, "utf-8");
|
|
9
|
+
}
|
|
10
|
+
function est(s: string): number {
|
|
11
|
+
return (bytes(s) + 3) >> 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
await Settings.init({ inMemory: true, cwd: process.cwd() });
|
|
15
|
+
const settings = Settings.isolated({});
|
|
16
|
+
|
|
17
|
+
const session: ToolSession = {
|
|
18
|
+
cwd: process.cwd(),
|
|
19
|
+
hasUI: false,
|
|
20
|
+
getSessionFile: () => null,
|
|
21
|
+
getSessionSpawns: () => "*",
|
|
22
|
+
settings,
|
|
23
|
+
} as ToolSession;
|
|
24
|
+
|
|
25
|
+
const tools = await createTools(session);
|
|
26
|
+
const toolsMap = new Map<string, Tool>(tools.map(t => [t.name, t]));
|
|
27
|
+
|
|
28
|
+
console.log(`active tools (${tools.length}): ${tools.map(t => t.name).join(", ")}\n`);
|
|
29
|
+
|
|
30
|
+
const rows: Array<{ name: string; descBytes: number; tok: number; schemaTok: number }> = [];
|
|
31
|
+
for (const t of tools) {
|
|
32
|
+
const tok = estimateToolSchemaTokens([t as never]);
|
|
33
|
+
const descBytes = bytes(t.description ?? "");
|
|
34
|
+
const descTok = est(t.description ?? "");
|
|
35
|
+
rows.push({ name: t.name, descBytes, tok, schemaTok: tok - descTok });
|
|
36
|
+
}
|
|
37
|
+
rows.sort((a, b) => b.tok - a.tok);
|
|
38
|
+
|
|
39
|
+
const totalTok = estimateToolSchemaTokens(tools as never);
|
|
40
|
+
console.log("per-tool tokens (sorted): name | total tok | desc bytes | ~schema tok");
|
|
41
|
+
for (const r of rows) {
|
|
42
|
+
console.log(
|
|
43
|
+
` ${r.name.padEnd(20)} ${String(r.tok).padStart(6)} ${String(r.descBytes).padStart(7)} ${String(r.schemaTok).padStart(6)}`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
console.log(`\nTOOLS TOTAL tokens: ${totalTok}\n`);
|
|
47
|
+
|
|
48
|
+
const built = await buildSystemPrompt({
|
|
49
|
+
tools: toolsMap as never,
|
|
50
|
+
toolNames: tools.map(t => t.name),
|
|
51
|
+
inlineToolDescriptors: false,
|
|
52
|
+
nativeTools: true,
|
|
53
|
+
cwd: process.cwd(),
|
|
54
|
+
skills: [],
|
|
55
|
+
contextFiles: [],
|
|
56
|
+
workspaceTree: { rootPath: process.cwd(), rendered: "", truncated: false, totalLines: 0, agentsMdFiles: [] },
|
|
57
|
+
});
|
|
58
|
+
const parts = built.systemPrompt;
|
|
59
|
+
const part0 = parts[0] ?? "";
|
|
60
|
+
const rest = parts.slice(1).join("\n");
|
|
61
|
+
console.log(`system prompt parts: ${parts.length}`);
|
|
62
|
+
console.log(`SYSTEM PROMPT tokens (part0, no skills): ${countTokens(part0)} (bytes=${bytes(part0)})`);
|
|
63
|
+
console.log(`SYSTEM CONTEXT tokens (parts[1..]): ${countTokens(rest)} (bytes=${bytes(rest)})`);
|