spiracha 2.0.0 → 2.2.0
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/AGENTS.md +27 -12
- package/README.md +42 -19
- package/apps/ui/AGENTS.md +18 -10
- package/apps/ui/README.md +36 -11
- package/apps/ui/src/components/analytics-breakdowns.tsx +106 -0
- package/apps/ui/src/components/antigravity-conversations-table.tsx +51 -11
- package/apps/ui/src/components/antigravity-workspaces-table.tsx +1 -1
- package/apps/ui/src/components/app-shell.tsx +46 -3
- package/apps/ui/src/components/breadcrumbs.tsx +21 -3
- package/apps/ui/src/components/claude-code-sessions-table.tsx +42 -6
- package/apps/ui/src/components/claude-code-workspaces-table.tsx +3 -1
- package/apps/ui/src/components/cursor-threads-table.tsx +10 -47
- package/apps/ui/src/components/data-table.tsx +23 -5
- package/apps/ui/src/components/delete-confirm-dialog.tsx +4 -3
- package/apps/ui/src/components/export-dialog.tsx +79 -74
- package/apps/ui/src/components/grok-sessions-table.tsx +146 -0
- package/apps/ui/src/components/grok-workspaces-table.tsx +53 -0
- package/apps/ui/src/components/kiro-sessions-table.tsx +40 -4
- package/apps/ui/src/components/opencode-sessions-table.tsx +40 -4
- package/apps/ui/src/components/page-header.tsx +15 -9
- package/apps/ui/src/components/projects-table.tsx +4 -1
- package/apps/ui/src/components/qoder-sessions-table.tsx +23 -2
- package/apps/ui/src/components/qoder-workspaces-table.tsx +5 -1
- package/apps/ui/src/components/route-error-panel.tsx +13 -0
- package/apps/ui/src/components/selection-actions-toolbar.tsx +80 -0
- package/apps/ui/src/components/thread-goals-panel.tsx +50 -0
- package/apps/ui/src/components/thread-tools-panel.tsx +142 -0
- package/apps/ui/src/components/threads-table.tsx +13 -47
- package/apps/ui/src/components/transcript-view.tsx +148 -52
- package/apps/ui/src/components/ui/select.tsx +1 -1
- package/apps/ui/src/lib/antigravity-conversation-state.ts +17 -4
- package/apps/ui/src/lib/antigravity-server.ts +209 -11
- package/apps/ui/src/lib/antigravity-transcript-events.ts +57 -73
- package/apps/ui/src/lib/claude-code-queries.ts +8 -0
- package/apps/ui/src/lib/claude-code-server.ts +185 -7
- package/apps/ui/src/lib/claude-code-transcript-events.ts +8 -1
- package/apps/ui/src/lib/codex-queries.ts +16 -0
- package/apps/ui/src/lib/codex-server.ts +134 -52
- package/apps/ui/src/lib/cursor-server.ts +68 -53
- package/apps/ui/src/lib/cursor-transcript-events.ts +11 -86
- package/apps/ui/src/lib/delete-batch.ts +52 -0
- package/apps/ui/src/lib/error-presentation.ts +43 -0
- package/apps/ui/src/lib/export-mutation.ts +20 -0
- package/apps/ui/src/lib/export-options.ts +15 -0
- package/apps/ui/src/lib/formatters.ts +3 -5
- package/apps/ui/src/lib/grok-queries.ts +22 -0
- package/apps/ui/src/lib/grok-server.ts +168 -0
- package/apps/ui/src/lib/grok-transcript-events.ts +149 -0
- package/apps/ui/src/lib/kiro-server.ts +97 -7
- package/apps/ui/src/lib/mutation-error.ts +15 -0
- package/apps/ui/src/lib/opencode-server.ts +96 -7
- package/apps/ui/src/lib/path-utils.ts +1 -1
- package/apps/ui/src/lib/qoder-queries.ts +15 -0
- package/apps/ui/src/lib/qoder-server.ts +67 -11
- package/apps/ui/src/lib/qoder-transcript-events.ts +1 -1
- package/apps/ui/src/lib/route-search.ts +114 -0
- package/apps/ui/src/lib/route-state-reset.tsx +10 -0
- package/apps/ui/src/lib/settings-server.ts +33 -0
- package/apps/ui/src/lib/settings-store.tsx +82 -38
- package/apps/ui/src/lib/settings.ts +65 -0
- package/apps/ui/src/lib/source-session-export-server.ts +86 -3
- package/apps/ui/src/lib/thread-metadata.ts +22 -0
- package/apps/ui/src/lib/thread-transcript-load.ts +15 -0
- package/apps/ui/src/lib/thread-transcript-stats.ts +10 -1
- package/apps/ui/src/lib/workspace-delete-navigation.ts +20 -0
- package/apps/ui/src/routeTree.gen.ts +341 -234
- package/apps/ui/src/routes/__root.tsx +12 -15
- package/apps/ui/src/routes/analytics.tsx +10 -61
- package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +149 -29
- package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +262 -42
- package/apps/ui/src/routes/antigravity.index.tsx +2 -2
- package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +4 -0
- package/apps/ui/src/routes/api.v1.conversations.delete.ts +12 -0
- package/apps/ui/src/routes/api.v1.conversations.export.ts +12 -0
- package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +168 -28
- package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +179 -45
- package/apps/ui/src/routes/claude-code.index.tsx +2 -2
- package/apps/ui/src/routes/codex.$project.tsx +33 -31
- package/apps/ui/src/routes/codex.index.tsx +5 -10
- package/apps/ui/src/routes/cursor-threads.$composerId.tsx +31 -18
- package/apps/ui/src/routes/cursor.$workspaceKey.tsx +44 -28
- package/apps/ui/src/routes/cursor.index.tsx +5 -2
- package/apps/ui/src/routes/grok-sessions.$sessionId.tsx +401 -0
- package/apps/ui/src/routes/grok.$workspaceKey.tsx +295 -0
- package/apps/ui/src/routes/grok.index.tsx +48 -0
- package/apps/ui/src/routes/index.tsx +2 -18
- package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +91 -27
- package/apps/ui/src/routes/kiro.$workspaceKey.tsx +213 -51
- package/apps/ui/src/routes/kiro.index.tsx +2 -2
- package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +108 -29
- package/apps/ui/src/routes/opencode.$workspaceKey.tsx +231 -55
- package/apps/ui/src/routes/opencode.index.tsx +6 -2
- package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +19 -15
- package/apps/ui/src/routes/qoder.$workspaceKey.tsx +89 -48
- package/apps/ui/src/routes/qoder.index.tsx +2 -2
- package/apps/ui/src/routes/threads.$threadId.tsx +620 -105
- package/apps/ui/vite.config.ts +22 -12
- package/bin/spiracha.ts +28 -1
- package/package.json +37 -27
- package/src/client.ts +183 -5
- package/src/lib/antigravity-db.ts +424 -94
- package/src/lib/antigravity-exporter-types.ts +3 -0
- package/src/lib/antigravity-keychain.ts +7 -8
- package/src/lib/antigravity-projects.ts +201 -0
- package/src/lib/antigravity-transcript-phase.ts +47 -0
- package/src/lib/claude-code-db.ts +534 -42
- package/src/lib/claude-code-exporter-types.ts +5 -0
- package/src/lib/claude-code-transcript-phase.ts +60 -1
- package/src/lib/claude-code-transcript.ts +8 -5
- package/src/lib/codex-analytics.ts +32 -5
- package/src/lib/codex-browser-db.ts +540 -137
- package/src/lib/codex-browser-export.ts +18 -27
- package/src/lib/codex-browser-types.ts +21 -1
- package/src/lib/codex-thread-cache.ts +106 -23
- package/src/lib/codex-thread-parser.ts +149 -55
- package/src/lib/codex-thread-recovery.ts +38 -11
- package/src/lib/codex-transcript-filter.ts +31 -0
- package/src/lib/codex-transcript-renderer.ts +87 -79
- package/src/lib/concurrency.ts +56 -3
- package/src/lib/conversation-api.ts +410 -27
- package/src/lib/conversation-data/adapter-helpers.ts +25 -3
- package/src/lib/conversation-data/antigravity-adapter.ts +70 -26
- package/src/lib/conversation-data/claude-code-adapter.ts +69 -12
- package/src/lib/conversation-data/codex-adapter.ts +108 -73
- package/src/lib/conversation-data/cursor-adapter.ts +77 -29
- package/src/lib/conversation-data/grok-adapter.ts +223 -0
- package/src/lib/conversation-data/index.ts +105 -11
- package/src/lib/conversation-data/kiro-adapter.ts +59 -12
- package/src/lib/conversation-data/message-selector.ts +2 -5
- package/src/lib/conversation-data/opencode-adapter.ts +67 -17
- package/src/lib/conversation-data/path-match.ts +1 -13
- package/src/lib/conversation-data/qoder-adapter.ts +67 -37
- package/src/lib/conversation-data/types.ts +43 -0
- package/src/lib/conversation-zip-export.ts +75 -0
- package/src/lib/cursor-db.ts +68 -28
- package/src/lib/cursor-id.ts +17 -0
- package/src/lib/cursor-recovery.ts +146 -35
- package/src/lib/cursor-transcript-phase.ts +40 -0
- package/src/lib/cursor-transcript.ts +21 -5
- package/src/lib/grok-db.ts +1068 -0
- package/src/lib/grok-exporter-types.ts +110 -0
- package/src/lib/grok-transcript-phase.ts +61 -0
- package/src/lib/grok-transcript.ts +167 -0
- package/src/lib/kiro-db.ts +187 -43
- package/src/lib/kiro-transcript.ts +0 -4
- package/src/lib/model-label.ts +11 -3
- package/src/lib/opencode-db.ts +599 -60
- package/src/lib/opencode-think-tags.ts +17 -3
- package/src/lib/opencode-transcript.ts +8 -5
- package/src/lib/portable-path.ts +9 -0
- package/src/lib/qoder-acp-client.ts +11 -2
- package/src/lib/qoder-db.ts +51 -17
- package/src/lib/qoder-transcript-phase.ts +64 -0
- package/src/lib/qoder-transcript.ts +30 -2
- package/src/lib/shared.ts +63 -15
- package/src/lib/sqlite-error.ts +31 -5
- package/src/lib/transcript-load-limiter.ts +87 -0
- package/src/lib/ui-cache.ts +185 -24
- package/src/lib/ui-export-archive.ts +58 -39
- package/src/lib/ui-export-files.ts +75 -15
- package/src/lib/ui-export-zip.ts +40 -0
- package/apps/ui/package.json +0 -65
|
@@ -46,9 +46,11 @@ export type AntigravityConversation = {
|
|
|
46
46
|
indexedItemCount: number | null;
|
|
47
47
|
lastUpdatedAtMs: number | null;
|
|
48
48
|
model: string | null;
|
|
49
|
+
projectId: string | null;
|
|
49
50
|
sourceRoot: string | null;
|
|
50
51
|
summaryPath: string | null;
|
|
51
52
|
title: string;
|
|
53
|
+
totalBytes: number;
|
|
52
54
|
transcriptBytes: number;
|
|
53
55
|
transcriptEntryCount: number;
|
|
54
56
|
transcriptPath: string | null;
|
|
@@ -67,5 +69,6 @@ export type AntigravityWorkspaceGroup = {
|
|
|
67
69
|
label: string;
|
|
68
70
|
lastActiveMs: number;
|
|
69
71
|
transcriptCount: number;
|
|
72
|
+
totalBytes: number;
|
|
70
73
|
uri: string | null;
|
|
71
74
|
};
|
|
@@ -169,19 +169,18 @@ export const getAntigravityDecryptionState = ({
|
|
|
169
169
|
|
|
170
170
|
export const getCachedAntigravityKeychainSecret = (): string | null => cachedKeychainSecret;
|
|
171
171
|
|
|
172
|
+
export const getAntigravityKeychainExecOptions = () => ({ timeout: 10_000 });
|
|
173
|
+
|
|
172
174
|
export const readAntigravityKeychainSecret = async (): Promise<string> => {
|
|
173
175
|
if (process.platform !== 'darwin') {
|
|
174
176
|
throw new Error('Antigravity Keychain access is only available on macOS.');
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
const { stdout } = await execFileAsync(
|
|
178
|
-
'
|
|
179
|
-
'-s',
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
ANTIGRAVITY_KEYCHAIN_ACCOUNT,
|
|
183
|
-
'-w',
|
|
184
|
-
]);
|
|
179
|
+
const { stdout } = await execFileAsync(
|
|
180
|
+
'security',
|
|
181
|
+
['find-generic-password', '-s', ANTIGRAVITY_KEYCHAIN_SERVICE, '-a', ANTIGRAVITY_KEYCHAIN_ACCOUNT, '-w'],
|
|
182
|
+
getAntigravityKeychainExecOptions(),
|
|
183
|
+
);
|
|
185
184
|
const secret = stdout.trim();
|
|
186
185
|
if (!secret) {
|
|
187
186
|
throw new Error(`No secret was returned for ${ANTIGRAVITY_KEYCHAIN_SERVICE}.`);
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { mapWithConcurrency } from './concurrency';
|
|
4
|
+
|
|
5
|
+
type AntigravityDevToolsTarget = {
|
|
6
|
+
type?: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type AntigravityProjectConnection = {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
csrfToken: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type AntigravityProjectRequest = (
|
|
16
|
+
url: string,
|
|
17
|
+
init: RequestInit & { tls?: { rejectUnauthorized: boolean } },
|
|
18
|
+
) => Promise<Response>;
|
|
19
|
+
|
|
20
|
+
type AntigravityProjectResolverOptions = {
|
|
21
|
+
getConnection?: () => Promise<AntigravityProjectConnection | null>;
|
|
22
|
+
request?: AntigravityProjectRequest;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const ANTIGRAVITY_PROJECT_READ_CONCURRENCY = 8;
|
|
26
|
+
const SAFE_PROJECT_ID_PATTERN = /^[a-z0-9._-]{1,128}$/iu;
|
|
27
|
+
|
|
28
|
+
const encodeGrpcWebJson = (value: unknown): Uint8Array => {
|
|
29
|
+
const payload = Buffer.from(JSON.stringify(value));
|
|
30
|
+
const frame = new Uint8Array(payload.length + 5);
|
|
31
|
+
new DataView(frame.buffer).setUint32(1, payload.length);
|
|
32
|
+
frame.set(payload, 5);
|
|
33
|
+
return frame;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const decodeAntigravityGrpcWebJson = (bytes: Uint8Array): unknown => {
|
|
37
|
+
if (bytes.length < 5 || bytes[0] !== 0) {
|
|
38
|
+
throw new Error('Invalid Antigravity gRPC-Web data frame');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const payloadLength = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(1);
|
|
42
|
+
const payloadEnd = 5 + payloadLength;
|
|
43
|
+
if (payloadEnd > bytes.length) {
|
|
44
|
+
throw new Error('Truncated Antigravity gRPC-Web data frame');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return JSON.parse(new TextDecoder().decode(bytes.subarray(5, payloadEnd)));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const extractAntigravityCsrfToken = (processCommands: string): string | null => {
|
|
51
|
+
for (const command of processCommands.split(/\r?\n/u)) {
|
|
52
|
+
if (!command.includes('language_server') || !command.includes('--app_data_dir antigravity')) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const token = command.match(/--csrf_token(?:=|\s+)([a-z0-9-]{16,128})/iu)?.[1];
|
|
57
|
+
if (token) {
|
|
58
|
+
return token;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const extractAntigravityProjectServiceUrl = (targets: AntigravityDevToolsTarget[]): string | null => {
|
|
66
|
+
for (const target of targets) {
|
|
67
|
+
if (target.type !== 'page' || !target.url) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const url = new URL(target.url);
|
|
73
|
+
if (url.protocol === 'https:' && url.hostname === '127.0.0.1' && url.port) {
|
|
74
|
+
return url.origin;
|
|
75
|
+
}
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getAntigravityDevToolsPortPaths = (): string[] => {
|
|
83
|
+
if (process.platform === 'darwin') {
|
|
84
|
+
return [path.join(os.homedir(), 'Library', 'Application Support', 'Antigravity', 'DevToolsActivePort')];
|
|
85
|
+
}
|
|
86
|
+
if (process.platform === 'win32' && process.env.APPDATA) {
|
|
87
|
+
return [path.join(process.env.APPDATA, 'Antigravity', 'DevToolsActivePort')];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [
|
|
91
|
+
path.join(
|
|
92
|
+
process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), '.config'),
|
|
93
|
+
'Antigravity',
|
|
94
|
+
'DevToolsActivePort',
|
|
95
|
+
),
|
|
96
|
+
];
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const readDevToolsPort = async (): Promise<number | null> => {
|
|
100
|
+
for (const filePath of getAntigravityDevToolsPortPaths()) {
|
|
101
|
+
try {
|
|
102
|
+
const port = Number.parseInt((await Bun.file(filePath).text()).split(/\r?\n/u)[0] ?? '', 10);
|
|
103
|
+
if (Number.isInteger(port) && port > 0 && port <= 65_535) {
|
|
104
|
+
return port;
|
|
105
|
+
}
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const readProcessCommands = async (): Promise<string> => {
|
|
113
|
+
if (process.platform === 'win32') {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const processList = Bun.spawn(['ps', '-axo', 'command='], {
|
|
119
|
+
stderr: 'ignore',
|
|
120
|
+
stdout: 'pipe',
|
|
121
|
+
});
|
|
122
|
+
const output = await new Response(processList.stdout).text();
|
|
123
|
+
return (await processList.exited) === 0 ? output : '';
|
|
124
|
+
} catch {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const getRunningAntigravityProjectConnection = async (): Promise<AntigravityProjectConnection | null> => {
|
|
130
|
+
const [devToolsPort, processCommands] = await Promise.all([readDevToolsPort(), readProcessCommands()]);
|
|
131
|
+
const csrfToken = extractAntigravityCsrfToken(processCommands);
|
|
132
|
+
if (!devToolsPort || !csrfToken) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const response = await fetch(`http://127.0.0.1:${devToolsPort}/json/list`, {
|
|
138
|
+
signal: AbortSignal.timeout(1_000),
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const targets = (await response.json()) as AntigravityDevToolsTarget[];
|
|
145
|
+
const baseUrl = extractAntigravityProjectServiceUrl(targets);
|
|
146
|
+
return baseUrl ? { baseUrl, csrfToken } : null;
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const resolveAntigravityProjectNames = async (
|
|
153
|
+
projectIds: string[],
|
|
154
|
+
options: AntigravityProjectResolverOptions = {},
|
|
155
|
+
): Promise<Map<string, string>> => {
|
|
156
|
+
const ids = [...new Set(projectIds)].filter((id) => SAFE_PROJECT_ID_PATTERN.test(id));
|
|
157
|
+
if (ids.length === 0) {
|
|
158
|
+
return new Map();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const connection = await (options.getConnection ?? getRunningAntigravityProjectConnection)();
|
|
162
|
+
if (!connection) {
|
|
163
|
+
return new Map();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const request: AntigravityProjectRequest = options.request ?? ((url, init) => fetch(url, init));
|
|
167
|
+
const projects = await mapWithConcurrency(ids, ANTIGRAVITY_PROJECT_READ_CONCURRENCY, async (projectId) => {
|
|
168
|
+
try {
|
|
169
|
+
const response = await request(
|
|
170
|
+
`${connection.baseUrl}/exa.language_server_pb.LanguageServerService/ReadProject`,
|
|
171
|
+
{
|
|
172
|
+
body: encodeGrpcWebJson({ id: projectId }).buffer as ArrayBuffer,
|
|
173
|
+
headers: {
|
|
174
|
+
'content-type': 'application/grpc-web+json',
|
|
175
|
+
'x-codeium-csrf-token': connection.csrfToken,
|
|
176
|
+
'x-grpc-web': '1',
|
|
177
|
+
},
|
|
178
|
+
method: 'POST',
|
|
179
|
+
signal: AbortSignal.timeout(1_500),
|
|
180
|
+
tls: { rejectUnauthorized: false },
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
if (!response.ok || response.headers.get('grpc-status') === '16') {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const decoded = decodeAntigravityGrpcWebJson(new Uint8Array(await response.arrayBuffer())) as {
|
|
188
|
+
project?: { id?: unknown; name?: unknown };
|
|
189
|
+
};
|
|
190
|
+
const id = decoded.project?.id;
|
|
191
|
+
const name = decoded.project?.name;
|
|
192
|
+
return id === projectId && typeof name === 'string' && name.trim()
|
|
193
|
+
? ([projectId, name.trim()] as const)
|
|
194
|
+
: null;
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return new Map(projects.filter((project): project is readonly [string, string] => project !== null));
|
|
201
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type AntigravityTranscriptPhaseItem = {
|
|
2
|
+
hasContent: boolean;
|
|
3
|
+
hasToolCalls: boolean;
|
|
4
|
+
role: 'assistant' | 'other' | 'user';
|
|
5
|
+
sequence: number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type AntigravityAssistantMessagePhase = 'commentary' | 'final_answer';
|
|
9
|
+
|
|
10
|
+
export const getFinalAntigravityAssistantSequences = (items: AntigravityTranscriptPhaseItem[]): Set<number> => {
|
|
11
|
+
const finalSequences = new Set<number>();
|
|
12
|
+
let latestAssistantContentSequence: number | null = null;
|
|
13
|
+
|
|
14
|
+
const flushAssistantRun = () => {
|
|
15
|
+
if (latestAssistantContentSequence !== null) {
|
|
16
|
+
finalSequences.add(latestAssistantContentSequence);
|
|
17
|
+
}
|
|
18
|
+
latestAssistantContentSequence = null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
for (const item of items) {
|
|
22
|
+
if (item.role === 'user') {
|
|
23
|
+
flushAssistantRun();
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (item.role !== 'assistant') {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (item.hasToolCalls) {
|
|
32
|
+
latestAssistantContentSequence = null;
|
|
33
|
+
} else if (item.hasContent) {
|
|
34
|
+
latestAssistantContentSequence = item.sequence;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
flushAssistantRun();
|
|
39
|
+
return finalSequences;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const getAntigravityAssistantPhase = (
|
|
43
|
+
sequence: number,
|
|
44
|
+
finalAssistantSequences: Set<number>,
|
|
45
|
+
): AntigravityAssistantMessagePhase => {
|
|
46
|
+
return finalAssistantSequences.has(sequence) ? 'final_answer' : 'commentary';
|
|
47
|
+
};
|