paseo-acp-agy 1.2.6 → 1.2.7
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/dist/acp-server.d.ts +2 -1
- package/dist/acp-server.js +153 -17
- package/dist/antigravity-process.d.ts +10 -1
- package/dist/antigravity-process.js +129 -36
- package/dist/index.js +24 -4
- package/dist/paseo-patcher.js +176 -38
- package/dist/protocol.d.ts +12 -0
- package/dist/protocol.js +31 -6
- package/dist/session-store.d.ts +4 -0
- package/dist/session-store.js +59 -0
- package/dist/session.d.ts +6 -1
- package/dist/session.js +47 -2
- package/dist/transcript.d.ts +25 -0
- package/dist/transcript.js +157 -0
- package/package.json +2 -2
package/dist/paseo-patcher.js
CHANGED
|
@@ -716,35 +716,70 @@ export async function fetchAntigravityUsage() {
|
|
|
716
716
|
|
|
717
717
|
for (const rawLine of lines) {
|
|
718
718
|
const line = rawLine.trim();
|
|
719
|
-
if (!line) continue;
|
|
719
|
+
if (!line || line.toLowerCase().startsWith("quota:")) continue;
|
|
720
720
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
const isGemini = /gemini/i.test(currentModel) || !/claude/i.test(currentModel);
|
|
727
|
-
const match = line.match(/^([A-Za-z0-9\\s_-]+):\\s*(\\d+)%\\s*(?:used)?(?:\\s*\\((?:resets?\\s+in\\s+)?([^)]+)\\))?/i);
|
|
728
|
-
if (match) {
|
|
729
|
-
const limitType = match[1].trim();
|
|
730
|
-
const usedPct = parseInt(match[2], 10);
|
|
731
|
-
const resetStr = match[3] ? match[3].trim() : null;
|
|
721
|
+
let scope = currentModel;
|
|
722
|
+
let limitType = "";
|
|
723
|
+
let remainingPct = null;
|
|
724
|
+
let resetsAt = null;
|
|
732
725
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
const
|
|
742
|
-
|
|
726
|
+
// Format 1: Table format e.g. "Gemini Models Weekly Limit Remaining 56% 2026-10-14 04:37 UTC"
|
|
727
|
+
const m = line.match(/^(.*?)\\s{2,}(.*?Remaining)\\s+(\\d+)%(?:\\s+(.*))?$/i);
|
|
728
|
+
if (m) {
|
|
729
|
+
scope = m[1].trim();
|
|
730
|
+
limitType = m[2].trim();
|
|
731
|
+
remainingPct = parseInt(m[3], 10);
|
|
732
|
+
if (m[4]) {
|
|
733
|
+
try {
|
|
734
|
+
const d = new Date(m[4].trim());
|
|
735
|
+
resetsAt = isNaN(d.getTime()) ? null : d.toISOString();
|
|
736
|
+
} catch {}
|
|
737
|
+
}
|
|
738
|
+
} else {
|
|
739
|
+
// Format 2: Tab / multi-space separated
|
|
740
|
+
const parts = line.split(/\\t+|\\s{2,}/).map(p => p.trim());
|
|
741
|
+
if (parts.length >= 3 && parts[1]?.toLowerCase().includes("remaining")) {
|
|
742
|
+
scope = parts[0];
|
|
743
|
+
limitType = parts[1];
|
|
744
|
+
const remMatch = parts[2].match(/(\\d+)%/);
|
|
745
|
+
if (remMatch) remainingPct = parseInt(remMatch[1], 10);
|
|
746
|
+
if (parts[3]) {
|
|
747
|
+
try {
|
|
748
|
+
const d = new Date(parts[3]);
|
|
749
|
+
resetsAt = isNaN(d.getTime()) ? null : d.toISOString();
|
|
750
|
+
} catch {}
|
|
751
|
+
}
|
|
752
|
+
} else if (line.endsWith(":") && !line.includes("%")) {
|
|
753
|
+
currentModel = line.slice(0, -1).trim();
|
|
754
|
+
continue;
|
|
755
|
+
} else {
|
|
756
|
+
// Format 3: Colon format e.g. "Session: 20% used (resets in 2h)"
|
|
757
|
+
const colonMatch = line.match(/^([A-Za-z0-9\\s_-]+):\\s*(\\d+)%\\s*(?:used)?(?:\\s*\\((?:resets?\\s+in\\s+)?([^)]+)\\))?/i);
|
|
758
|
+
if (colonMatch) {
|
|
759
|
+
limitType = colonMatch[1].trim();
|
|
760
|
+
const usedVal = parseInt(colonMatch[2], 10);
|
|
761
|
+
remainingPct = Math.max(0, 100 - usedVal);
|
|
762
|
+
const resetStr = colonMatch[3] ? colonMatch[3].trim() : null;
|
|
763
|
+
if (resetStr) {
|
|
764
|
+
const durMatch = resetStr.match(/(?:(\\d+)h)?\\s*(?:(\\d+)m)?/i);
|
|
765
|
+
if (durMatch && (durMatch[1] || durMatch[2])) {
|
|
766
|
+
const h = parseInt(durMatch[1] || "0", 10);
|
|
767
|
+
const m = parseInt(durMatch[2] || "0", 10);
|
|
768
|
+
resetsAt = new Date(Date.now() + (h * 3600 + m * 60) * 1000).toISOString();
|
|
769
|
+
} else {
|
|
770
|
+
const parsed = Date.parse(resetStr);
|
|
771
|
+
if (!isNaN(parsed)) resetsAt = new Date(parsed).toISOString();
|
|
772
|
+
}
|
|
773
|
+
}
|
|
743
774
|
}
|
|
744
775
|
}
|
|
776
|
+
}
|
|
745
777
|
|
|
746
|
-
|
|
778
|
+
if (remainingPct !== null && !isNaN(remainingPct)) {
|
|
779
|
+
const usedPct = Math.max(0, Math.min(100, 100 - remainingPct));
|
|
780
|
+
const isFiveHour = /session|five\\s*hour|5-?hour|5h/i.test(limitType);
|
|
747
781
|
const isWeekly = /week|7-?day/i.test(limitType);
|
|
782
|
+
const isGemini = /gemini/i.test(scope) || !/claude/i.test(scope);
|
|
748
783
|
|
|
749
784
|
let id = isFiveHour ? "session" : isWeekly ? "weekly" : "quota";
|
|
750
785
|
let label = isFiveHour ? "Session" : isWeekly ? "Weekly" : limitType.replace(/\\s+Remaining$/i, "");
|
|
@@ -759,7 +794,7 @@ export async function fetchAntigravityUsage() {
|
|
|
759
794
|
shortLabel: isFiveHour ? "5h" : isWeekly ? "wk" : "",
|
|
760
795
|
summary: true,
|
|
761
796
|
usedPct,
|
|
762
|
-
remainingPct
|
|
797
|
+
remainingPct,
|
|
763
798
|
resetsAt,
|
|
764
799
|
tone: toneFromUsedPct(usedPct),
|
|
765
800
|
isFiveHour,
|
|
@@ -826,7 +861,7 @@ export function registerAntigravityUsageSource(server) {
|
|
|
826
861
|
icon: "icon.svg",
|
|
827
862
|
input: z.object({}).passthrough(),
|
|
828
863
|
discover: async (scope) => {
|
|
829
|
-
if (scope && scope.kind === "session" && scope.provider && scope.provider !== "antigravity") {
|
|
864
|
+
if (scope && scope.kind === "session" && scope.provider && scope.provider !== "antigravity" && scope.provider !== "acp") {
|
|
830
865
|
return [];
|
|
831
866
|
}
|
|
832
867
|
return [{ key: "default", label: "Antigravity", input: {} }];
|
|
@@ -903,19 +938,18 @@ export function patchPaseoServer(serverDir) {
|
|
|
903
938
|
indexModified = true;
|
|
904
939
|
}
|
|
905
940
|
// Inject registration call into contribute function
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
const
|
|
913
|
-
if (
|
|
914
|
-
indexCode =
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
indexCode = indexCode.replace(contributeMatch[0], `${before}${body}\n server.registerUsageSource ? registerAntigravityUsageSource(server) : null;\n${after}`);
|
|
941
|
+
if (!indexCode.includes("registerAntigravityUsageSource(server)")) {
|
|
942
|
+
if (/return\s*\(\)\s*=>/.test(indexCode)) {
|
|
943
|
+
indexCode = indexCode.replace(/return\s*\(\)\s*=>/, "server.registerUsageSource ? registerAntigravityUsageSource(server) : null;\n return () =>");
|
|
944
|
+
indexModified = true;
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
const lastBraceIndex = indexCode.lastIndexOf("}");
|
|
948
|
+
if (lastBraceIndex !== -1) {
|
|
949
|
+
indexCode =
|
|
950
|
+
indexCode.slice(0, lastBraceIndex) +
|
|
951
|
+
" server.registerUsageSource ? registerAntigravityUsageSource(server) : null;\n" +
|
|
952
|
+
indexCode.slice(lastBraceIndex);
|
|
919
953
|
indexModified = true;
|
|
920
954
|
}
|
|
921
955
|
}
|
|
@@ -1101,11 +1135,112 @@ ${indent}}`;
|
|
|
1101
1135
|
}
|
|
1102
1136
|
}
|
|
1103
1137
|
}
|
|
1138
|
+
// Patch usageSession() in ACPAgentSession for Paseo 0.11+ usage reporting
|
|
1139
|
+
if (!acpCode.includes("usageSession()")) {
|
|
1140
|
+
const constructorEndMatch = acpCode.match(/(?:^|\n)([ \t]*)this\.extensionCommandsParser\s*=[^;\n]*;[ \t]*\r?\n([ \t]*)\}/);
|
|
1141
|
+
if (constructorEndMatch && constructorEndMatch.index !== undefined) {
|
|
1142
|
+
const indent = constructorEndMatch[1] || " ";
|
|
1143
|
+
const braceIndent = constructorEndMatch[2] || " ";
|
|
1144
|
+
const usageSnippet = `this.usageSessionKey = typeof randomUUID === "function" ? randomUUID() : Math.random().toString(36).slice(2);
|
|
1145
|
+
${braceIndent}}
|
|
1146
|
+
${braceIndent}usageSession() {
|
|
1147
|
+
${braceIndent} if (this.closed)
|
|
1148
|
+
${braceIndent} return null;
|
|
1149
|
+
${braceIndent} if (!this.usageSessionKey) {
|
|
1150
|
+
${braceIndent} this.usageSessionKey = typeof randomUUID === "function" ? randomUUID() : Math.random().toString(36).slice(2);
|
|
1151
|
+
${braceIndent} }
|
|
1152
|
+
${braceIndent} return {
|
|
1153
|
+
${braceIndent} provider: this.provider,
|
|
1154
|
+
${braceIndent} model: this.currentModel ?? this.config?.model,
|
|
1155
|
+
${braceIndent} env: (this.launchEnv && typeof this.launchEnv === "object") ? this.launchEnv : {},
|
|
1156
|
+
${braceIndent} sessionKey: this.usageSessionKey,
|
|
1157
|
+
${braceIndent} };
|
|
1158
|
+
${braceIndent}}`;
|
|
1159
|
+
acpCode = acpCode.replace(/(?:^|\n)([ \t]*)this\.extensionCommandsParser\s*=[^;\n]*;[ \t]*\r?\n([ \t]*)\}/, (match, ind1) => `\n${ind1}this.extensionCommandsParser = options.extensionCommandsParser;\n${ind1}${usageSnippet}`);
|
|
1160
|
+
acpModified = true;
|
|
1161
|
+
}
|
|
1162
|
+
else {
|
|
1163
|
+
const sessionClassMatch = acpCode.match(/(?:export\s+)?class\s+ACPAgentSession\b[^{]*\{/);
|
|
1164
|
+
if (sessionClassMatch && sessionClassMatch.index !== undefined) {
|
|
1165
|
+
const insertPos = sessionClassMatch.index + sessionClassMatch[0].length;
|
|
1166
|
+
const usageSnippet = `\n usageSession() {
|
|
1167
|
+
if (this.closed)
|
|
1168
|
+
return null;
|
|
1169
|
+
if (!this.usageSessionKey) {
|
|
1170
|
+
this.usageSessionKey = typeof randomUUID === "function" ? randomUUID() : Math.random().toString(36).slice(2);
|
|
1171
|
+
}
|
|
1172
|
+
return {
|
|
1173
|
+
provider: this.provider,
|
|
1174
|
+
model: this.currentModel ?? this.config?.model,
|
|
1175
|
+
env: (this.launchEnv && typeof this.launchEnv === "object") ? this.launchEnv : {},
|
|
1176
|
+
sessionKey: this.usageSessionKey,
|
|
1177
|
+
};
|
|
1178
|
+
}`;
|
|
1179
|
+
acpCode = acpCode.slice(0, insertPos) + usageSnippet + acpCode.slice(insertPos);
|
|
1180
|
+
acpModified = true;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1104
1184
|
if (acpModified) {
|
|
1105
1185
|
fs.writeFileSync(acpFile, acpCode, "utf-8");
|
|
1106
1186
|
changes.push(`Patched ${acpFile} for context-window token telemetry and usage updates`);
|
|
1107
1187
|
}
|
|
1108
1188
|
}
|
|
1189
|
+
// 4. Locate and patch plugin-provider.js (if present) for Paseo 0.11+
|
|
1190
|
+
const pluginProviderCandidates = [
|
|
1191
|
+
path.join(serverDir, "dist", "server", "server", "agent", "plugin-provider.js"),
|
|
1192
|
+
path.join(serverDir, "dist", "server", "agent", "plugin-provider.js"),
|
|
1193
|
+
path.join(serverDir, "dist", "agent", "plugin-provider.js"),
|
|
1194
|
+
];
|
|
1195
|
+
let pluginProviderFile = pluginProviderCandidates.find((f) => fs.existsSync(f));
|
|
1196
|
+
if (!pluginProviderFile && fs.existsSync(path.join(serverDir, "dist"))) {
|
|
1197
|
+
const findPluginProvider = (dir, depth = 0) => {
|
|
1198
|
+
if (depth > 5)
|
|
1199
|
+
return null;
|
|
1200
|
+
try {
|
|
1201
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1202
|
+
for (const e of entries) {
|
|
1203
|
+
const full = path.join(dir, e.name);
|
|
1204
|
+
if (e.isDirectory() && e.name !== "node_modules") {
|
|
1205
|
+
const found = findPluginProvider(full, depth + 1);
|
|
1206
|
+
if (found)
|
|
1207
|
+
return found;
|
|
1208
|
+
}
|
|
1209
|
+
else if (e.isFile() && e.name === "plugin-provider.js") {
|
|
1210
|
+
return full;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
catch { }
|
|
1215
|
+
return null;
|
|
1216
|
+
};
|
|
1217
|
+
pluginProviderFile = findPluginProvider(path.join(serverDir, "dist")) || undefined;
|
|
1218
|
+
}
|
|
1219
|
+
if (pluginProviderFile) {
|
|
1220
|
+
let ppCode = fs.readFileSync(pluginProviderFile, "utf-8");
|
|
1221
|
+
if (!ppCode.includes("usageSession()")) {
|
|
1222
|
+
const ppClassMatch = ppCode.match(/(?:export\s+)?class\s+PluginAgentSession\b[^{]*\{/);
|
|
1223
|
+
if (ppClassMatch && ppClassMatch.index !== undefined) {
|
|
1224
|
+
const insertPos = ppClassMatch.index + ppClassMatch[0].length;
|
|
1225
|
+
const ppUsage = `\n usageSession() {
|
|
1226
|
+
if (this.closed)
|
|
1227
|
+
return null;
|
|
1228
|
+
if (!this.usageSessionKey) {
|
|
1229
|
+
this.usageSessionKey = typeof randomUUID === "function" ? randomUUID() : Math.random().toString(36).slice(2);
|
|
1230
|
+
}
|
|
1231
|
+
return {
|
|
1232
|
+
provider: this.provider,
|
|
1233
|
+
model: this.bridge?.config?.model,
|
|
1234
|
+
env: (this.bridge?.launch?.env && typeof this.bridge?.launch?.env === "object") ? this.bridge.launch.env : {},
|
|
1235
|
+
sessionKey: this.usageSessionKey,
|
|
1236
|
+
};
|
|
1237
|
+
}`;
|
|
1238
|
+
ppCode = ppCode.slice(0, insertPos) + ppUsage + ppCode.slice(insertPos);
|
|
1239
|
+
fs.writeFileSync(pluginProviderFile, ppCode, "utf-8");
|
|
1240
|
+
changes.push(`Patched ${pluginProviderFile} with usageSession for plugin provider sessions`);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1109
1244
|
return { success: true, changes };
|
|
1110
1245
|
}
|
|
1111
1246
|
catch (err) {
|
|
@@ -1540,6 +1675,9 @@ export function isPaseoServerPatched(serverDir) {
|
|
|
1540
1675
|
if (!content.includes("this.currentTurnUsage =") || !content.includes("contextWindowMaxTokens")) {
|
|
1541
1676
|
return false;
|
|
1542
1677
|
}
|
|
1678
|
+
if (pluginDir && !content.includes("usageSession()")) {
|
|
1679
|
+
return false;
|
|
1680
|
+
}
|
|
1543
1681
|
}
|
|
1544
1682
|
return true;
|
|
1545
1683
|
}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -106,6 +106,11 @@ export declare const ACP_METHODS: {
|
|
|
106
106
|
readonly SESSION_LOAD_ALIAS: "loadSession";
|
|
107
107
|
readonly SESSION_RESUME: "session/resume";
|
|
108
108
|
readonly SESSION_RESUME_ALIAS: "unstable_resumeSession";
|
|
109
|
+
readonly SESSION_LIST: "session/list";
|
|
110
|
+
readonly SESSION_LIST_CAMEL: "session/listSessions";
|
|
111
|
+
readonly SESSION_LIST_ALIAS: "sessionList";
|
|
112
|
+
readonly SESSION_FORK: "session/fork";
|
|
113
|
+
readonly SESSION_FORK_ALIAS: "forkSession";
|
|
109
114
|
readonly SESSION_PROMPT: "session/prompt";
|
|
110
115
|
readonly SESSION_PROMPT_ALIAS: "prompt";
|
|
111
116
|
readonly SESSION_CANCEL: "session/cancel";
|
|
@@ -123,6 +128,13 @@ export declare const ACP_METHODS: {
|
|
|
123
128
|
readonly SESSION_SET_CONFIG_OPTION_ALIAS: "setSessionConfigOption";
|
|
124
129
|
readonly SESSION_UPDATE: "session/update";
|
|
125
130
|
};
|
|
131
|
+
export interface SessionInfo {
|
|
132
|
+
sessionId: string;
|
|
133
|
+
cwd: string;
|
|
134
|
+
title?: string | null;
|
|
135
|
+
updatedAt?: string | null;
|
|
136
|
+
_meta?: Record<string, unknown> | null;
|
|
137
|
+
}
|
|
126
138
|
export type ToolKind = "read" | "edit" | "execute" | "fetch" | "other";
|
|
127
139
|
export declare function mapToolNameToKind(toolName: string): ToolKind;
|
|
128
140
|
export declare function extractPromptText(promptInput: unknown): string;
|
package/dist/protocol.js
CHANGED
|
@@ -16,6 +16,11 @@ export const ACP_METHODS = {
|
|
|
16
16
|
SESSION_LOAD_ALIAS: "loadSession",
|
|
17
17
|
SESSION_RESUME: "session/resume",
|
|
18
18
|
SESSION_RESUME_ALIAS: "unstable_resumeSession",
|
|
19
|
+
SESSION_LIST: "session/list",
|
|
20
|
+
SESSION_LIST_CAMEL: "session/listSessions",
|
|
21
|
+
SESSION_LIST_ALIAS: "sessionList",
|
|
22
|
+
SESSION_FORK: "session/fork",
|
|
23
|
+
SESSION_FORK_ALIAS: "forkSession",
|
|
19
24
|
SESSION_PROMPT: "session/prompt",
|
|
20
25
|
SESSION_PROMPT_ALIAS: "prompt",
|
|
21
26
|
SESSION_CANCEL: "session/cancel",
|
|
@@ -136,6 +141,8 @@ export const MODEL_PRICING = {
|
|
|
136
141
|
"gemini-3.7-flash": { inputCostPerM: 0.10, outputCostPerM: 0.40, cachedInputCostPerM: 0.025 },
|
|
137
142
|
"gemini-3.6-flash": { inputCostPerM: 0.10, outputCostPerM: 0.40, cachedInputCostPerM: 0.025 },
|
|
138
143
|
"gemini-3.1-pro": { inputCostPerM: 1.25, outputCostPerM: 5.00, cachedInputCostPerM: 0.3125 },
|
|
144
|
+
"claude-opus-5-5": { inputCostPerM: 15.00, outputCostPerM: 75.00, cachedInputCostPerM: 1.50 },
|
|
145
|
+
"claude-sonnet-5-5": { inputCostPerM: 3.00, outputCostPerM: 15.00, cachedInputCostPerM: 0.30 },
|
|
139
146
|
"claude-sonnet-4-6": { inputCostPerM: 3.00, outputCostPerM: 15.00, cachedInputCostPerM: 0.30 },
|
|
140
147
|
"claude-opus-4-6-thinking": { inputCostPerM: 15.00, outputCostPerM: 75.00, cachedInputCostPerM: 1.50 },
|
|
141
148
|
"gpt-oss-120b": { inputCostPerM: 0.15, outputCostPerM: 0.60, cachedInputCostPerM: 0.0375 },
|
|
@@ -145,6 +152,8 @@ export const MODEL_CONTEXT_WINDOWS = {
|
|
|
145
152
|
"gemini-3.7-flash": 1_048_576,
|
|
146
153
|
"gemini-3.6-flash": 1_048_576,
|
|
147
154
|
"gemini-3.1-pro": 2_097_152,
|
|
155
|
+
"claude-opus-5-5": 200_000,
|
|
156
|
+
"claude-sonnet-5-5": 200_000,
|
|
148
157
|
"claude-sonnet-4-6": 200_000,
|
|
149
158
|
"claude-opus-4-6-thinking": 200_000,
|
|
150
159
|
"gpt-oss-120b": 128_000,
|
|
@@ -178,14 +187,14 @@ export function getModelPricing(modelId) {
|
|
|
178
187
|
if (lower.includes("pro"))
|
|
179
188
|
return MODEL_PRICING["gemini-3.1-pro"];
|
|
180
189
|
if (lower.includes("flash"))
|
|
181
|
-
return MODEL_PRICING["gemini-3.
|
|
190
|
+
return MODEL_PRICING["gemini-3.8-flash"];
|
|
182
191
|
if (lower.includes("gpt-oss"))
|
|
183
192
|
return MODEL_PRICING["gpt-oss-120b"];
|
|
184
193
|
return null;
|
|
185
194
|
}
|
|
186
195
|
// Keep costs at full JavaScript floating-point precision. Rounding happens
|
|
187
196
|
// only when values are serialized for the UI so micro-costs accumulate.
|
|
188
|
-
export function calculateUsageCostUsd(modelId = "gemini-3.
|
|
197
|
+
export function calculateUsageCostUsd(modelId = "gemini-3.8-flash", inputTokens = 0, outputTokens = 0, cachedInputTokens = 0) {
|
|
189
198
|
const pricing = getModelPricing(modelId);
|
|
190
199
|
if (!pricing)
|
|
191
200
|
return 0;
|
|
@@ -389,6 +398,8 @@ export const FALLBACK_MODELS = [
|
|
|
389
398
|
{ modelId: "gemini-3.7-flash", name: "Gemini 3.7 Flash", description: "Google Gemini 3.7 Flash", supportedEfforts: ["high", "medium", "low"], contextWindowMaxTokens: 1_048_576 },
|
|
390
399
|
{ modelId: "gemini-3.6-flash", name: "Gemini 3.6 Flash", description: "Google Gemini 3.6 Flash", supportedEfforts: ["high", "medium", "low"], contextWindowMaxTokens: 1_048_576 },
|
|
391
400
|
{ modelId: "gemini-3.1-pro", name: "Gemini 3.1 Pro", description: "Google Gemini 3.1 Pro", supportedEfforts: ["high", "low"], contextWindowMaxTokens: 2_097_152 },
|
|
401
|
+
{ modelId: "claude-opus-5-5", name: "Claude Opus 5.5 (Thinking)", description: "Anthropic Claude Opus 5.5 (Thinking)", supportedEfforts: ["high", "medium", "low"], contextWindowMaxTokens: 200_000 },
|
|
402
|
+
{ modelId: "claude-sonnet-5-5", name: "Claude Sonnet 5.5 (Thinking)", description: "Anthropic Claude Sonnet 5.5 (Thinking)", supportedEfforts: ["high", "medium", "low"], contextWindowMaxTokens: 200_000 },
|
|
392
403
|
{ modelId: "claude-sonnet-4-6", name: "Claude Sonnet 4.6 (Thinking)", description: "Anthropic Claude Sonnet 4.6 (Thinking)", supportedEfforts: [], contextWindowMaxTokens: 200_000 },
|
|
393
404
|
{ modelId: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 (Thinking)", description: "Anthropic Claude Opus 4.6 (Thinking)", supportedEfforts: [], contextWindowMaxTokens: 200_000 },
|
|
394
405
|
{ modelId: "gpt-oss-120b", name: "GPT-OSS 120B", description: "GPT-OSS 120B (Medium)", supportedEfforts: ["medium"], contextWindowMaxTokens: 128_000 },
|
|
@@ -401,8 +412,12 @@ const MODEL_CACHE_TTL_MS = 60_000;
|
|
|
401
412
|
export function parseAgyModelsOutput(rawOutput) {
|
|
402
413
|
const modelsMap = new Map();
|
|
403
414
|
for (const line of rawOutput.split(/[\r\n]+/)) {
|
|
404
|
-
const trimmed = line
|
|
405
|
-
|
|
415
|
+
const trimmed = line
|
|
416
|
+
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "")
|
|
417
|
+
.replace(/[\u2800-\u28ff]+/g, "")
|
|
418
|
+
.replace(/Fetching available models\.\.\./gi, "")
|
|
419
|
+
.trim();
|
|
420
|
+
if (!trimmed)
|
|
406
421
|
continue;
|
|
407
422
|
const parts = trimmed.split(/\t+|\s{2,}/).map((p) => p.trim()).filter(Boolean);
|
|
408
423
|
if (parts.length < 2)
|
|
@@ -456,10 +471,20 @@ export async function fetchAvailableModels(binaryPath = "agy", force = false) {
|
|
|
456
471
|
windowsHide: true,
|
|
457
472
|
});
|
|
458
473
|
const parsed = parseAgyModelsOutput(stdout);
|
|
459
|
-
|
|
474
|
+
const mergedMap = new Map();
|
|
475
|
+
for (const m of parsed) {
|
|
476
|
+
mergedMap.set(m.modelId, m);
|
|
477
|
+
}
|
|
478
|
+
for (const fallback of FALLBACK_MODELS) {
|
|
479
|
+
if (!mergedMap.has(fallback.modelId)) {
|
|
480
|
+
mergedMap.set(fallback.modelId, fallback);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const merged = Array.from(mergedMap.values());
|
|
484
|
+
cachedModels = merged;
|
|
460
485
|
cachedModelsBinaryPath = binaryPath;
|
|
461
486
|
lastModelFetch = Date.now();
|
|
462
|
-
return
|
|
487
|
+
return merged;
|
|
463
488
|
}
|
|
464
489
|
catch (err) {
|
|
465
490
|
logger.warn("Failed to fetch models from agy CLI, using fallback models", {
|
package/dist/session-store.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface PersistedSessionState {
|
|
|
11
11
|
sessionId: string;
|
|
12
12
|
conversationId?: string;
|
|
13
13
|
cwd: string;
|
|
14
|
+
title?: string;
|
|
14
15
|
model: string;
|
|
15
16
|
effort: string;
|
|
16
17
|
mode: string;
|
|
@@ -21,8 +22,11 @@ export interface PersistedSessionState {
|
|
|
21
22
|
export declare class SessionStore {
|
|
22
23
|
private dir;
|
|
23
24
|
constructor(dir?: string);
|
|
25
|
+
get storageDir(): string;
|
|
24
26
|
private pathFor;
|
|
25
27
|
load(sessionId: string): PersistedSessionState | null;
|
|
26
28
|
save(state: PersistedSessionState): void;
|
|
29
|
+
delete(sessionId: string): boolean;
|
|
30
|
+
list(cwd?: string): PersistedSessionState[];
|
|
27
31
|
}
|
|
28
32
|
export declare const sessionStore: SessionStore;
|
package/dist/session-store.js
CHANGED
|
@@ -28,6 +28,9 @@ export class SessionStore {
|
|
|
28
28
|
}
|
|
29
29
|
catch { }
|
|
30
30
|
}
|
|
31
|
+
get storageDir() {
|
|
32
|
+
return this.dir;
|
|
33
|
+
}
|
|
31
34
|
pathFor(sessionId) {
|
|
32
35
|
return path.join(this.dir, fileNameForSession(sessionId));
|
|
33
36
|
}
|
|
@@ -80,5 +83,61 @@ export class SessionStore {
|
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
85
|
}
|
|
86
|
+
delete(sessionId) {
|
|
87
|
+
const filePath = this.pathFor(sessionId);
|
|
88
|
+
try {
|
|
89
|
+
if (fs.existsSync(filePath)) {
|
|
90
|
+
fs.unlinkSync(filePath);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
logger.warn("Failed to delete persisted ACP session", {
|
|
97
|
+
sessionId,
|
|
98
|
+
error: err.message,
|
|
99
|
+
});
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
list(cwd) {
|
|
104
|
+
if (!fs.existsSync(this.dir))
|
|
105
|
+
return [];
|
|
106
|
+
const results = [];
|
|
107
|
+
const normalizedTargetCwd = cwd ? path.resolve(cwd).toLowerCase() : undefined;
|
|
108
|
+
try {
|
|
109
|
+
const files = fs.readdirSync(this.dir);
|
|
110
|
+
for (const file of files) {
|
|
111
|
+
if (!file.endsWith(".json"))
|
|
112
|
+
continue;
|
|
113
|
+
const fullPath = path.join(this.dir, file);
|
|
114
|
+
try {
|
|
115
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
116
|
+
const parsed = JSON.parse(content);
|
|
117
|
+
if (!parsed.sessionId)
|
|
118
|
+
continue;
|
|
119
|
+
if (normalizedTargetCwd && parsed.cwd) {
|
|
120
|
+
const sessionCwd = path.resolve(parsed.cwd).toLowerCase();
|
|
121
|
+
if (sessionCwd !== normalizedTargetCwd)
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
results.push(parsed);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// ignore corrupted individual files
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Sort by updatedAt descending
|
|
131
|
+
results.sort((a, b) => {
|
|
132
|
+
const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
|
133
|
+
const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
134
|
+
return timeB - timeA;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
logger.warn("Failed to list persisted ACP sessions", { error: err.message });
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
83
142
|
}
|
|
84
143
|
export const sessionStore = new SessionStore();
|
package/dist/session.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { AntigravityProcess } from "./antigravity-process.js";
|
|
2
|
+
import { SessionInfo } from "./protocol.js";
|
|
2
3
|
import { SessionStore, SessionUsageState } from "./session-store.js";
|
|
3
4
|
export interface SessionOptions {
|
|
4
5
|
id?: string;
|
|
5
6
|
cwd?: string;
|
|
7
|
+
title?: string;
|
|
6
8
|
model?: string;
|
|
7
9
|
effort?: string;
|
|
8
10
|
mode?: string;
|
|
@@ -18,6 +20,7 @@ export interface SessionOptions {
|
|
|
18
20
|
export declare class Session {
|
|
19
21
|
readonly id: string;
|
|
20
22
|
cwd: string;
|
|
23
|
+
title?: string;
|
|
21
24
|
model: string;
|
|
22
25
|
effort: string;
|
|
23
26
|
mode: string;
|
|
@@ -31,6 +34,7 @@ export declare class Session {
|
|
|
31
34
|
private promptOperationActive;
|
|
32
35
|
constructor(options?: SessionOptions);
|
|
33
36
|
private persistedState;
|
|
37
|
+
setTitle(title: string): void;
|
|
34
38
|
persist(): void;
|
|
35
39
|
get isPromptOperationActive(): boolean;
|
|
36
40
|
tryBeginPromptOperation(): boolean;
|
|
@@ -65,5 +69,6 @@ export declare class SessionManager {
|
|
|
65
69
|
hasPersistedSession(id: string): boolean;
|
|
66
70
|
closeSession(id: string): Promise<boolean>;
|
|
67
71
|
closeAll(): Promise<void>;
|
|
68
|
-
|
|
72
|
+
listActiveSessions(): Session[];
|
|
73
|
+
listSessions(cwd?: string): SessionInfo[];
|
|
69
74
|
}
|
package/dist/session.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { AntigravityProcess } from "./antigravity-process.js";
|
|
3
4
|
import { logger } from "./logger.js";
|
|
4
5
|
import { resolvePermissionSettings } from "./permissions.js";
|
|
@@ -7,6 +8,7 @@ import { sessionStore, } from "./session-store.js";
|
|
|
7
8
|
export class Session {
|
|
8
9
|
id;
|
|
9
10
|
cwd;
|
|
11
|
+
title;
|
|
10
12
|
model;
|
|
11
13
|
effort;
|
|
12
14
|
mode;
|
|
@@ -21,7 +23,8 @@ export class Session {
|
|
|
21
23
|
constructor(options = {}) {
|
|
22
24
|
this.id = options.id || crypto.randomUUID();
|
|
23
25
|
this.cwd = options.cwd || process.cwd();
|
|
24
|
-
this.
|
|
26
|
+
this.title = options.title;
|
|
27
|
+
this.model = options.model || "gemini-3.8-flash";
|
|
25
28
|
this.effort = options.effort || "high";
|
|
26
29
|
this.mode = options.mode || "default";
|
|
27
30
|
this.permission =
|
|
@@ -65,6 +68,7 @@ export class Session {
|
|
|
65
68
|
});
|
|
66
69
|
this.process.on("init", () => this.persist());
|
|
67
70
|
this.process.on("result", () => this.persist());
|
|
71
|
+
this.process.on("conversation_healed", () => this.persist());
|
|
68
72
|
this.persist();
|
|
69
73
|
}
|
|
70
74
|
persistedState() {
|
|
@@ -72,6 +76,7 @@ export class Session {
|
|
|
72
76
|
sessionId: this.id,
|
|
73
77
|
conversationId: this.process.currentConversationId,
|
|
74
78
|
cwd: this.cwd,
|
|
79
|
+
title: this.title,
|
|
75
80
|
model: this.model,
|
|
76
81
|
effort: this.effort,
|
|
77
82
|
mode: this.mode,
|
|
@@ -80,6 +85,12 @@ export class Session {
|
|
|
80
85
|
updatedAt: new Date().toISOString(),
|
|
81
86
|
};
|
|
82
87
|
}
|
|
88
|
+
setTitle(title) {
|
|
89
|
+
if (this.title !== title) {
|
|
90
|
+
this.title = title;
|
|
91
|
+
this.persist();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
83
94
|
persist() {
|
|
84
95
|
this.store.save(this.persistedState());
|
|
85
96
|
}
|
|
@@ -224,6 +235,7 @@ export class SessionManager {
|
|
|
224
235
|
id: options.id,
|
|
225
236
|
binaryPath: options.binaryPath || this.defaultBinaryPath,
|
|
226
237
|
cwd: options.cwd || persisted?.cwd,
|
|
238
|
+
title: options.title || persisted?.title,
|
|
227
239
|
model: options.model || persisted?.model,
|
|
228
240
|
effort: options.effort || persisted?.effort,
|
|
229
241
|
mode: options.mode || persisted?.mode,
|
|
@@ -264,7 +276,40 @@ export class SessionManager {
|
|
|
264
276
|
await Promise.allSettled(Array.from(this.sessions.values(), (session) => session.close()));
|
|
265
277
|
this.sessions.clear();
|
|
266
278
|
}
|
|
267
|
-
|
|
279
|
+
listActiveSessions() {
|
|
268
280
|
return Array.from(this.sessions.values());
|
|
269
281
|
}
|
|
282
|
+
listSessions(cwd) {
|
|
283
|
+
const persisted = this.store.list(cwd);
|
|
284
|
+
const sessionMap = new Map();
|
|
285
|
+
for (const p of persisted) {
|
|
286
|
+
sessionMap.set(p.sessionId, {
|
|
287
|
+
sessionId: p.sessionId,
|
|
288
|
+
cwd: p.cwd,
|
|
289
|
+
title: p.title || (p.cwd ? path.basename(p.cwd) : "Antigravity Session"),
|
|
290
|
+
updatedAt: p.updatedAt,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
for (const active of this.sessions.values()) {
|
|
294
|
+
if (cwd) {
|
|
295
|
+
const targetCwd = path.resolve(cwd).toLowerCase();
|
|
296
|
+
const activeCwd = path.resolve(active.cwd).toLowerCase();
|
|
297
|
+
if (targetCwd !== activeCwd)
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
sessionMap.set(active.id, {
|
|
301
|
+
sessionId: active.id,
|
|
302
|
+
cwd: active.cwd,
|
|
303
|
+
title: active.title || (active.cwd ? path.basename(active.cwd) : "Antigravity Session"),
|
|
304
|
+
updatedAt: active.lastActivity.toISOString(),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
const list = Array.from(sessionMap.values());
|
|
308
|
+
list.sort((a, b) => {
|
|
309
|
+
const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
|
310
|
+
const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
311
|
+
return timeB - timeA;
|
|
312
|
+
});
|
|
313
|
+
return list;
|
|
314
|
+
}
|
|
270
315
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ToolKind } from "./protocol.js";
|
|
2
|
+
export interface ReplayItem {
|
|
3
|
+
type: "user_message" | "agent_message" | "agent_thought" | "tool_call" | "tool_call_update";
|
|
4
|
+
text?: string;
|
|
5
|
+
toolCallId?: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
kind?: ToolKind;
|
|
8
|
+
rawInput?: Record<string, unknown>;
|
|
9
|
+
rawOutput?: string;
|
|
10
|
+
status?: "completed" | "failed";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Strips XML-like tags injected by harness or system prompts (e.g., <USER_REQUEST>, <ADDITIONAL_METADATA>)
|
|
14
|
+
* to recover the clean user prompt for history display in clients like Paseo.
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractCleanUserPrompt(rawText: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the path to the Antigravity conversation directory in ~/.gemini/antigravity-cli/brain/<conversationId>
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveConversationBrainDir(conversationId: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Loads and parses transcript.jsonl (or transcript_full.jsonl) for a conversation,
|
|
23
|
+
* transforming each step into ordered ACP replay events.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadConversationTranscript(conversationId: string): ReplayItem[];
|