feat(goose): add local v1.49 canary routing, smoke gates, and migration docs
Wire Portal and TKMind proxy to loopback Goose v1.49 via canary env blocks, with verification scripts, Phase 2/3 evidence baselines, and rollback runbooks so local upgrade stays isolated from stable 1.41 and production. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+32
-2
@@ -23,6 +23,10 @@ import { reconcileAgentSession } from './session-reconcile.mjs';
|
||||
import { consumeSessionEventsUntilFinish } from './session-reply-wait.mjs';
|
||||
import { createSessionAccess, isSessionBrokerEnabled } from './session-broker.mjs';
|
||||
import { createSessionBrokerMetrics, isSessionBrokerMetricsEnabled } from './session-broker-metrics.mjs';
|
||||
import {
|
||||
resolveGooseApiTargetsFromEnv,
|
||||
resolveGooseTargetForIdentity,
|
||||
} from './scripts/goose-v149-canary.mjs';
|
||||
import { createImgproxySigner } from './imgproxy-signer.mjs';
|
||||
import { isDirectChatSessionId } from './direct-chat-service.mjs';
|
||||
import { ensureGooseUserMessageMetadata } from './goose-message.mjs';
|
||||
@@ -1189,6 +1193,15 @@ export function createTkmindProxy({
|
||||
: null;
|
||||
const targets = apiTargets?.length ? apiTargets : apiTarget ? [apiTarget] : [];
|
||||
const primaryTarget = targets[0] ?? apiTarget ?? '';
|
||||
let gooseCanaryConfig = null;
|
||||
try {
|
||||
gooseCanaryConfig = resolveGooseApiTargetsFromEnv(process.env);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
'[TKMindProxy] Goose v1.49 canary config ignored:',
|
||||
err instanceof Error ? err.message : err,
|
||||
);
|
||||
}
|
||||
let rrIdx = 0;
|
||||
|
||||
let imgproxySigner = null;
|
||||
@@ -1369,6 +1382,23 @@ export function createTkmindProxy({
|
||||
return fallbackPick();
|
||||
}
|
||||
|
||||
async function pickTargetForUser(userId, user = null) {
|
||||
if (gooseCanaryConfig?.mode === 'users' && userId) {
|
||||
const target = resolveGooseTargetForIdentity(
|
||||
{
|
||||
id: String(userId),
|
||||
username: user?.username ?? user?.name ?? '',
|
||||
wechatUserId: user?.wechatUserId ?? user?.wechat_user_id ?? '',
|
||||
},
|
||||
gooseCanaryConfig,
|
||||
);
|
||||
if (target && (targets.includes(target) || target === gooseCanaryConfig.v149 || target === gooseCanaryConfig.stable)) {
|
||||
if (await targetHealthy(target)) return target;
|
||||
}
|
||||
}
|
||||
return pickTarget();
|
||||
}
|
||||
|
||||
async function rememberSessionTarget(sessionId, target) {
|
||||
if (!runtimeRouter || !sessionId || !target) return;
|
||||
await runtimeRouter.registerSession(sessionId, target).catch(() => null);
|
||||
@@ -1491,7 +1521,7 @@ export function createTkmindProxy({
|
||||
const resolvedSessionPolicy = disableImageReading
|
||||
? withoutSessionImageRead(baseSessionPolicy)
|
||||
: baseSessionPolicy;
|
||||
const startTarget = await pickTarget();
|
||||
const startTarget = await pickTargetForUser(userId);
|
||||
const upstream = await apiFetch(startTarget, apiSecret, '/agent/start', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
@@ -2355,7 +2385,7 @@ export function createTkmindProxy({
|
||||
try {
|
||||
const workingDir = await userAuth.resolveWorkingDir(req.currentUser.id);
|
||||
const sessionPolicy = await userAuth.getAgentSessionPolicy(req.currentUser.id);
|
||||
const startTarget = await pickTarget();
|
||||
const startTarget = await pickTargetForUser(req.currentUser.id, req.currentUser);
|
||||
const upstream = await apiFetch(startTarget, apiSecret, '/agent/start', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user