This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
The following commit(s) were added to refs/heads/master by this push:
new db34f8e fix(agents): say when a switched Codex account needs the
agent restarted (#232)
db34f8e is described below
commit db34f8ec3ce2bcf6b6c0628666a3222f181faa92
Author: qioo777 <[email protected]>
AuthorDate: Fri Sep 18 18:29:57 2026 +0800
fix(agents): say when a switched Codex account needs the agent restarted
(#232)
---
controllers/agent_account.go | 36 +++++++++++++++++++++++++-----------
web/src/Setting.tsx | 4 +++-
web/src/backend/AgentBackend.ts | 3 ++-
web/src/lib/agents.ts | 29 +++++++++++++++++++++++------
web/src/locales/en/data.json | 1 +
web/src/locales/zh/data.json | 1 +
web/src/types.ts | 6 ++++++
7 files changed, 61 insertions(+), 19 deletions(-)
diff --git a/controllers/agent_account.go b/controllers/agent_account.go
index e25e542..039d579 100644
--- a/controllers/agent_account.go
+++ b/controllers/agent_account.go
@@ -23,6 +23,7 @@ import (
"github.com/apache/casbin-gateway/agent"
"github.com/apache/casbin-gateway/agentauth"
"github.com/apache/casbin-gateway/agentpatch"
+ "github.com/apache/casbin-gateway/agentprocess"
"github.com/apache/casbin-gateway/object"
)
@@ -33,6 +34,15 @@ type agentAccountView struct {
Current bool `json:"current"`
}
+// agentAccountSwitchView is the answer to a swap: the account now in the
+// credential file, and whether the agent has to be restarted before it uses
it.
+type agentAccountSwitchView struct {
+ agentAccountView
+ // Restart marks a swap made while the agent was running. An agent
reads its
+ // sign-in when it starts, so what is running keeps the account it read
then.
+ Restart bool `json:"restart"`
+}
+
// agentAccountsView is the accounts of one agent and what it is signed in to,
// which may be an account Gateway has not been given a copy of yet.
type agentAccountsView struct {
@@ -124,7 +134,7 @@ func (c *ApiController) SaveAgentAccount() {
return
}
- form, home, ok := c.readAgentAccountForm()
+ form, _, home, ok := c.readAgentAccountForm()
if !ok {
return
}
@@ -153,7 +163,7 @@ func (c *ApiController) AddAgentAccount() {
return
}
- form, _, ok := c.readAgentAccountForm()
+ form, _, _, ok := c.readAgentAccountForm()
if !ok {
return
}
@@ -178,7 +188,7 @@ func (c *ApiController) SwitchAgentAccount() {
return
}
- form, home, ok := c.readAgentAccountForm()
+ form, installation, home, ok := c.readAgentAccountForm()
if !ok {
return
}
@@ -216,7 +226,10 @@ func (c *ApiController) SwitchAgentAccount() {
c.ResponseError(err.Error())
return
}
- c.ResponseOk(agentAccountView{AgentAccount: account, Current: true})
+ c.ResponseOk(agentAccountSwitchView{
+ agentAccountView: agentAccountView{AgentAccount: account,
Current: true},
+ Restart:
agentprocess.StatusOf(processTarget(installation)).Running,
+ })
}
// UpdateAgentAccount renames one stored account in the lists.
@@ -322,27 +335,28 @@ func (c *ApiController) CancelAgentSignin() {
}
// readAgentAccountForm resolves the body against the installations a scan
found
-// and answers with the directory its sign-in is read from. Writing there is
-// writing into somebody's home, so an unverified body would name any of them.
-func (c *ApiController) readAgentAccountForm() (agentAccountForm, string,
bool) {
+// and answers with the installation and the directory its sign-in is read
from.
+// Writing there is writing into somebody's home, so an unverified body would
+// name any of them.
+func (c *ApiController) readAgentAccountForm() (agentAccountForm,
agent.Installation, string, bool) {
var form agentAccountForm
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &form); err != nil {
c.ResponseError(err.Error())
- return form, "", false
+ return form, agent.Installation{}, "", false
}
installation, err := findInstallation(form.AgentId, form.Path,
form.Owner)
if err != nil {
c.ResponseError(err.Error())
- return form, "", false
+ return form, agent.Installation{}, "", false
}
home, err := agentauth.HomeOf(installation.AgentId, installation.Path,
installation.Owner)
if err != nil {
c.ResponseError(err.Error())
- return form, "", false
+ return form, agent.Installation{}, "", false
}
form.AgentId = installation.AgentId
- return form, home, true
+ return form, installation, home, true
}
// codexLoginProgram is the Codex program a sign-in is run with. The desktop
app
diff --git a/web/src/Setting.tsx b/web/src/Setting.tsx
index d6d1c68..8d2ac02 100644
--- a/web/src/Setting.tsx
+++ b/web/src/Setting.tsx
@@ -102,7 +102,7 @@ export function goToLink(link: string) {
window.location.href = link;
}
-export function showMessage(type: "" | "success" | "error" | "info", text:
string) {
+export function showMessage(type: "" | "success" | "warning" | "error" |
"info", text: string) {
// Backend messages are worth pasting into a bug report, and a toast is gone
// before it can be selected by hand, so every one carries a copy button.
const options = {action: <CopyButton value={text} className="text-current"
/>};
@@ -111,6 +111,8 @@ export function showMessage(type: "" | "success" | "error"
| "info", text: strin
return;
} else if (type === "success") {
toast.success(text, options);
+ } else if (type === "warning") {
+ toast.warning(text, options);
} else if (type === "error") {
toast.error(text, options);
} else {
diff --git a/web/src/backend/AgentBackend.ts b/web/src/backend/AgentBackend.ts
index 5004b51..1c3701c 100644
--- a/web/src/backend/AgentBackend.ts
+++ b/web/src/backend/AgentBackend.ts
@@ -32,6 +32,7 @@ import type {
BrowseListing,
SavedAccount,
SavedAccounts,
+ SwitchedAccount,
} from "@/types";
export interface PatchTarget {
@@ -222,7 +223,7 @@ export function addAgentAccount(target: PatchTarget,
apiKey: string, displayName
/** Puts one stored sign-in back into the agent, saving what it replaces. */
export function switchAgentAccount(target: PatchTarget, name: string) {
- return request<SavedAccount>("/api/switch-agent-account", "POST",
{...target, name: name});
+ return request<SwitchedAccount>("/api/switch-agent-account", "POST",
{...target, name: name});
}
export function renameAgentAccount(name: string, displayName: string) {
diff --git a/web/src/lib/agents.ts b/web/src/lib/agents.ts
index 2412925..6973b41 100644
--- a/web/src/lib/agents.ts
+++ b/web/src/lib/agents.ts
@@ -35,6 +35,7 @@ import type {
Provider,
SavedAccount,
SavedAccounts,
+ SwitchedAccount,
} from "@/types";
/** How long a started app is given before its process is looked for again. */
@@ -1133,17 +1134,21 @@ export function useAgentAccounts(agents: Agent[],
enabled = true) {
// withUsage is for the calls that change which sign-in is stored or in use;
a
// rename changes neither, so it asks the vendor nothing.
const call = React.useCallback(
- (
+ <T,>(
key: string,
- run: () => Promise<{status: string; msg?: string}>,
- done: string,
+ run: () => Promise<{status: string; msg?: string; data?: T}>,
+ // A string is reported as it stands; a call whose wording depends on the
+ // answer reports it itself.
+ done: string | ((data?: T) => void),
withUsage = false,
) => {
setBusyKey(key);
return run()
.then(res => {
if (res.status === "ok") {
- if (done !== "") {
+ if (typeof done === "function") {
+ done(res.data);
+ } else if (done !== "") {
Setting.showMessage("success", done);
}
load();
@@ -1163,10 +1168,22 @@ export function useAgentAccounts(agents: Agent[],
enabled = true) {
/** Puts one stored sign-in back into the agent, saving what it replaces. */
const switchTo = React.useCallback(
(agent: Agent, account: SavedAccount) =>
- call(
+ call<SwitchedAccount>(
account.name,
() => AgentBackend.switchAgentAccount(targetOf(agent), account.name),
- `${i18next.t("agent:Account switched")}: ${accountName(account)}`,
+ switched => {
+ const done = `${i18next.t("agent:Account switched")}:
${accountName(account)}`;
+ // A running agent keeps the sign-in it started with, and saying the
+ // swap is done would be saying it is already answering as the new
one.
+ if (switched?.restart) {
+ Setting.showMessage(
+ "warning",
+ `${done} - ${i18next.t("agent:Restart the agent for it to take
effect")}`,
+ );
+ } else {
+ Setting.showMessage("success", done);
+ }
+ },
true,
),
[call],
diff --git a/web/src/locales/en/data.json b/web/src/locales/en/data.json
index 9d8ca85..d900334 100644
--- a/web/src/locales/en/data.json
+++ b/web/src/locales/en/data.json
@@ -267,6 +267,7 @@
"Remove the line to clear it": "Remove that line, then start the agent
again.",
"Reported from": "Reported from",
"Resets {time}": "resets {time}",
+ "Restart the agent for it to take effect": "restart the agent for it to
take effect",
"Restore configuration": "Restore configuration",
"Restore confirm hint": "Puts back the provider settings this agent had
before Gateway first wrote them, and leaves every other setting untouched.",
"Restore the configuration of {agent}?": "Restore the configuration of
{agent}?",
diff --git a/web/src/locales/zh/data.json b/web/src/locales/zh/data.json
index 3dea2ab..a6c74d8 100644
--- a/web/src/locales/zh/data.json
+++ b/web/src/locales/zh/data.json
@@ -267,6 +267,7 @@
"Remove the line to clear it": "请删除该行,然后重新启动该Agent。",
"Reported from": "上报来源",
"Resets {time}": "{time}重置",
+ "Restart the agent for it to take effect": "重启Agent后生效",
"Restore configuration": "还原配置",
"Restore confirm hint": "把该Agent在Gateway首次写入之前的供应商配置还原回去,其他配置保持不变。",
"Restore the configuration of {agent}?": "还原{agent}的配置?",
diff --git a/web/src/types.ts b/web/src/types.ts
index 10c624c..6186a3e 100644
--- a/web/src/types.ts
+++ b/web/src/types.ts
@@ -239,6 +239,12 @@ export interface SavedAccount {
current?: boolean;
}
+/** The account a swap put in place, and what it takes for the agent to use
it. */
+export interface SwitchedAccount extends SavedAccount {
+ /** Set when the agent was running: it keeps the sign-in it started with. */
+ restart?: boolean;
+}
+
/** One rate limit window of an account: what is left of it, and when it
fills. */
export interface AccountUsageWindow {
/** What is left of the window, 0 to 100. */
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]