@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
|
@@ -32,11 +32,11 @@ import {
|
|
|
32
32
|
AppendOnlyContextManager,
|
|
33
33
|
type AsideMessage,
|
|
34
34
|
type CompactionSummaryMessage,
|
|
35
|
+
countTokens,
|
|
35
36
|
resolveTelemetry,
|
|
36
37
|
STREAM_INTERRUPTED_AFTER_CONTENT_STOP_DETAIL,
|
|
37
38
|
ThinkingLevel,
|
|
38
39
|
} from "@oh-my-pi/pi-agent-core";
|
|
39
|
-
|
|
40
40
|
import {
|
|
41
41
|
AGGRESSIVE_SHAKE_CONFIG,
|
|
42
42
|
AUTO_HANDOFF_THRESHOLD_FOCUS,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
} from "@oh-my-pi/pi-ai";
|
|
105
105
|
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
106
106
|
import { modelsAreEqual } from "@oh-my-pi/pi-catalog/models";
|
|
107
|
-
import {
|
|
107
|
+
import { MacOSPowerAssertion } from "@oh-my-pi/pi-natives";
|
|
108
108
|
import {
|
|
109
109
|
extractRetryHint,
|
|
110
110
|
formatDuration,
|
|
@@ -150,7 +150,7 @@ import {
|
|
|
150
150
|
resolveModelRoleValue,
|
|
151
151
|
resolveRoleSelection,
|
|
152
152
|
} from "../config/model-resolver";
|
|
153
|
-
import { MODEL_ROLE_IDS } from "../config/model-roles";
|
|
153
|
+
import { MODEL_ROLE_IDS, MODEL_ROLES } from "../config/model-roles";
|
|
154
154
|
import { expandPromptTemplate, type PromptTemplate } from "../config/prompt-templates";
|
|
155
155
|
import type { Settings, SkillsSettings } from "../config/settings";
|
|
156
156
|
import { onAppendOnlyModeChanged } from "../config/settings";
|
|
@@ -1755,6 +1755,24 @@ export class AgentSession {
|
|
|
1755
1755
|
systemPrompt.push(this.#advisorWatchdogPrompt);
|
|
1756
1756
|
}
|
|
1757
1757
|
const advisorSessionId = this.sessionId ? `${this.sessionId}-advisor` : undefined;
|
|
1758
|
+
|
|
1759
|
+
// Thread the primary's telemetry into the advisor loop so the advisor
|
|
1760
|
+
// model's GenAI spans + usage/cost hooks fire like every other model call,
|
|
1761
|
+
// stamped with the advisor's own identity. `conversationId` is cleared so
|
|
1762
|
+
// the advisor loop falls back to its own `-advisor` session id for
|
|
1763
|
+
// `gen_ai.conversation.id` instead of inheriting the primary's
|
|
1764
|
+
// conversation; undefined telemetry stays undefined (zero-overhead no-op).
|
|
1765
|
+
const advisorTelemetry = this.agent.telemetry
|
|
1766
|
+
? {
|
|
1767
|
+
...this.agent.telemetry,
|
|
1768
|
+
agent: {
|
|
1769
|
+
id: advisorSessionId,
|
|
1770
|
+
name: MODEL_ROLES.advisor.name,
|
|
1771
|
+
description: formatModelString(advisorSel.model),
|
|
1772
|
+
},
|
|
1773
|
+
conversationId: undefined,
|
|
1774
|
+
}
|
|
1775
|
+
: undefined;
|
|
1758
1776
|
const advisorAgent = new Agent({
|
|
1759
1777
|
initialState: {
|
|
1760
1778
|
systemPrompt,
|
|
@@ -1766,6 +1784,7 @@ export class AgentSession {
|
|
|
1766
1784
|
sessionId: advisorSessionId,
|
|
1767
1785
|
getApiKey: requestModel => this.#modelRegistry.resolver(requestModel, advisorSessionId),
|
|
1768
1786
|
intentTracing: false,
|
|
1787
|
+
telemetry: advisorTelemetry,
|
|
1769
1788
|
});
|
|
1770
1789
|
advisorAgent.setDisableReasoning(shouldDisableReasoning(advisorThinkingLevel));
|
|
1771
1790
|
|
|
@@ -1941,24 +1960,26 @@ export class AgentSession {
|
|
|
1941
1960
|
|
|
1942
1961
|
let compactResult: CompactionResult | undefined;
|
|
1943
1962
|
let lastError: unknown;
|
|
1963
|
+
const advisorSessionId = this.sessionId ? `${this.sessionId}-advisor` : undefined;
|
|
1964
|
+
// Instrument the advisor's overflow-compaction one-shot like the primary
|
|
1965
|
+
// compaction path so the advisor model's maintenance call also emits spans.
|
|
1966
|
+
const telemetry = resolveTelemetry(advisor.telemetry, advisorSessionId);
|
|
1944
1967
|
|
|
1945
1968
|
for (const candidate of candidates) {
|
|
1946
|
-
const apiKey = await this.#modelRegistry.getApiKey(
|
|
1947
|
-
candidate,
|
|
1948
|
-
this.sessionId ? `${this.sessionId}-advisor` : undefined,
|
|
1949
|
-
);
|
|
1969
|
+
const apiKey = await this.#modelRegistry.getApiKey(candidate, advisorSessionId);
|
|
1950
1970
|
if (!apiKey) continue;
|
|
1951
1971
|
|
|
1952
1972
|
try {
|
|
1953
1973
|
compactResult = await compact(
|
|
1954
1974
|
preparation,
|
|
1955
1975
|
candidate,
|
|
1956
|
-
this.#modelRegistry.resolver(candidate,
|
|
1976
|
+
this.#modelRegistry.resolver(candidate, advisorSessionId),
|
|
1957
1977
|
undefined,
|
|
1958
1978
|
undefined,
|
|
1959
1979
|
{
|
|
1960
1980
|
thinkingLevel: advisorCompactionThinkingLevel,
|
|
1961
1981
|
convertToLlm: messages => this.#convertToLlmForSideRequest(messages),
|
|
1982
|
+
telemetry,
|
|
1962
1983
|
},
|
|
1963
1984
|
);
|
|
1964
1985
|
break;
|
|
@@ -4422,7 +4443,7 @@ export class AgentSession {
|
|
|
4422
4443
|
}
|
|
4423
4444
|
return new Proxy(tool, {
|
|
4424
4445
|
get: (target, prop) => {
|
|
4425
|
-
if (prop !== "execute") return
|
|
4446
|
+
if (prop !== "execute") return target[prop as keyof T];
|
|
4426
4447
|
return async (
|
|
4427
4448
|
toolCallId: string,
|
|
4428
4449
|
args: unknown,
|
|
@@ -4964,20 +4985,15 @@ export class AgentSession {
|
|
|
4964
4985
|
const antigravityEndpointMode =
|
|
4965
4986
|
provider === "google-antigravity" ? this.settings.get("providers.antigravityEndpoint") : undefined;
|
|
4966
4987
|
|
|
4967
|
-
if (
|
|
4968
|
-
!sessionOnPayload &&
|
|
4969
|
-
!sessionOnResponse &&
|
|
4970
|
-
!sessionMetadata &&
|
|
4971
|
-
!sessionOnSseEvent &&
|
|
4972
|
-
!openrouterVariant &&
|
|
4973
|
-
!antigravityEndpointMode
|
|
4974
|
-
)
|
|
4975
|
-
return options;
|
|
4976
|
-
|
|
4977
4988
|
const preparedOptions: SimpleStreamOptions = {
|
|
4978
4989
|
...options,
|
|
4979
4990
|
...(openrouterVariant !== undefined && { openrouterVariant }),
|
|
4980
4991
|
...(antigravityEndpointMode !== undefined && { antigravityEndpointMode }),
|
|
4992
|
+
loopGuard: {
|
|
4993
|
+
enabled: this.settings.get("model.loopGuard.enabled"),
|
|
4994
|
+
checkAssistantContent: this.settings.get("model.loopGuard.checkAssistantContent"),
|
|
4995
|
+
...options.loopGuard,
|
|
4996
|
+
},
|
|
4981
4997
|
};
|
|
4982
4998
|
|
|
4983
4999
|
// Stamp session metadata (e.g. user_id={session_id}) onto direct-call requests so
|
|
@@ -9225,7 +9241,9 @@ export class AgentSession {
|
|
|
9225
9241
|
let compactResult: CompactionResult | undefined;
|
|
9226
9242
|
let lastError: unknown;
|
|
9227
9243
|
|
|
9228
|
-
for (
|
|
9244
|
+
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
|
|
9245
|
+
const candidate = candidates[candidateIndex];
|
|
9246
|
+
const hasMoreCandidates = candidateIndex < candidates.length - 1;
|
|
9229
9247
|
const apiKey = await this.#modelRegistry.getApiKey(candidate, this.sessionId);
|
|
9230
9248
|
if (!apiKey) continue;
|
|
9231
9249
|
|
|
@@ -9264,6 +9282,20 @@ export class AgentSession {
|
|
|
9264
9282
|
lastError = this.#buildCompactionAuthError();
|
|
9265
9283
|
break;
|
|
9266
9284
|
}
|
|
9285
|
+
if (this.#isCompactionSummarizationTimeoutMessage(message)) {
|
|
9286
|
+
logger.warn(
|
|
9287
|
+
hasMoreCandidates
|
|
9288
|
+
? "Auto-compaction summarization timed out, trying next model"
|
|
9289
|
+
: "Auto-compaction summarization timed out, not retrying same model",
|
|
9290
|
+
{
|
|
9291
|
+
error: message,
|
|
9292
|
+
model: `${candidate.provider}/${candidate.id}`,
|
|
9293
|
+
},
|
|
9294
|
+
);
|
|
9295
|
+
lastError = error;
|
|
9296
|
+
break;
|
|
9297
|
+
}
|
|
9298
|
+
|
|
9267
9299
|
const retryAfterMs = this.#parseRetryAfterMsFromError(message);
|
|
9268
9300
|
const shouldRetry =
|
|
9269
9301
|
retrySettings.enabled &&
|
|
@@ -9281,19 +9313,15 @@ export class AgentSession {
|
|
|
9281
9313
|
|
|
9282
9314
|
// If retry delay is too long (>30s), try next candidate instead of waiting
|
|
9283
9315
|
const maxAcceptableDelayMs = 30_000;
|
|
9284
|
-
if (delayMs > maxAcceptableDelayMs) {
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
lastError = error;
|
|
9294
|
-
break; // Exit retry loop, continue to next candidate
|
|
9295
|
-
}
|
|
9296
|
-
// No more candidates - we have to wait
|
|
9316
|
+
if (delayMs > maxAcceptableDelayMs && hasMoreCandidates) {
|
|
9317
|
+
logger.warn("Auto-compaction retry delay too long, trying next model", {
|
|
9318
|
+
delayMs,
|
|
9319
|
+
retryAfterMs,
|
|
9320
|
+
error: message,
|
|
9321
|
+
model: `${candidate.provider}/${candidate.id}`,
|
|
9322
|
+
});
|
|
9323
|
+
lastError = error;
|
|
9324
|
+
break; // Exit retry loop, continue to next candidate
|
|
9297
9325
|
}
|
|
9298
9326
|
|
|
9299
9327
|
attempt++;
|
|
@@ -9654,6 +9682,7 @@ export class AgentSession {
|
|
|
9654
9682
|
if (isContextOverflow(message, contextWindow)) return false;
|
|
9655
9683
|
|
|
9656
9684
|
if (this.#isClassifierRefusal(message)) return true;
|
|
9685
|
+
if (this.#isProviderErrorFinishReasonBeforeToolUse(message)) return true;
|
|
9657
9686
|
if (this.#streamInterruptedAfterObservableOutput(message)) return false;
|
|
9658
9687
|
if (this.#isStaleOpenAIResponsesReplayError(message)) return true;
|
|
9659
9688
|
|
|
@@ -9698,6 +9727,12 @@ export class AgentSession {
|
|
|
9698
9727
|
return stopType === "refusal" || stopType === "sensitive";
|
|
9699
9728
|
}
|
|
9700
9729
|
|
|
9730
|
+
#isProviderErrorFinishReasonBeforeToolUse(message: AssistantMessage): boolean {
|
|
9731
|
+
if (!message.errorMessage) return false;
|
|
9732
|
+
if (message.content.some(block => block.type === "toolCall")) return false;
|
|
9733
|
+
return /\bProvider (?:returned error finish_reason|finish_reason:\s*error)\b/i.test(message.errorMessage);
|
|
9734
|
+
}
|
|
9735
|
+
|
|
9701
9736
|
#isTransientErrorMessage(errorMessage: string): boolean {
|
|
9702
9737
|
return (
|
|
9703
9738
|
this.#isTransientEnvelopeErrorMessage(errorMessage) || this.#isTransientTransportErrorMessage(errorMessage)
|
|
@@ -9709,6 +9744,10 @@ export class AgentSession {
|
|
|
9709
9744
|
return /anthropic stream envelope error:/i.test(errorMessage) && /before message_start/i.test(errorMessage);
|
|
9710
9745
|
}
|
|
9711
9746
|
|
|
9747
|
+
#isCompactionSummarizationTimeoutMessage(errorMessage: string): boolean {
|
|
9748
|
+
return /\b(?:operation\s+)?timed?\s*out\b|\btimeout\b|\bstream stall\b/i.test(errorMessage);
|
|
9749
|
+
}
|
|
9750
|
+
|
|
9712
9751
|
#isTransientTransportErrorMessage(errorMessage: string): boolean {
|
|
9713
9752
|
// Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504,
|
|
9714
9753
|
// service unavailable, provider-suggested retry, network/connection/socket errors, fetch failed,
|
|
@@ -11157,6 +11196,94 @@ export class AgentSession {
|
|
|
11157
11196
|
return { selectedText, cancelled: false };
|
|
11158
11197
|
}
|
|
11159
11198
|
|
|
11199
|
+
async branchFromBtw(
|
|
11200
|
+
question: string,
|
|
11201
|
+
assistantMessage: AssistantMessage,
|
|
11202
|
+
): Promise<{ cancelled: boolean; sessionFile: string | undefined }> {
|
|
11203
|
+
const previousSessionFile = this.sessionFile;
|
|
11204
|
+
if (!this.sessionManager.getSessionFile()) {
|
|
11205
|
+
throw new Error("Cannot branch /btw: session is not persisted");
|
|
11206
|
+
}
|
|
11207
|
+
|
|
11208
|
+
const leafId = this.sessionManager.getLeafId();
|
|
11209
|
+
if (!leafId) {
|
|
11210
|
+
throw new Error("Cannot branch /btw: current session has no leaf");
|
|
11211
|
+
}
|
|
11212
|
+
|
|
11213
|
+
if (
|
|
11214
|
+
this.isBashRunning ||
|
|
11215
|
+
this.isEvalRunning ||
|
|
11216
|
+
this.isCompacting ||
|
|
11217
|
+
this.isGeneratingHandoff ||
|
|
11218
|
+
this.isRetrying
|
|
11219
|
+
) {
|
|
11220
|
+
throw new Error("Cannot branch /btw while session maintenance or user work is still running");
|
|
11221
|
+
}
|
|
11222
|
+
|
|
11223
|
+
if (this.#extensionRunner?.hasHandlers("session_before_branch")) {
|
|
11224
|
+
const result = (await this.#extensionRunner.emit({
|
|
11225
|
+
type: "session_before_branch",
|
|
11226
|
+
entryId: leafId,
|
|
11227
|
+
})) as SessionBeforeBranchResult | undefined;
|
|
11228
|
+
|
|
11229
|
+
if (result?.cancel) {
|
|
11230
|
+
return { cancelled: true, sessionFile: previousSessionFile };
|
|
11231
|
+
}
|
|
11232
|
+
}
|
|
11233
|
+
|
|
11234
|
+
await this.#cancelPostPromptTasks();
|
|
11235
|
+
if (
|
|
11236
|
+
this.isBashRunning ||
|
|
11237
|
+
this.isEvalRunning ||
|
|
11238
|
+
this.isCompacting ||
|
|
11239
|
+
this.isGeneratingHandoff ||
|
|
11240
|
+
this.isRetrying
|
|
11241
|
+
) {
|
|
11242
|
+
throw new Error("Cannot branch /btw while session maintenance or user work is still running");
|
|
11243
|
+
}
|
|
11244
|
+
|
|
11245
|
+
this.#pendingNextTurnMessages = [];
|
|
11246
|
+
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
11247
|
+
this.agent.replaceQueues([], []);
|
|
11248
|
+
if (this.isStreaming) {
|
|
11249
|
+
await this.abort({ goalReason: "internal", reason: "branching /btw" });
|
|
11250
|
+
this.agent.replaceQueues([], []);
|
|
11251
|
+
}
|
|
11252
|
+
await this.sessionManager.flush();
|
|
11253
|
+
this.#cancelOwnAsyncJobs();
|
|
11254
|
+
|
|
11255
|
+
this.sessionManager.createBranchedSession(leafId);
|
|
11256
|
+
this.sessionManager.appendMessage({
|
|
11257
|
+
role: "user",
|
|
11258
|
+
content: [{ type: "text", text: question }],
|
|
11259
|
+
timestamp: Date.now(),
|
|
11260
|
+
});
|
|
11261
|
+
this.sessionManager.appendMessage(assistantMessage);
|
|
11262
|
+
this.#syncTodoPhasesFromBranch();
|
|
11263
|
+
this.#freshProviderSessionId = undefined;
|
|
11264
|
+
this.#syncAgentSessionId();
|
|
11265
|
+
this.#rekeyHindsightMemoryForCurrentSessionId();
|
|
11266
|
+
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
11267
|
+
this.#resetHindsightConversationTrackingIfHindsight();
|
|
11268
|
+
this.#resetMnemopiConversationTrackingIfMnemopi();
|
|
11269
|
+
|
|
11270
|
+
const sessionContext = this.buildDisplaySessionContext();
|
|
11271
|
+
await this.#restoreMCPSelectionsForSessionContext(sessionContext);
|
|
11272
|
+
|
|
11273
|
+
if (this.#extensionRunner) {
|
|
11274
|
+
await this.#extensionRunner.emit({
|
|
11275
|
+
type: "session_branch",
|
|
11276
|
+
previousSessionFile,
|
|
11277
|
+
});
|
|
11278
|
+
}
|
|
11279
|
+
|
|
11280
|
+
this.agent.replaceMessages(sessionContext.messages);
|
|
11281
|
+
this.#advisorRuntime?.reset();
|
|
11282
|
+
this.#closeCodexProviderSessionsForHistoryRewrite();
|
|
11283
|
+
|
|
11284
|
+
return { cancelled: false, sessionFile: this.sessionFile };
|
|
11285
|
+
}
|
|
11286
|
+
|
|
11160
11287
|
// =========================================================================
|
|
11161
11288
|
// Tree Navigation
|
|
11162
11289
|
// =========================================================================
|
|
@@ -45,6 +45,7 @@ const PRIMARY_ARG_KEYS = [
|
|
|
45
45
|
"query",
|
|
46
46
|
"prompt",
|
|
47
47
|
"assignment",
|
|
48
|
+
"note",
|
|
48
49
|
"message",
|
|
49
50
|
"op",
|
|
50
51
|
"name",
|
|
@@ -74,8 +75,16 @@ function lineCount(text: string): number {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
/** Pick the most informative scalar argument of a tool call. */
|
|
77
|
-
function primaryArg(args: Record<string, unknown> | undefined): string {
|
|
78
|
+
function primaryArg(name: string, args: Record<string, unknown> | undefined): string {
|
|
78
79
|
if (!args || typeof args !== "object") return "";
|
|
80
|
+
// Advisor note is the most informative summary; preserve severity too.
|
|
81
|
+
if (name === "advise") {
|
|
82
|
+
const note = typeof args.note === "string" ? args.note : "";
|
|
83
|
+
const severity = typeof args.severity === "string" ? args.severity : "";
|
|
84
|
+
if (note && severity) return oneLine(`${severity}: ${note}`);
|
|
85
|
+
if (note) return oneLine(note);
|
|
86
|
+
if (severity) return oneLine(severity);
|
|
87
|
+
}
|
|
79
88
|
for (const key of PRIMARY_ARG_KEYS) {
|
|
80
89
|
const value = args[key];
|
|
81
90
|
if (typeof value === "string" && value.length > 0) return oneLine(value);
|
|
@@ -108,7 +117,7 @@ function toolCallLine(
|
|
|
108
117
|
result: ToolResultMessage | undefined,
|
|
109
118
|
includeToolIntent?: boolean,
|
|
110
119
|
): string {
|
|
111
|
-
const head = `→ ${name}(${primaryArg(args)})`;
|
|
120
|
+
const head = `→ ${name}(${primaryArg(name, args)})`;
|
|
112
121
|
let base: string;
|
|
113
122
|
if (!result) {
|
|
114
123
|
base = `${head} ⇒ pending`;
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* estimate (`estimateInlineSavings`) so the two can never disagree.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { countTokens } from "@oh-my-pi/pi-agent-core";
|
|
17
18
|
import type { Context, ImageContent, Model, TextContent, ToolResultMessage, UserMessage } from "@oh-my-pi/pi-ai";
|
|
18
|
-
import { countTokens } from "@oh-my-pi/pi-natives";
|
|
19
19
|
import * as snapcompact from "@oh-my-pi/snapcompact";
|
|
20
20
|
import contextFramesNote from "../prompts/system/snapcompact-context-frames-note.md" with { type: "text" };
|
|
21
21
|
import contextStub from "../prompts/system/snapcompact-context-stub.md" with { type: "text" };
|
|
@@ -240,13 +240,8 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
240
240
|
allowArgs: true,
|
|
241
241
|
handleTui: async (command, runtime) => {
|
|
242
242
|
const hadArgs = !!command.args;
|
|
243
|
-
// Capture state BEFORE the call: when plan mode is already active,
|
|
244
|
-
// handlePlanModeCommand may exit it (on confirmed exit) or leave it on (on cancel
|
|
245
|
-
// or warning). In every "already active" case the typed args are NOT consumed,
|
|
246
|
-
// so preserve them in history regardless of the user's confirm/cancel choice.
|
|
247
|
-
const wasPlanModeEnabled = runtime.ctx.planModeEnabled;
|
|
248
243
|
await runtime.ctx.handlePlanModeCommand(command.args || undefined);
|
|
249
|
-
if (hadArgs
|
|
244
|
+
if (hadArgs) {
|
|
250
245
|
runtime.ctx.editor.addToHistory(command.text);
|
|
251
246
|
}
|
|
252
247
|
runtime.ctx.editor.setText("");
|
|
@@ -275,10 +270,8 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
275
270
|
allowArgs: true,
|
|
276
271
|
handleTui: async (command, runtime) => {
|
|
277
272
|
const hadArgs = !!command.args;
|
|
278
|
-
// Capture state BEFORE the call (see /plan above for rationale).
|
|
279
|
-
const wasGoalModeEnabled = runtime.ctx.goalModeEnabled;
|
|
280
273
|
await runtime.ctx.handleGoalModeCommand(command.args || undefined);
|
|
281
|
-
if (hadArgs
|
|
274
|
+
if (hadArgs) {
|
|
282
275
|
runtime.ctx.editor.addToHistory(command.text);
|
|
283
276
|
}
|
|
284
277
|
runtime.ctx.editor.setText("");
|
|
@@ -308,7 +301,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
308
301
|
{
|
|
309
302
|
name: "model",
|
|
310
303
|
aliases: ["models"],
|
|
311
|
-
description: "
|
|
304
|
+
description: "Switch model for this session",
|
|
312
305
|
acpDescription: "Show current model selection",
|
|
313
306
|
handle: async (command, runtime) => {
|
|
314
307
|
if (command.args) {
|
|
@@ -341,7 +334,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
341
334
|
return commandConsumed();
|
|
342
335
|
},
|
|
343
336
|
handleTui: (_command, runtime) => {
|
|
344
|
-
runtime.ctx.showModelSelector();
|
|
337
|
+
runtime.ctx.showModelSelector({ temporaryOnly: true });
|
|
345
338
|
runtime.ctx.editor.setText("");
|
|
346
339
|
},
|
|
347
340
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Inputs used to decide whether the optional startup splash may run for this process. */
|
|
2
|
+
export interface StartupSplashDecisionOptions {
|
|
3
|
+
readonly configured: boolean;
|
|
4
|
+
readonly isInteractive: boolean;
|
|
5
|
+
readonly resuming: boolean;
|
|
6
|
+
readonly quiet: boolean;
|
|
7
|
+
readonly timing: boolean;
|
|
8
|
+
readonly stdinIsTTY: boolean | undefined;
|
|
9
|
+
readonly stdoutIsTTY: boolean | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Returns true only for explicitly enabled, normal interactive TTY startup. */
|
|
13
|
+
export function shouldShowStartupSplash(options: StartupSplashDecisionOptions): boolean {
|
|
14
|
+
if (!options.configured) return false;
|
|
15
|
+
if (!options.isInteractive) return false;
|
|
16
|
+
if (options.resuming || options.quiet) return false;
|
|
17
|
+
if (options.timing) return false;
|
|
18
|
+
return options.stdinIsTTY === true && options.stdoutIsTTY === true;
|
|
19
|
+
}
|
package/src/task/executor.ts
CHANGED
|
@@ -516,6 +516,7 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
|
|
|
516
516
|
const { yieldItems, reportFindings, doneAborted, signalAborted, outputSchema } = args;
|
|
517
517
|
let abortedViaYield = false;
|
|
518
518
|
const hasYield = Array.isArray(yieldItems) && yieldItems.length > 0;
|
|
519
|
+
const hadFailureBeforeYield = exitCode !== 0 && stderr.trim().length > 0;
|
|
519
520
|
|
|
520
521
|
if (hasYield) {
|
|
521
522
|
const lastYield = yieldItems[yieldItems.length - 1];
|
|
@@ -553,12 +554,16 @@ export function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): Fi
|
|
|
553
554
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
554
555
|
rawOutput = `{"error":"Failed to serialize yield data: ${errorMessage}"}`;
|
|
555
556
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
557
|
+
if (!hadFailureBeforeYield) {
|
|
558
|
+
exitCode = 0;
|
|
559
|
+
stderr = overridden
|
|
560
|
+
? SUBAGENT_WARNING_SCHEMA_OVERRIDDEN
|
|
561
|
+
: schemaError
|
|
562
|
+
? `invalid output schema: ${schemaError}`
|
|
563
|
+
: "";
|
|
564
|
+
} else if (!stderr) {
|
|
565
|
+
stderr = "Subagent failed after yielding a result.";
|
|
566
|
+
}
|
|
562
567
|
}
|
|
563
568
|
}
|
|
564
569
|
}
|
package/src/task/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import {
|
|
4
|
+
import { type } from "arktype";
|
|
5
5
|
import type { AgentSessionEvent } from "../session/agent-session";
|
|
6
6
|
import type { NestedRepoPatch } from "./worktree";
|
|
7
7
|
|
|
@@ -78,37 +78,23 @@ export interface SubagentLifecyclePayload {
|
|
|
78
78
|
export const ROLE_LABEL_MAX = 80;
|
|
79
79
|
/** Schema bound on the raw `role` input, before it is label-normalized at every use site. */
|
|
80
80
|
export const ROLE_INPUT_MAX = 256;
|
|
81
|
+
const ROLE_INPUT_SCHEMA = `string <= ${ROLE_INPUT_MAX}` as const;
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
),
|
|
98
|
-
assignment: z.string().describe("the work; self-contained instructions"),
|
|
99
|
-
};
|
|
100
|
-
const isolatedShape = {
|
|
101
|
-
isolated: z.boolean().optional().describe("run in isolated env; returns patches"),
|
|
102
|
-
};
|
|
103
|
-
const agentShape = {
|
|
104
|
-
agent: z.string().describe("agent type to spawn"),
|
|
105
|
-
};
|
|
106
|
-
const contextShape = {
|
|
107
|
-
context: z.string().describe("shared background prepended to each assignment"),
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export const taskItemSchema = z.object(taskItemShape);
|
|
111
|
-
const taskItemSchemaIsolated = z.object({ ...taskItemShape, ...isolatedShape });
|
|
83
|
+
export const taskItemSchema = type({
|
|
84
|
+
"id?": "string",
|
|
85
|
+
"description?": "string",
|
|
86
|
+
"role?": ROLE_INPUT_SCHEMA,
|
|
87
|
+
assignment: "string",
|
|
88
|
+
"+": "delete",
|
|
89
|
+
});
|
|
90
|
+
const taskItemSchemaIsolated = type({
|
|
91
|
+
"id?": "string",
|
|
92
|
+
"description?": "string",
|
|
93
|
+
"role?": ROLE_INPUT_SCHEMA,
|
|
94
|
+
assignment: "string",
|
|
95
|
+
"isolated?": "boolean",
|
|
96
|
+
"+": "delete",
|
|
97
|
+
});
|
|
112
98
|
|
|
113
99
|
/** Single task item. Fields are optional defensively: args stream in token by token. */
|
|
114
100
|
export interface TaskItem {
|
|
@@ -124,17 +110,34 @@ export interface TaskItem {
|
|
|
124
110
|
isolated?: boolean;
|
|
125
111
|
}
|
|
126
112
|
|
|
127
|
-
export const taskSchema =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
113
|
+
export const taskSchema = type({
|
|
114
|
+
agent: "string",
|
|
115
|
+
"id?": "string",
|
|
116
|
+
"description?": "string",
|
|
117
|
+
"role?": ROLE_INPUT_SCHEMA,
|
|
118
|
+
assignment: "string",
|
|
119
|
+
"isolated?": "boolean",
|
|
120
|
+
"+": "delete",
|
|
121
|
+
});
|
|
122
|
+
const taskSchemaNoIsolation = type({
|
|
123
|
+
agent: "string",
|
|
124
|
+
"id?": "string",
|
|
125
|
+
"description?": "string",
|
|
126
|
+
"role?": ROLE_INPUT_SCHEMA,
|
|
127
|
+
assignment: "string",
|
|
128
|
+
"+": "delete",
|
|
129
|
+
});
|
|
130
|
+
const taskSchemaBatch = type({
|
|
131
|
+
agent: "string",
|
|
132
|
+
context: "string",
|
|
133
|
+
tasks: taskItemSchemaIsolated.array(),
|
|
134
|
+
"+": "delete",
|
|
133
135
|
});
|
|
134
|
-
const taskSchemaBatchNoIsolation =
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
tasks:
|
|
136
|
+
const taskSchemaBatchNoIsolation = type({
|
|
137
|
+
agent: "string",
|
|
138
|
+
context: "string",
|
|
139
|
+
tasks: taskItemSchema.array(),
|
|
140
|
+
"+": "delete",
|
|
138
141
|
});
|
|
139
142
|
const ALL_TASK_SCHEMAS = [taskSchema, taskSchemaNoIsolation, taskSchemaBatch, taskSchemaBatchNoIsolation] as const;
|
|
140
143
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import type { Tool as AiTool } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { toolWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
|
|
3
4
|
|
|
4
5
|
// ─── Generic Tool Discovery Types ────────────────────────────────────────────
|
|
5
6
|
|
|
@@ -65,8 +66,13 @@ export function isMCPToolName(name: string): boolean {
|
|
|
65
66
|
return name.startsWith("mcp__");
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
function getSchemaPropertyKeys(
|
|
69
|
-
|
|
69
|
+
function getSchemaPropertyKeys(tool: Pick<AiTool, "name" | "description" | "parameters">): string[] {
|
|
70
|
+
let parameters: unknown = tool.parameters;
|
|
71
|
+
try {
|
|
72
|
+
parameters = toolWireSchema(tool as AiTool);
|
|
73
|
+
} catch {
|
|
74
|
+
// Schema may contain functions or cycles; fall back to the raw shape.
|
|
75
|
+
}
|
|
70
76
|
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return [];
|
|
71
77
|
const properties = (parameters as { properties?: unknown }).properties;
|
|
72
78
|
if (!properties || typeof properties !== "object" || Array.isArray(properties)) return [];
|
|
@@ -149,7 +155,14 @@ export function getDiscoverableTool(
|
|
|
149
155
|
source,
|
|
150
156
|
serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
|
|
151
157
|
mcpToolName: typeof toolRecord.mcpToolName === "string" ? toolRecord.mcpToolName : undefined,
|
|
152
|
-
schemaKeys:
|
|
158
|
+
schemaKeys:
|
|
159
|
+
toolRecord.parameters === undefined
|
|
160
|
+
? []
|
|
161
|
+
: getSchemaPropertyKeys({
|
|
162
|
+
name: tool.name,
|
|
163
|
+
description: rawDescription,
|
|
164
|
+
parameters: toolRecord.parameters as AiTool["parameters"],
|
|
165
|
+
}),
|
|
153
166
|
};
|
|
154
167
|
}
|
|
155
168
|
|
package/src/tools/ask.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
19
19
|
import type { ToolExample } from "@oh-my-pi/pi-ai";
|
|
20
20
|
import { type Component, Markdown, type MarkdownTheme, renderInlineMarkdown, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
21
21
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
22
|
-
import {
|
|
22
|
+
import { type as arkType } from "arktype";
|
|
23
23
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
24
24
|
import type { ExtensionUISelectItem } from "../extensibility/extensions";
|
|
25
25
|
import { getMarkdownTheme, type Theme, theme } from "../modes/theme/theme";
|
|
@@ -34,24 +34,24 @@ import { ToolAbortError } from "./tool-errors";
|
|
|
34
34
|
// Types
|
|
35
35
|
// =============================================================================
|
|
36
36
|
|
|
37
|
-
const OptionItem =
|
|
38
|
-
label:
|
|
39
|
-
description:
|
|
37
|
+
const OptionItem = arkType({
|
|
38
|
+
label: arkType("string").describe("display label"),
|
|
39
|
+
"description?": arkType("string").describe("optional explanatory text displayed below the label"),
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
const QuestionItem =
|
|
43
|
-
id:
|
|
44
|
-
question:
|
|
45
|
-
options:
|
|
46
|
-
multi:
|
|
47
|
-
recommended:
|
|
42
|
+
const QuestionItem = arkType({
|
|
43
|
+
id: arkType("string").describe("question id"),
|
|
44
|
+
question: arkType("string").describe("question text"),
|
|
45
|
+
options: OptionItem.array().describe("available options"),
|
|
46
|
+
"multi?": arkType("boolean").describe("allow multiple selections"),
|
|
47
|
+
"recommended?": arkType("number").describe("recommended option index"),
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
const askSchema =
|
|
51
|
-
questions:
|
|
50
|
+
const askSchema = arkType({
|
|
51
|
+
questions: QuestionItem.array().atLeastLength(1).describe("questions to ask"),
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
export type AskToolInput =
|
|
54
|
+
export type AskToolInput = typeof askSchema.infer;
|
|
55
55
|
|
|
56
56
|
/** Result for a single question */
|
|
57
57
|
export interface QuestionResult {
|
|
@@ -424,7 +424,7 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
|
|
|
424
424
|
readonly parameters = askSchema;
|
|
425
425
|
readonly strict = true;
|
|
426
426
|
|
|
427
|
-
readonly examples: readonly ToolExample<
|
|
427
|
+
readonly examples: readonly ToolExample<typeof askSchema.infer>[] = [
|
|
428
428
|
{
|
|
429
429
|
caption: "Single question",
|
|
430
430
|
call: {
|