@estebanforge/pi-antigravity-bridge 1.6.0 → 1.6.2
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 +12 -0
- package/package.json +5 -5
- package/src/ask-tool.ts +52 -5
- package/src/models.ts +42 -1
- package/src/provider.ts +20 -52
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.6.2] - 2026-09-19
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Compatibility with host 0.86.0's normalized provider stream input.** Stream entry points now receive a branded `TranscriptContext` (`{ messages }` only): the `context.systemPrompt` / `context.tools` fields are gone, and only `normalizeContext()` produces the new type. G10 fresh-conversation delivery read `context.systemPrompt`, so every fresh agy conversation silently lost the system prompt block (operating instructions, AGENTS.md project context, tool-priority note); the prompt now comes from the transcript via `getCurrentSystemPrompt(context.messages)`. `emitToolUse` arguments are restricted to `Record<string, JsonValue>` per the tightened `ToolCall.arguments` contract (driver args arrive JSON-decoded off the wire, so the two call-site casts are sound). Test fixtures in `provider-{sysprompt,streaming,late-result,escalation}.test.ts` and the `scripts/test-provider.ts` smoke context wrap raw objects with `normalizeContext()`. Dev pins `@earendil-works/*` raised `^0.85.0` to `^0.86.0`; `tsc` clean, 360 tests green.
|
|
10
|
+
|
|
11
|
+
## [1.6.1] - 2026-09-18
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`thinking` / `effort` params on AskAntigravity (synonyms).** Delegation calls had no direct tier knob: the only lever was tier sugar inside `model` ("flash high"), so a caller told "peer review on high thinking" fell through to the configured default (medium) with no signal anything was dropped. The tool now takes `thinking` (pi vocabulary: minimal|low|medium|high|xhigh|max, clamped to agy's low|medium|high; unknown values fall back to low) plus `effort` as the same knob under agy's own name, so calling models reach for either word. An explicit level beats a tier embedded in `model` and the config default; passing both with different values errors; fixed-thinking families (Claude, GPT-OSS) ignore it because agy rejects `--effort` for them. `toAgyEffort` moved from `src/provider.ts` to `src/models.ts` so provider turns and the delegation tool share one clamp.
|
|
16
|
+
|
|
5
17
|
## [1.6.0] - 2026-09-14
|
|
6
18
|
|
|
7
19
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estebanforge/pi-antigravity-bridge",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "Gemini provider for Pi on the Antigravity ACP server (official Google ACP) or the stream-json agy CLI. antigravity/* models in Pi's /model picker, no-patch MCP bridge: agy runs Pi's tools. ToS safe to use.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@earendil-works/pi-ai": "^0.
|
|
63
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
64
|
-
"@earendil-works/pi-server": "^0.
|
|
65
|
-
"@earendil-works/pi-tui": "^0.
|
|
62
|
+
"@earendil-works/pi-ai": "^0.86.0",
|
|
63
|
+
"@earendil-works/pi-coding-agent": "^0.86.0",
|
|
64
|
+
"@earendil-works/pi-server": "^0.86.0",
|
|
65
|
+
"@earendil-works/pi-tui": "^0.86.0",
|
|
66
66
|
"@types/node": "^22.0.0",
|
|
67
67
|
"tsx": "^4.19.0",
|
|
68
68
|
"typebox": "^1.1.38",
|
package/src/ask-tool.ts
CHANGED
|
@@ -17,7 +17,7 @@ import * as path from "node:path";
|
|
|
17
17
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
18
18
|
import { buildSessionContext, getAgentDir, keyHint } from "@earendil-works/pi-coding-agent";
|
|
19
19
|
import { Text } from "@earendil-works/pi-tui";
|
|
20
|
-
import { contentText } from "@earendil-works/pi-ai";
|
|
20
|
+
import { contentText, type ThinkingLevel } from "@earendil-works/pi-ai";
|
|
21
21
|
import { Type } from "typebox";
|
|
22
22
|
import {
|
|
23
23
|
CONVERSATIONS_DIR,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from "./discovery.js";
|
|
27
27
|
import { loadConfig, type AgyMode, type ThinkingTier } from "./config.js";
|
|
28
28
|
import { acquireBridgeSuppression } from "./mcp-registration.js";
|
|
29
|
-
import { spawnAgyModelsRaw } from "./models.js";
|
|
29
|
+
import { AGY_EFFORT_ORDER, spawnAgyModelsRaw, toAgyEffort } from "./models.js";
|
|
30
30
|
|
|
31
31
|
// --- Constants -------------------------------------------------------------
|
|
32
32
|
|
|
@@ -80,7 +80,12 @@ EXECUTION MODES (param: mode):
|
|
|
80
80
|
- **plan**: agy reviews and plans without writing. Use for cross-review and read-only tasks.
|
|
81
81
|
- **accept-edits** (default): agy applies edits directly inside the workspace.
|
|
82
82
|
|
|
83
|
-
COMPACT OUTPUT (param: digest): when true, the prompt is prefixed to request compact digests instead of full file contents. Defaults on for plan, off for accept-edits
|
|
83
|
+
COMPACT OUTPUT (param: digest): when true, the prompt is prefixed to request compact digests instead of full file contents. Defaults on for plan, off for accept-edits.
|
|
84
|
+
|
|
85
|
+
THINKING LEVEL (params: thinking, effort - SYNONYMS for one knob):
|
|
86
|
+
- pi calls it thinking, agy calls it effort. Same thing. Pass ONE of the two.
|
|
87
|
+
- Values (pi vocabulary): minimal|low|medium|high|xhigh|max. Clamped to agy's low|medium|high; unknown values fall back to low. "peer review on high thinking" -> thinking: "high".
|
|
88
|
+
- An explicit level beats a tier embedded in model ("flash high") and the configured default. Omit both for the configured default.`;
|
|
84
89
|
|
|
85
90
|
// --- Types -----------------------------------------------------------------
|
|
86
91
|
|
|
@@ -176,6 +181,10 @@ export function resolveModel(
|
|
|
176
181
|
input: string,
|
|
177
182
|
entries: ModelEntry[],
|
|
178
183
|
defaultThinking: ThinkingTier,
|
|
184
|
+
/** Explicit thinking param (thinking/effort). Beats a tier embedded in
|
|
185
|
+
* the alias ("flash high") and the configured default; clamped to the
|
|
186
|
+
* family's real tiers, ignored for fixed-thinking families. */
|
|
187
|
+
preferredTier?: ThinkingTier,
|
|
179
188
|
): ResolvedModel | null {
|
|
180
189
|
const lower = input.toLowerCase().trim();
|
|
181
190
|
|
|
@@ -232,6 +241,7 @@ export function resolveModel(
|
|
|
232
241
|
if (familyTiers.size === 0) return toResolved(candidates[0].full, null);
|
|
233
242
|
|
|
234
243
|
const preferred =
|
|
244
|
+
preferredTier ??
|
|
235
245
|
tier ??
|
|
236
246
|
(familyTiers.has(defaultThinking) ? defaultThinking : FAMILY_DEFAULT_TIER[family]);
|
|
237
247
|
const chosenTier = nearestTier([...familyTiers], preferred);
|
|
@@ -293,6 +303,18 @@ export async function registerAskAntigravityTool(
|
|
|
293
303
|
"Model alias or exact id. Friendly: 'flash', 'pro', 'gemini'. Add a tier: 'flash high'. Pin a version: '3.5 flash'. Exact: 'gemini-3.6-flash-medium'. Omit for the configured default.",
|
|
294
304
|
}),
|
|
295
305
|
),
|
|
306
|
+
thinking: Type.Optional(
|
|
307
|
+
Type.String({
|
|
308
|
+
description:
|
|
309
|
+
"Thinking level (= agy effort tier). pi vocabulary: minimal|low|medium|high|xhigh|max, clamped to agy's low|medium|high (unknown values fall back to low). Overrides a tier embedded in `model`. Omit for the configured default.",
|
|
310
|
+
}),
|
|
311
|
+
),
|
|
312
|
+
effort: Type.Optional(
|
|
313
|
+
Type.String({
|
|
314
|
+
description:
|
|
315
|
+
"Alias for `thinking` (agy's own name for the same knob). Pass ONE of the two; different values on both is an error.",
|
|
316
|
+
}),
|
|
317
|
+
),
|
|
296
318
|
mode: Type.Optional(
|
|
297
319
|
Type.Union([Type.Literal("plan"), Type.Literal("accept-edits")], {
|
|
298
320
|
description:
|
|
@@ -327,8 +349,14 @@ export async function registerAskAntigravityTool(
|
|
|
327
349
|
// row identifies what will actually run, not just explicit args.
|
|
328
350
|
const cfg = loadConfig();
|
|
329
351
|
const requestedModel = (args.model as string | undefined)?.trim() || cfg.defaultModel;
|
|
352
|
+
const thinkingArg = (args.thinking as string | undefined) ?? (args.effort as string | undefined);
|
|
330
353
|
const resolved =
|
|
331
|
-
resolveModel(
|
|
354
|
+
resolveModel(
|
|
355
|
+
requestedModel,
|
|
356
|
+
entries,
|
|
357
|
+
cfg.defaultThinking,
|
|
358
|
+
thinkingArg ? toAgyEffort(thinkingArg as ThinkingLevel, AGY_EFFORT_ORDER) : undefined,
|
|
359
|
+
) ?? { model: requestedModel };
|
|
332
360
|
const thinking: ThinkingTier = resolved.effort ?? cfg.defaultThinking;
|
|
333
361
|
const mode: AgyMode = (args.mode as AgyMode | undefined) ?? "accept-edits";
|
|
334
362
|
const useDigest = typeof args.digest === "boolean" ? args.digest : mode === "plan";
|
|
@@ -415,8 +443,27 @@ export async function registerAskAntigravityTool(
|
|
|
415
443
|
details: emptyDetails(requestedModel),
|
|
416
444
|
};
|
|
417
445
|
}
|
|
446
|
+
if (
|
|
447
|
+
typeof params.thinking === "string" &&
|
|
448
|
+
typeof params.effort === "string" &&
|
|
449
|
+
params.thinking !== params.effort
|
|
450
|
+
) {
|
|
451
|
+
return {
|
|
452
|
+
content: [
|
|
453
|
+
{
|
|
454
|
+
type: "text",
|
|
455
|
+
text: "thinking and effort are synonyms for the same knob - pass one, not both with different values.",
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
details: emptyDetails(requestedModel),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
const thinkingArg = (params.thinking as string | undefined) ?? (params.effort as string | undefined);
|
|
462
|
+
const preferredTier = thinkingArg
|
|
463
|
+
? toAgyEffort(thinkingArg as ThinkingLevel, AGY_EFFORT_ORDER)
|
|
464
|
+
: undefined;
|
|
418
465
|
const resolved =
|
|
419
|
-
resolveModel(requestedModel, entries, config.defaultThinking) ?? {
|
|
466
|
+
resolveModel(requestedModel, entries, config.defaultThinking, preferredTier) ?? {
|
|
420
467
|
model: requestedModel,
|
|
421
468
|
};
|
|
422
469
|
|
package/src/models.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { spawn } from "node:child_process";
|
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import os from "node:os";
|
|
23
23
|
import path from "node:path";
|
|
24
|
-
import type { Api, Model, ThinkingLevelMap } from "@earendil-works/pi-ai";
|
|
24
|
+
import type { Api, Model, ThinkingLevel, ThinkingLevelMap } from "@earendil-works/pi-ai";
|
|
25
25
|
|
|
26
26
|
const DISCOVERY_TIMEOUT_MS = 8_000;
|
|
27
27
|
|
|
@@ -31,6 +31,47 @@ export type AgyEffort = "low" | "medium" | "high";
|
|
|
31
31
|
/** low < medium < high, for sorting/clamping. */
|
|
32
32
|
const EFFORT_RANK: Record<AgyEffort, number> = { low: 0, medium: 1, high: 2 };
|
|
33
33
|
|
|
34
|
+
/** pi thinking-effort order mirrors agy's, for clamping. */
|
|
35
|
+
export const AGY_EFFORT_ORDER: readonly AgyEffort[] = ["low", "medium", "high"];
|
|
36
|
+
|
|
37
|
+
/** Map pi's thinking level onto one of the tiers `efforts` the base actually
|
|
38
|
+
* supports, clamping to the nearest available. agy rejects an effort tier a
|
|
39
|
+
* base doesn't list (e.g. medium on Pro), so we never emit one. Shared by the
|
|
40
|
+
* provider turns AND the AskAntigravity delegation tool (thinking/effort
|
|
41
|
+
* params): one vocabulary, one clamp. When pi sends no level we fall to the
|
|
42
|
+
* first available tier. */
|
|
43
|
+
export function toAgyEffort(
|
|
44
|
+
reasoning: ThinkingLevel | undefined,
|
|
45
|
+
efforts: readonly AgyEffort[],
|
|
46
|
+
): AgyEffort {
|
|
47
|
+
let candidate: AgyEffort;
|
|
48
|
+
switch (reasoning) {
|
|
49
|
+
case "minimal":
|
|
50
|
+
case "low":
|
|
51
|
+
candidate = "low";
|
|
52
|
+
break;
|
|
53
|
+
case "medium":
|
|
54
|
+
candidate = "medium";
|
|
55
|
+
break;
|
|
56
|
+
case "high":
|
|
57
|
+
case "xhigh":
|
|
58
|
+
case "max":
|
|
59
|
+
candidate = "high";
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
candidate = efforts[0] ?? "low";
|
|
63
|
+
}
|
|
64
|
+
if (efforts.includes(candidate)) return candidate;
|
|
65
|
+
const i = AGY_EFFORT_ORDER.indexOf(candidate);
|
|
66
|
+
for (let j = i; j < AGY_EFFORT_ORDER.length; j++) {
|
|
67
|
+
if (efforts.includes(AGY_EFFORT_ORDER[j])) return AGY_EFFORT_ORDER[j];
|
|
68
|
+
}
|
|
69
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
70
|
+
if (efforts.includes(AGY_EFFORT_ORDER[j])) return AGY_EFFORT_ORDER[j];
|
|
71
|
+
}
|
|
72
|
+
return efforts[0] ?? "low";
|
|
73
|
+
}
|
|
74
|
+
|
|
34
75
|
/** Split an agy slug into (base, tier). tier is null when the slug has no
|
|
35
76
|
* -high/-medium/-low suffix (claude-sonnet-4-6, gpt-oss-120b-medium's "medium"
|
|
36
77
|
* IS its suffix here, claude-opus-4-6-thinking is not a tier). */
|
package/src/provider.ts
CHANGED
|
@@ -19,13 +19,15 @@
|
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
createAssistantMessageEventStream,
|
|
22
|
+
getCurrentSystemPrompt,
|
|
22
23
|
type AssistantMessage,
|
|
23
24
|
type AssistantMessageEventStream,
|
|
24
|
-
type
|
|
25
|
+
type JsonValue,
|
|
25
26
|
type Message,
|
|
26
27
|
type Model,
|
|
27
28
|
type SimpleStreamOptions,
|
|
28
29
|
type ThinkingLevel,
|
|
30
|
+
type TranscriptContext,
|
|
29
31
|
type Usage,
|
|
30
32
|
} from "@earendil-works/pi-ai";
|
|
31
33
|
import fs from "node:fs";
|
|
@@ -33,7 +35,7 @@ import type { Api } from "@earendil-works/pi-ai";
|
|
|
33
35
|
import type { DriverActivity, TurnDriver, TurnHandle } from "./driver-types.js";
|
|
34
36
|
import { toPiUsage } from "./stream-events.js";
|
|
35
37
|
import { mapAgyToolToNative } from "./native-tools.js";
|
|
36
|
-
import {
|
|
38
|
+
import { toAgyEffort, type AgyModelEntry } from "./models.js";
|
|
37
39
|
import { SessionStore } from "./sessions.js";
|
|
38
40
|
import { loadConfig } from "./config.js";
|
|
39
41
|
import { GATE_MARKER, mapNativeToShadow, stripMarkerFields } from "./approval-gate.js";
|
|
@@ -59,7 +61,7 @@ function zeroUsage(): Usage {
|
|
|
59
61
|
/** Extract the latest user message as a flat prompt string. agy maintains its
|
|
60
62
|
* own conversation history via --conversation, so we collapse pi's structured
|
|
61
63
|
* message to text. Returns null if the last message isn't a user message. */
|
|
62
|
-
function extractUserPrompt(context:
|
|
64
|
+
function extractUserPrompt(context: TranscriptContext): string | null {
|
|
63
65
|
const last = context.messages[context.messages.length - 1];
|
|
64
66
|
if (!last || last.role !== "user") return null;
|
|
65
67
|
const content = last.content;
|
|
@@ -75,7 +77,7 @@ function extractUserPrompt(context: Context): string | null {
|
|
|
75
77
|
/** Image blocks of the latest user message (pi-ai ImageContent: base64 data
|
|
76
78
|
* + mimeType). The ACP engine forwards them as typed content blocks; the
|
|
77
79
|
* stream-json CLI prompt is text-only, so its driver simply ignores these. */
|
|
78
|
-
function extractImages(context:
|
|
80
|
+
function extractImages(context: TranscriptContext): Array<{ data: string; mimeType: string }> {
|
|
79
81
|
const last = context.messages[context.messages.length - 1];
|
|
80
82
|
if (!last || last.role !== "user" || typeof last.content === "string") return [];
|
|
81
83
|
return last.content
|
|
@@ -100,7 +102,8 @@ const DIGEST_PREAMBLE =
|
|
|
100
102
|
|
|
101
103
|
// --- pi system prompt (G10) ----------------------------------------------------
|
|
102
104
|
//
|
|
103
|
-
// pi
|
|
105
|
+
// pi normalizes the system prompt into the transcript every turn (read via
|
|
106
|
+
// getCurrentSystemPrompt): its own operating instructions
|
|
104
107
|
// plus every AGENTS.md/CLAUDE.md it loaded (global agent dir first, then
|
|
105
108
|
// ancestors). The provider used to drop it, so agy models never saw the user's
|
|
106
109
|
// machine-level or project-level instructions. agy has no system-prompt flag
|
|
@@ -338,46 +341,6 @@ export interface StreamSimpleDeps {
|
|
|
338
341
|
log?: (event: string, data?: unknown, level?: "debug" | "info" | "warn" | "error") => void;
|
|
339
342
|
}
|
|
340
343
|
|
|
341
|
-
/** pi thinking-effort order mirrors agy's, for clamping. */
|
|
342
|
-
const AGY_EFFORT_ORDER: readonly AgyEffort[] = ["low", "medium", "high"];
|
|
343
|
-
|
|
344
|
-
/** Map pi's thinking level onto one of the tiers `efforts` the base actually
|
|
345
|
-
* supports, clamping to the nearest available. agy rejects an effort tier a
|
|
346
|
-
* base doesn't list (e.g. medium on Pro), so we never emit one. A base slug is
|
|
347
|
-
* invalid without --effort, so when pi sends no level we default to the
|
|
348
|
-
* middle tier (or the highest available). */
|
|
349
|
-
export function toAgyEffort(
|
|
350
|
-
reasoning: ThinkingLevel | undefined,
|
|
351
|
-
efforts: readonly AgyEffort[],
|
|
352
|
-
): AgyEffort {
|
|
353
|
-
let candidate: AgyEffort;
|
|
354
|
-
switch (reasoning) {
|
|
355
|
-
case "minimal":
|
|
356
|
-
case "low":
|
|
357
|
-
candidate = "low";
|
|
358
|
-
break;
|
|
359
|
-
case "medium":
|
|
360
|
-
candidate = "medium";
|
|
361
|
-
break;
|
|
362
|
-
case "high":
|
|
363
|
-
case "xhigh":
|
|
364
|
-
case "max":
|
|
365
|
-
candidate = "high";
|
|
366
|
-
break;
|
|
367
|
-
default:
|
|
368
|
-
candidate = efforts[0] ?? "low";
|
|
369
|
-
}
|
|
370
|
-
if (efforts.includes(candidate)) return candidate;
|
|
371
|
-
const i = AGY_EFFORT_ORDER.indexOf(candidate);
|
|
372
|
-
for (let j = i; j < AGY_EFFORT_ORDER.length; j++) {
|
|
373
|
-
if (efforts.includes(AGY_EFFORT_ORDER[j])) return AGY_EFFORT_ORDER[j];
|
|
374
|
-
}
|
|
375
|
-
for (let j = i - 1; j >= 0; j--) {
|
|
376
|
-
if (efforts.includes(AGY_EFFORT_ORDER[j])) return AGY_EFFORT_ORDER[j];
|
|
377
|
-
}
|
|
378
|
-
return efforts[0] ?? "low";
|
|
379
|
-
}
|
|
380
|
-
|
|
381
344
|
// --- G9: no-patch pi-tool round-trips -----------------------------------------
|
|
382
345
|
//
|
|
383
346
|
// The MCP bridge's onToolCall parks the call here instead of executing it:
|
|
@@ -961,13 +924,14 @@ function nextRtId(kind: "nat" | "wrap"): string {
|
|
|
961
924
|
return `${kind}-${++RT_SEQ}`;
|
|
962
925
|
}
|
|
963
926
|
|
|
964
|
-
/** Emit a complete toolCall block and end the pi call with toolUse.
|
|
927
|
+
/** Emit a complete toolCall block and end the pi call with toolUse.
|
|
928
|
+
* pi 0.86 restricts ToolCall.arguments to JSON-compatible values. */
|
|
965
929
|
function emitToolUse(
|
|
966
930
|
stream: AssistantMessageEventStream,
|
|
967
931
|
blocks: BlockState,
|
|
968
932
|
id: string,
|
|
969
933
|
name: string,
|
|
970
|
-
args: Record<string,
|
|
934
|
+
args: Record<string, JsonValue>,
|
|
971
935
|
): void {
|
|
972
936
|
const partial = blocks.partial;
|
|
973
937
|
closeThinking(stream, blocks);
|
|
@@ -1090,7 +1054,7 @@ function acpEditFileArg(args: Record<string, unknown>): string | undefined {
|
|
|
1090
1054
|
emitToolUse(stream, blocks, id, mapped.tool, {
|
|
1091
1055
|
reasoning: `re-exec of agy ${activity.name} for display`,
|
|
1092
1056
|
...mapped.args,
|
|
1093
|
-
});
|
|
1057
|
+
} as Record<string, JsonValue>);
|
|
1094
1058
|
return "parked";
|
|
1095
1059
|
}
|
|
1096
1060
|
{
|
|
@@ -1107,7 +1071,9 @@ function acpEditFileArg(args: Record<string, unknown>): string | undefined {
|
|
|
1107
1071
|
case "bridge_call": {
|
|
1108
1072
|
// Park the pi call: real tool name + args, toolUse stopReason. pi
|
|
1109
1073
|
// executes; the toolResult returns on the next stream call.
|
|
1110
|
-
|
|
1074
|
+
// Driver args are JSON-decoded off the agy wire, so the JsonValue
|
|
1075
|
+
// cast is sound.
|
|
1076
|
+
emitToolUse(stream, blocks, activity.callId, activity.name, activity.args as Record<string, JsonValue>);
|
|
1111
1077
|
return "parked";
|
|
1112
1078
|
}
|
|
1113
1079
|
}
|
|
@@ -1117,7 +1083,7 @@ function acpEditFileArg(args: Record<string, unknown>): string | undefined {
|
|
|
1117
1083
|
async function runTurnDriver(
|
|
1118
1084
|
stream: AssistantMessageEventStream,
|
|
1119
1085
|
model: Model<Api>,
|
|
1120
|
-
context:
|
|
1086
|
+
context: TranscriptContext,
|
|
1121
1087
|
options: SimpleStreamOptions | undefined,
|
|
1122
1088
|
entries: AgyModelEntry[],
|
|
1123
1089
|
store: SessionStore,
|
|
@@ -1219,7 +1185,9 @@ async function runTurnDriver(
|
|
|
1219
1185
|
// Fresh conversation only: agy stores the block in its own history, so
|
|
1220
1186
|
// re-sending it every turn would bloat each prompt and bust the cache.
|
|
1221
1187
|
const sysPrompt =
|
|
1222
|
-
config.systemPrompt && !existing?.conversationId
|
|
1188
|
+
config.systemPrompt && !existing?.conversationId
|
|
1189
|
+
? getCurrentSystemPrompt(context.messages) || undefined
|
|
1190
|
+
: undefined;
|
|
1223
1191
|
const fullPrompt =
|
|
1224
1192
|
late.length > 0
|
|
1225
1193
|
? buildLateResultPrompt(late, prompt || undefined)
|
|
@@ -1298,7 +1266,7 @@ async function runTurnDriver(
|
|
|
1298
1266
|
* fallback). */
|
|
1299
1267
|
export function createStreamSimple(
|
|
1300
1268
|
deps: StreamSimpleDeps,
|
|
1301
|
-
): (model: Model<Api>, context:
|
|
1269
|
+
): (model: Model<Api>, context: TranscriptContext, options?: SimpleStreamOptions) => AssistantMessageEventStream {
|
|
1302
1270
|
const { entries, store, roundTrips } = deps;
|
|
1303
1271
|
|
|
1304
1272
|
return function streamSimple(model, context, options) {
|