mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(telegram): preserve codex login profile identity
This commit is contained in:
@@ -55,6 +55,7 @@ const persistentBindingMocks = vi.hoisted(() => ({
|
||||
const sessionMocks = vi.hoisted(() => ({
|
||||
getSessionEntry: vi.fn(),
|
||||
loadSessionStore: vi.fn(),
|
||||
patchSessionEntry: vi.fn(),
|
||||
recordSessionMetaFromInbound: vi.fn(),
|
||||
resolveStorePath: vi.fn(),
|
||||
}));
|
||||
@@ -175,6 +176,7 @@ vi.mock("openclaw/plugin-sdk/session-store-runtime", async () => {
|
||||
...actual,
|
||||
getSessionEntry: sessionMocks.getSessionEntry,
|
||||
loadSessionStore: sessionMocks.loadSessionStore,
|
||||
patchSessionEntry: sessionMocks.patchSessionEntry,
|
||||
resolveStorePath: sessionMocks.resolveStorePath,
|
||||
};
|
||||
});
|
||||
@@ -640,6 +642,7 @@ function resetSessionMetaMocks() {
|
||||
({ storePath, sessionKey }: { storePath: string; sessionKey: string }) =>
|
||||
sessionMocks.loadSessionStore(storePath)[sessionKey],
|
||||
);
|
||||
sessionMocks.patchSessionEntry.mockClear().mockResolvedValue(null);
|
||||
sessionMocks.recordSessionMetaFromInbound.mockClear().mockResolvedValue(undefined);
|
||||
sessionMocks.resolveStorePath.mockClear().mockReturnValue("/tmp/openclaw-sessions.json");
|
||||
pluginRuntimeMocks.executePluginCommand.mockClear().mockResolvedValue({ text: "ok" });
|
||||
@@ -1617,7 +1620,7 @@ describe("registerTelegramNativeCommands — session metadata", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("passes the target session auth profile to Telegram /login codex", async () => {
|
||||
it("moves the target session to the profile returned by Telegram /login codex", async () => {
|
||||
sessionMocks.loadSessionStore.mockReturnValue({
|
||||
"agent:main:main": {
|
||||
authProfileOverride: "openai:owner@example.com",
|
||||
@@ -1633,7 +1636,9 @@ describe("registerTelegramNativeCommands — session metadata", () => {
|
||||
return {
|
||||
providerId: "openai",
|
||||
methodId: "device-code",
|
||||
profiles: [{ profileId: "openai:owner@example.com", provider: "openai", mode: "oauth" }],
|
||||
profiles: [
|
||||
{ profileId: "openai:new-owner@example.com", provider: "openai", mode: "oauth" },
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1653,9 +1658,33 @@ describe("registerTelegramNativeCommands — session metadata", () => {
|
||||
provider: "openai",
|
||||
method: "device-code",
|
||||
agent: "main",
|
||||
profileId: "openai:owner@example.com",
|
||||
}),
|
||||
);
|
||||
expect(
|
||||
(runModelsAuthLoginFlow.mock.calls[0]?.[0] as { profileId?: string } | undefined)?.profileId,
|
||||
).toBeUndefined();
|
||||
expect(sessionMocks.patchSessionEntry).toHaveBeenCalledWith({
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:main",
|
||||
storePath: "/tmp/openclaw-sessions.json",
|
||||
fallbackEntry: {
|
||||
authProfileOverride: "openai:owner@example.com",
|
||||
sessionId: "sess-main",
|
||||
updatedAt: 1,
|
||||
},
|
||||
preserveActivity: true,
|
||||
update: expect.any(Function),
|
||||
});
|
||||
const patchUpdate = (
|
||||
sessionMocks.patchSessionEntry.mock.calls[0]?.[0] as {
|
||||
update?: () => Record<string, unknown>;
|
||||
}
|
||||
)?.update?.();
|
||||
expect(patchUpdate).toEqual({
|
||||
authProfileOverride: "openai:new-owner@example.com",
|
||||
authProfileOverrideSource: "user",
|
||||
authProfileOverrideCompactionCount: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("passes session identity to plugin commands when the entry has no file", async () => {
|
||||
|
||||
@@ -43,6 +43,7 @@ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import {
|
||||
formatSqliteSessionFileMarker,
|
||||
getSessionEntry,
|
||||
patchSessionEntry,
|
||||
resolveStorePath,
|
||||
type SessionEntry,
|
||||
} from "openclaw/plugin-sdk/session-store-runtime";
|
||||
@@ -1338,21 +1339,50 @@ export const registerTelegramNativeCommands = ({
|
||||
agentId: route.agentId,
|
||||
sessionKey: targetSessionKey,
|
||||
});
|
||||
const profileId = codexChannelLoginRuntime.resolveProviderScopedProfileId(
|
||||
const previousProfileId = codexChannelLoginRuntime.resolveProviderScopedProfileId(
|
||||
targetSessionEntry?.authProfileOverride,
|
||||
loginProvider,
|
||||
);
|
||||
await codexChannelLoginRuntime.runDeviceLoginFlow({
|
||||
const loginResult = await codexChannelLoginRuntime.runDeviceLoginFlow({
|
||||
runLoginFlow: loginFlow,
|
||||
provider: loginProvider,
|
||||
agentId: route.agentId,
|
||||
...(profileId ? { profileId } : {}),
|
||||
config: runtimeCfg,
|
||||
runtime,
|
||||
sendMessage: sendLoginMessage,
|
||||
unsupportedPromptMessage:
|
||||
"Telegram /login supports only fixed Codex device-code auth.",
|
||||
});
|
||||
const nextProfileId = loginResult.profiles.find(
|
||||
(profile) => profile.provider === loginProvider,
|
||||
)?.profileId;
|
||||
if (targetSessionEntry && nextProfileId && nextProfileId !== previousProfileId) {
|
||||
try {
|
||||
const storePath = resolveStorePath(runtimeCfg.session?.store, {
|
||||
agentId: route.agentId,
|
||||
});
|
||||
await patchSessionEntry({
|
||||
agentId: route.agentId,
|
||||
sessionKey: targetSessionKey,
|
||||
storePath,
|
||||
fallbackEntry: targetSessionEntry,
|
||||
preserveActivity: true,
|
||||
update: () => ({
|
||||
authProfileOverride: nextProfileId,
|
||||
authProfileOverrideSource: "user",
|
||||
authProfileOverrideCompactionCount: undefined,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
runtime.error?.(
|
||||
danger(
|
||||
`telegram /login codex completed but failed to update session auth profile: ${String(
|
||||
error,
|
||||
)}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
await sendLoginMessage("Codex login complete. Try your request again now.");
|
||||
} catch {
|
||||
runtime.error?.(danger("telegram /login codex failed"));
|
||||
|
||||
@@ -10,10 +10,15 @@ export type {
|
||||
ModelsAuthLoginFlowOptions,
|
||||
ModelsAuthLoginFlowResult,
|
||||
} from "../commands/models/auth.js";
|
||||
import type { ModelsAuthLoginFlowOptions } from "../commands/models/auth.js";
|
||||
import type {
|
||||
ModelsAuthLoginFlowOptions,
|
||||
ModelsAuthLoginFlowResult,
|
||||
} from "../commands/models/auth.js";
|
||||
|
||||
type ProviderAuthLoginFlowRuntime = typeof import("../commands/models/auth.js");
|
||||
type RunModelsAuthLoginFlow = (opts: ModelsAuthLoginFlowOptions) => Promise<unknown>;
|
||||
type RunModelsAuthLoginFlow = (
|
||||
opts: ModelsAuthLoginFlowOptions,
|
||||
) => Promise<ModelsAuthLoginFlowResult>;
|
||||
|
||||
const CODEX_LOGIN_PROVIDER = "openai";
|
||||
const CODEX_LOGIN_METHOD = "device-code";
|
||||
@@ -134,7 +139,7 @@ async function runCodexDeviceLoginFlow(params: {
|
||||
sendMessage: (message: string) => Promise<void>;
|
||||
unsupportedPromptMessage: string;
|
||||
runLoginFlow?: RunModelsAuthLoginFlow;
|
||||
}): Promise<unknown> {
|
||||
}): Promise<ModelsAuthLoginFlowResult> {
|
||||
return await (params.runLoginFlow ?? runModelsAuthLoginFlow)({
|
||||
provider: params.provider,
|
||||
method: CODEX_LOGIN_METHOD,
|
||||
|
||||
Reference in New Issue
Block a user