fix: use real API response (trajectoryId, current:true, step count diffing)
This commit is contained in:
Binary file not shown.
@@ -286,81 +286,91 @@ function activate(context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Get trajectory descriptions — lightweight list of all conversations
|
// Get trajectory list — returns {trajectories:[{trajectoryId, trajectoryScope, current}]}
|
||||||
const result = await lsRPC('GetUserTrajectoryDescriptions');
|
const result = await lsRPC('GetUserTrajectoryDescriptions');
|
||||||
if (!result) {
|
if (!result || !result.trajectories) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Debug: log structure on first call
|
// Debug: log structure on first call
|
||||||
if (Object.keys(lastStepIndex).length === 0) {
|
const isFirstPoll = Object.keys(lastStepIndex).length === 0;
|
||||||
console.log(`Gravity Bridge: [LS] trajectories response keys: ${typeof result === 'object' ? Object.keys(result).join(', ') : typeof result}`);
|
if (isFirstPoll) {
|
||||||
|
console.log(`Gravity Bridge: [LS] trajectories response keys: ${Object.keys(result).join(', ')}`);
|
||||||
console.log(`Gravity Bridge: [LS] trajectories sample: ${JSON.stringify(result).substring(0, 600)}`);
|
console.log(`Gravity Bridge: [LS] trajectories sample: ${JSON.stringify(result).substring(0, 600)}`);
|
||||||
}
|
}
|
||||||
const trajectories = result.trajectories || result.trajectory_descriptions || result.userTrajectoryDescriptions || result.user_trajectory_descriptions || [];
|
// Find current (active) trajectory
|
||||||
if (!Array.isArray(trajectories)) {
|
const trajectories = result.trajectories;
|
||||||
|
const current = trajectories.find((t) => t.current === true) || trajectories[0];
|
||||||
|
if (!current?.trajectoryId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const traj of trajectories) {
|
const trajId = current.trajectoryId;
|
||||||
const id = traj.googleAgentId || traj.google_agent_id || traj.id || '';
|
// Fetch actual steps to detect changes
|
||||||
const stepIdx = traj.lastStepIndex ?? traj.last_step_index ?? traj.step_count ?? 0;
|
const stepsResult = await lsRPC('GetCascadeTrajectorySteps', {
|
||||||
const prev = lastStepIndex[id];
|
trajectoryId: trajId,
|
||||||
if (prev !== undefined && stepIdx > prev) {
|
});
|
||||||
// New steps! Fetch full trajectory to get AI response
|
if (isFirstPoll && stepsResult) {
|
||||||
console.log(`Gravity Bridge: [LS] ${id.substring(0, 8)} new steps: ${prev} → ${stepIdx}`);
|
console.log(`Gravity Bridge: [LS] steps response keys: ${typeof stepsResult === 'object' ? Object.keys(stepsResult).join(', ') : typeof stepsResult}`);
|
||||||
const full = await lsRPC('GetCascadeTrajectorySteps', {
|
console.log(`Gravity Bridge: [LS] steps sample: ${JSON.stringify(stepsResult).substring(0, 800)}`);
|
||||||
googleAgentId: id,
|
}
|
||||||
trajectoryId: traj.trajectoryId || traj.trajectory_id || '',
|
if (!stepsResult) {
|
||||||
startStepIndex: prev,
|
return;
|
||||||
});
|
}
|
||||||
// Also log structure on first fetch
|
// Count steps — detect new ones
|
||||||
if (full) {
|
const steps = stepsResult.steps || stepsResult.cortexSteps || stepsResult.cortex_steps || [];
|
||||||
console.log(`Gravity Bridge: [LS] steps response keys: ${typeof full === 'object' ? Object.keys(full).join(', ') : typeof full}`);
|
const stepCount = Array.isArray(steps) ? steps.length : 0;
|
||||||
console.log(`Gravity Bridge: [LS] steps sample: ${JSON.stringify(full).substring(0, 600)}`);
|
const prevCount = lastStepIndex[trajId] ?? -1;
|
||||||
}
|
if (prevCount === -1) {
|
||||||
if (full) {
|
// First poll — just record count, don't relay old messages
|
||||||
extractAndRelay(full, prev, stepIdx);
|
lastStepIndex[trajId] = stepCount;
|
||||||
}
|
console.log(`Gravity Bridge: [LS] trajectory ${trajId.substring(0, 8)} initialized with ${stepCount} steps`);
|
||||||
}
|
return;
|
||||||
lastStepIndex[id] = stepIdx;
|
}
|
||||||
|
if (stepCount > prevCount) {
|
||||||
|
console.log(`Gravity Bridge: [LS] ${trajId.substring(0, 8)} new steps: ${prevCount} → ${stepCount}`);
|
||||||
|
// Extract AI text from new steps
|
||||||
|
const newSteps = steps.slice(prevCount);
|
||||||
|
extractAndRelaySteps(newSteps);
|
||||||
|
lastStepIndex[trajId] = stepCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log(`Gravity Bridge: [LS poll] error: ${e}`);
|
console.log(`Gravity Bridge: [LS poll] error: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function extractAndRelay(trajectory, fromStep, toStep) {
|
function extractAndRelaySteps(steps) {
|
||||||
// Extract PlannerResponse or assistant messages from trajectory steps
|
|
||||||
const steps = trajectory.steps || trajectory.cortex_steps || [];
|
|
||||||
const messages = [];
|
const messages = [];
|
||||||
for (const step of steps) {
|
for (const step of steps) {
|
||||||
const idx = step.index ?? step.step_index ?? 0;
|
// Try every possible way to find AI text in a step
|
||||||
if (idx <= fromStep) {
|
const type = step.type || step.stepType || step.step_type || '';
|
||||||
|
const content = step.content || step.summary || step.text || step.message || '';
|
||||||
|
// PlannerResponse = AI's text output to user
|
||||||
|
if (content && (type.includes('Response') || type.includes('response') ||
|
||||||
|
type.includes('Message') || type.includes('message') ||
|
||||||
|
type.includes('Notify') || type.includes('notify'))) {
|
||||||
|
messages.push(content);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const type = step.type || step.step_type || '';
|
// Check nested data/content
|
||||||
const content = step.content || step.summary || step.text || '';
|
|
||||||
// PlannerResponse = AI's text output to user
|
|
||||||
if ((type === 'PlannerResponse' || type === 'planner_response') && content) {
|
|
||||||
messages.push(content);
|
|
||||||
}
|
|
||||||
// Also capture user-facing messages
|
|
||||||
if (step.data?.content && typeof step.data.content === 'string') {
|
if (step.data?.content && typeof step.data.content === 'string') {
|
||||||
messages.push(step.data.content);
|
messages.push(step.data.content);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
// Check role-based (assistant messages)
|
||||||
// Fallback: if no detailed steps, try messages array
|
if ((step.role === 'assistant' || step.role === 'model') && content) {
|
||||||
if (messages.length === 0) {
|
messages.push(content);
|
||||||
const msgs = trajectory.messages || trajectory.chat_messages || [];
|
continue;
|
||||||
for (const msg of msgs) {
|
}
|
||||||
if (msg.role === 'assistant' && msg.content) {
|
// Catch-all: any string content longer than 20 chars that's not a tool call
|
||||||
messages.push(msg.content);
|
if (typeof content === 'string' && content.length > 20 &&
|
||||||
}
|
!type.includes('Tool') && !type.includes('tool') &&
|
||||||
|
!type.includes('Command') && !type.includes('command')) {
|
||||||
|
messages.push(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (messages.length > 0) {
|
if (messages.length > 0) {
|
||||||
const combined = messages.join('\n\n---\n\n');
|
const combined = messages.join('\n\n---\n\n');
|
||||||
writeChatSnapshot(combined);
|
writeChatSnapshot(combined);
|
||||||
console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) to Discord`);
|
console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) (${combined.length} chars) to Discord`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Start LS bridge after a delay
|
// Start LS bridge after a delay
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -266,88 +266,107 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
async function pollConversations() {
|
async function pollConversations() {
|
||||||
if (!lsPort) { return; }
|
if (!lsPort) { return; }
|
||||||
try {
|
try {
|
||||||
// Get trajectory descriptions — lightweight list of all conversations
|
// Get trajectory list — returns {trajectories:[{trajectoryId, trajectoryScope, current}]}
|
||||||
const result = await lsRPC('GetUserTrajectoryDescriptions');
|
const result = await lsRPC('GetUserTrajectoryDescriptions');
|
||||||
if (!result) { return; }
|
if (!result || !result.trajectories) { return; }
|
||||||
|
|
||||||
// Debug: log structure on first call
|
// Debug: log structure on first call
|
||||||
if (Object.keys(lastStepIndex).length === 0) {
|
const isFirstPoll = Object.keys(lastStepIndex).length === 0;
|
||||||
console.log(`Gravity Bridge: [LS] trajectories response keys: ${typeof result === 'object' ? Object.keys(result).join(', ') : typeof result}`);
|
if (isFirstPoll) {
|
||||||
|
console.log(`Gravity Bridge: [LS] trajectories response keys: ${Object.keys(result).join(', ')}`);
|
||||||
console.log(`Gravity Bridge: [LS] trajectories sample: ${JSON.stringify(result).substring(0, 600)}`);
|
console.log(`Gravity Bridge: [LS] trajectories sample: ${JSON.stringify(result).substring(0, 600)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const trajectories = result.trajectories || result.trajectory_descriptions || result.userTrajectoryDescriptions || result.user_trajectory_descriptions || [];
|
// Find current (active) trajectory
|
||||||
if (!Array.isArray(trajectories)) { return; }
|
const trajectories = result.trajectories as any[];
|
||||||
|
const current = trajectories.find((t: any) => t.current === true) || trajectories[0];
|
||||||
|
if (!current?.trajectoryId) { return; }
|
||||||
|
|
||||||
for (const traj of trajectories) {
|
const trajId = current.trajectoryId;
|
||||||
const id = traj.googleAgentId || traj.google_agent_id || traj.id || '';
|
|
||||||
const stepIdx = traj.lastStepIndex ?? traj.last_step_index ?? traj.step_count ?? 0;
|
|
||||||
const prev = lastStepIndex[id];
|
|
||||||
|
|
||||||
if (prev !== undefined && stepIdx > prev) {
|
// Fetch actual steps to detect changes
|
||||||
// New steps! Fetch full trajectory to get AI response
|
const stepsResult = await lsRPC('GetCascadeTrajectorySteps', {
|
||||||
console.log(`Gravity Bridge: [LS] ${id.substring(0, 8)} new steps: ${prev} → ${stepIdx}`);
|
trajectoryId: trajId,
|
||||||
const full = await lsRPC('GetCascadeTrajectorySteps', {
|
});
|
||||||
googleAgentId: id,
|
|
||||||
trajectoryId: traj.trajectoryId || traj.trajectory_id || '',
|
|
||||||
startStepIndex: prev,
|
|
||||||
});
|
|
||||||
// Also log structure on first fetch
|
|
||||||
if (full) {
|
|
||||||
console.log(`Gravity Bridge: [LS] steps response keys: ${typeof full === 'object' ? Object.keys(full).join(', ') : typeof full}`);
|
|
||||||
console.log(`Gravity Bridge: [LS] steps sample: ${JSON.stringify(full).substring(0, 600)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (full) {
|
if (isFirstPoll && stepsResult) {
|
||||||
extractAndRelay(full, prev, stepIdx);
|
console.log(`Gravity Bridge: [LS] steps response keys: ${typeof stepsResult === 'object' ? Object.keys(stepsResult).join(', ') : typeof stepsResult}`);
|
||||||
}
|
console.log(`Gravity Bridge: [LS] steps sample: ${JSON.stringify(stepsResult).substring(0, 800)}`);
|
||||||
}
|
}
|
||||||
lastStepIndex[id] = stepIdx;
|
|
||||||
|
if (!stepsResult) { return; }
|
||||||
|
|
||||||
|
// Count steps — detect new ones
|
||||||
|
const steps = stepsResult.steps || stepsResult.cortexSteps || stepsResult.cortex_steps || [];
|
||||||
|
const stepCount = Array.isArray(steps) ? steps.length : 0;
|
||||||
|
const prevCount = lastStepIndex[trajId] ?? -1;
|
||||||
|
|
||||||
|
if (prevCount === -1) {
|
||||||
|
// First poll — just record count, don't relay old messages
|
||||||
|
lastStepIndex[trajId] = stepCount;
|
||||||
|
console.log(`Gravity Bridge: [LS] trajectory ${trajId.substring(0, 8)} initialized with ${stepCount} steps`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stepCount > prevCount) {
|
||||||
|
console.log(`Gravity Bridge: [LS] ${trajId.substring(0, 8)} new steps: ${prevCount} → ${stepCount}`);
|
||||||
|
// Extract AI text from new steps
|
||||||
|
const newSteps = steps.slice(prevCount);
|
||||||
|
extractAndRelaySteps(newSteps);
|
||||||
|
lastStepIndex[trajId] = stepCount;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Gravity Bridge: [LS poll] error: ${e}`);
|
console.log(`Gravity Bridge: [LS poll] error: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractAndRelay(trajectory: any, fromStep: number, toStep: number) {
|
|
||||||
// Extract PlannerResponse or assistant messages from trajectory steps
|
function extractAndRelaySteps(steps: any[]) {
|
||||||
const steps = trajectory.steps || trajectory.cortex_steps || [];
|
|
||||||
const messages: string[] = [];
|
const messages: string[] = [];
|
||||||
|
|
||||||
for (const step of steps) {
|
for (const step of steps) {
|
||||||
const idx = step.index ?? step.step_index ?? 0;
|
// Try every possible way to find AI text in a step
|
||||||
if (idx <= fromStep) { continue; }
|
const type = step.type || step.stepType || step.step_type || '';
|
||||||
|
const content = step.content || step.summary || step.text || step.message || '';
|
||||||
const type = step.type || step.step_type || '';
|
|
||||||
const content = step.content || step.summary || step.text || '';
|
|
||||||
|
|
||||||
// PlannerResponse = AI's text output to user
|
// PlannerResponse = AI's text output to user
|
||||||
if ((type === 'PlannerResponse' || type === 'planner_response') && content) {
|
if (content && (
|
||||||
|
type.includes('Response') || type.includes('response') ||
|
||||||
|
type.includes('Message') || type.includes('message') ||
|
||||||
|
type.includes('Notify') || type.includes('notify')
|
||||||
|
)) {
|
||||||
messages.push(content);
|
messages.push(content);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
// Also capture user-facing messages
|
|
||||||
|
// Check nested data/content
|
||||||
if (step.data?.content && typeof step.data.content === 'string') {
|
if (step.data?.content && typeof step.data.content === 'string') {
|
||||||
messages.push(step.data.content);
|
messages.push(step.data.content);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: if no detailed steps, try messages array
|
// Check role-based (assistant messages)
|
||||||
if (messages.length === 0) {
|
if ((step.role === 'assistant' || step.role === 'model') && content) {
|
||||||
const msgs = trajectory.messages || trajectory.chat_messages || [];
|
messages.push(content);
|
||||||
for (const msg of msgs) {
|
continue;
|
||||||
if (msg.role === 'assistant' && msg.content) {
|
}
|
||||||
messages.push(msg.content);
|
|
||||||
}
|
// Catch-all: any string content longer than 20 chars that's not a tool call
|
||||||
|
if (typeof content === 'string' && content.length > 20 &&
|
||||||
|
!type.includes('Tool') && !type.includes('tool') &&
|
||||||
|
!type.includes('Command') && !type.includes('command')) {
|
||||||
|
messages.push(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messages.length > 0) {
|
if (messages.length > 0) {
|
||||||
const combined = messages.join('\n\n---\n\n');
|
const combined = messages.join('\n\n---\n\n');
|
||||||
writeChatSnapshot(combined);
|
writeChatSnapshot(combined);
|
||||||
console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) to Discord`);
|
console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) (${combined.length} chars) to Discord`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Start LS bridge after a delay
|
// Start LS bridge after a delay
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const found = await discoverLS();
|
const found = await discoverLS();
|
||||||
|
|||||||
Reference in New Issue
Block a user