akanjs 3.0.0-alpha.30 → 3.0.0-alpha.32
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/dictionary/base.dictionary.ts +19 -0
- package/fetch/client/fetchClient.ts +1 -1
- package/fetch/client/httpClient.ts +12 -10
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/package.json +1 -1
- package/server/akanOption.ts +9 -8
- package/server/devtools/signalSerializer.ts +1 -1
- package/server/devtools/types.ts +2 -2
- package/server/di/diLifecycle.ts +6 -3
- package/server/resolver/signal.resolver.ts +53 -18
- package/signal/guard.ts +15 -0
- package/signal/guards.ts +21 -16
- package/signal/openapi/openapi.ts +3 -2
- package/signal/serializer/fetch.serializer.ts +1 -0
- package/signal/signalContext.ts +3 -16
- package/signal/types.ts +8 -0
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictionary.d.ts +8 -8
- package/types/fetch/client/httpClient.d.ts +2 -1
- package/types/server/akanOption.d.ts +7 -6
- package/types/server/devtools/types.d.ts +2 -2
- package/types/server/resolver/signal.resolver.d.ts +3 -1
- package/types/signal/guard.d.ts +1 -0
- package/types/signal/guards.d.ts +10 -7
- package/types/signal/types.d.ts +7 -0
- package/types/ui/Agent/Chat.d.ts +4 -1
- package/types/ui/Agent/ChatCommands.d.ts +34 -0
- package/types/ui/Agent/Menu.d.ts +12 -0
- package/types/ui/Signal/endpointEntries.d.ts +5 -1
- package/types/vendor/use-agentic/AgentSession.d.ts +14 -2
- package/types/vendor/use-agentic/types.d.ts +5 -0
- package/ui/Agent/Chat.tsx +66 -33
- package/ui/Agent/ChatCommands.ts +129 -0
- package/ui/Agent/Menu.tsx +58 -0
- package/ui/Signal/endpointEntries.ts +15 -4
- package/vendor/use-agentic/AgentSession.ts +40 -5
- package/vendor/use-agentic/types.ts +5 -0
|
@@ -56,6 +56,25 @@ export const baseDictionary = serviceDictionary(["en", "ko"])
|
|
|
56
56
|
agentAnswer: ["Type your answer...", "답변을 입력하세요..."],
|
|
57
57
|
agentContinue: ["This is taking a while. Keep going?", "시간이 걸리고 있습니다. 계속할까요?"],
|
|
58
58
|
agentKeepGoing: ["Keep going", "계속하기"],
|
|
59
|
+
agentCmdNew: ["Start a new conversation", "새 대화 시작"],
|
|
60
|
+
agentCmdRetry: ["Send the last message again", "마지막 메시지 다시 보내기"],
|
|
61
|
+
agentCmdCopy: ["Copy this conversation", "이 대화 복사"],
|
|
62
|
+
agentCmdHelp: ["What you can do here", "여기서 할 수 있는 것"],
|
|
63
|
+
agentCmdTools: ["List this screen's tools", "이 화면의 툴 목록"],
|
|
64
|
+
agentHelpIntro: [
|
|
65
|
+
"Ask about this page, or tell the agent what to do. Commands:",
|
|
66
|
+
"이 화면에 대해 묻거나 할 일을 지시하세요. 커맨드:",
|
|
67
|
+
],
|
|
68
|
+
agentHelpNote: [
|
|
69
|
+
"The agent asks before anything it should not decide alone, and Stop ends a running turn.",
|
|
70
|
+
"에이전트는 혼자 결정하면 안 되는 일을 하기 전에 물어보며, 중지는 진행 중인 턴을 끝냅니다.",
|
|
71
|
+
],
|
|
72
|
+
agentNothingToRetry: ["There is no message to send again.", "다시 보낼 메시지가 없습니다."],
|
|
73
|
+
agentBusy: ["A turn is still running. Stop it first.", "진행 중인 턴이 있습니다. 먼저 중지하세요."],
|
|
74
|
+
agentCopied: ["Conversation copied to the clipboard.", "대화를 클립보드에 복사했습니다."],
|
|
75
|
+
agentCopyFailed: ["Could not reach the clipboard.", "클립보드에 접근할 수 없습니다."],
|
|
76
|
+
agentToolsHead: ["What the agent can do on this screen:", "이 화면에서 에이전트가 할 수 있는 일:"],
|
|
77
|
+
agentToolsState: ["Readable state:", "읽을 수 있는 상태:"],
|
|
59
78
|
send: ["Send", "보내기"],
|
|
60
79
|
stop: ["Stop", "중지"],
|
|
61
80
|
skip: ["Skip", "건너뛰기"],
|
|
@@ -297,7 +297,7 @@ export class FetchClient {
|
|
|
297
297
|
const argMap = new Map(serializerMap.entries().map(([key, serializer], idx) => [key, serializer(args[idx])]));
|
|
298
298
|
const url = FetchClient.makeHttpUrl(key, endpoint, prefix, argMap);
|
|
299
299
|
const body = HttpClient.makeBody(bodyArgs, uploadArgs, argMap);
|
|
300
|
-
const response = await this.http.
|
|
300
|
+
const response = await this.http.send(endpoint.method ?? "POST", url, body, {
|
|
301
301
|
headers: this.#makeAuthHeaders(option),
|
|
302
302
|
baseUrl: option?.origin,
|
|
303
303
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SerializedArg } from "akanjs/signal";
|
|
1
|
+
import type { HttpMutationMethod, SerializedArg } from "akanjs/signal";
|
|
2
2
|
|
|
3
3
|
export interface ErrorResponsePayload {
|
|
4
4
|
error: string;
|
|
@@ -53,31 +53,33 @@ export class HttpClient {
|
|
|
53
53
|
if (data instanceof FormData) return { body: data, headers: {} };
|
|
54
54
|
return { body: JSON.stringify(data), headers: { "Content-Type": "application/json" } };
|
|
55
55
|
}
|
|
56
|
-
async
|
|
56
|
+
async send<Returns = unknown>(
|
|
57
|
+
method: HttpMutationMethod,
|
|
57
58
|
url: string,
|
|
58
59
|
data: FormData | Record<string, unknown>,
|
|
59
60
|
options: FetchOptions = {},
|
|
60
61
|
): Promise<Returns> {
|
|
61
62
|
const { body, headers } = this.#makeReqContent(data);
|
|
62
63
|
const res = await fetch(`${this.#resolveBaseUrl(options.baseUrl)}${url}`, {
|
|
63
|
-
method
|
|
64
|
+
method,
|
|
64
65
|
body,
|
|
65
66
|
headers: { ...headers, ...options.headers },
|
|
66
67
|
});
|
|
67
68
|
return await this.#readJsonResponse<Returns>(res);
|
|
68
69
|
}
|
|
70
|
+
async put<Returns = unknown>(
|
|
71
|
+
url: string,
|
|
72
|
+
data: FormData | Record<string, unknown>,
|
|
73
|
+
options: FetchOptions = {},
|
|
74
|
+
): Promise<Returns> {
|
|
75
|
+
return await this.send<Returns>("PUT", url, data, options);
|
|
76
|
+
}
|
|
69
77
|
async post<Returns = unknown>(
|
|
70
78
|
url: string,
|
|
71
79
|
data: FormData | Record<string, unknown>,
|
|
72
80
|
options: FetchOptions = {},
|
|
73
81
|
): Promise<Returns> {
|
|
74
|
-
|
|
75
|
-
const res = await fetch(`${this.#resolveBaseUrl(options.baseUrl)}${url}`, {
|
|
76
|
-
method: "POST",
|
|
77
|
-
body,
|
|
78
|
-
headers: { ...headers, ...options.headers },
|
|
79
|
-
});
|
|
80
|
-
return await this.#readJsonResponse<Returns>(res);
|
|
82
|
+
return await this.send<Returns>("POST", url, data, options);
|
|
81
83
|
}
|
|
82
84
|
async delete<Returns = unknown>(url: string, options: FetchOptions = {}): Promise<Returns> {
|
|
83
85
|
const res = await fetch(`${this.#resolveBaseUrl(options.baseUrl)}${url}`, {
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/server/akanOption.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BackendEnv, PromiseOrObject } from "akanjs/base";
|
|
2
2
|
import type { Adaptor, AdaptorCls, LlmOption } from "akanjs/service";
|
|
3
|
-
import type {
|
|
3
|
+
import type { GuardCls, MiddlewareCls } from "akanjs/signal";
|
|
4
4
|
import type { McpServerOption } from "./akanServer";
|
|
5
5
|
import type { WebProxyRegistration } from "./proxy";
|
|
6
6
|
import { HostBasePathWebProxy, LocaleWebProxy } from "./proxy";
|
|
@@ -12,7 +12,7 @@ export interface AdaptorOverride {
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* App/library server option builder: use objects, signal middleware, adaptor overrides, web proxies, and the
|
|
15
|
-
* server settings an app owns — MCP, the agent relay's access
|
|
15
|
+
* server settings an app owns — MCP, the agent relay's access guards, and the LLM the relay speaks to.
|
|
16
16
|
*/
|
|
17
17
|
export class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
18
18
|
readonly #getUses: ((env: Env) => Record<string, PromiseOrObject<unknown>>)[];
|
|
@@ -21,7 +21,7 @@ export class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
21
21
|
readonly #webProxies: WebProxyRegistration[] = [];
|
|
22
22
|
readonly #getLlms: ((env: Env) => LlmOption)[] = [];
|
|
23
23
|
#mcp: boolean | McpServerOption | undefined;
|
|
24
|
-
#agentAccess:
|
|
24
|
+
#agentAccess: GuardCls | GuardCls[] | null | undefined;
|
|
25
25
|
constructor() {
|
|
26
26
|
this.#getUses = [];
|
|
27
27
|
}
|
|
@@ -54,11 +54,12 @@ export class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
54
54
|
return this;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Who may spend the LLM key through the `runAgentTurn` relay
|
|
58
|
-
* answer `None` gives — because the framework has no account
|
|
57
|
+
* Who may spend the LLM key through the `runAgentTurn` relay, named as the guards any other endpoint would
|
|
58
|
+
* name. With none the call is refused — the same answer `None` gives — because the framework has no account
|
|
59
|
+
* model to gate on. Several are ANDed; `null` clears what a library set.
|
|
59
60
|
*/
|
|
60
|
-
setAgentAccess(
|
|
61
|
-
this.#agentAccess =
|
|
61
|
+
setAgentAccess(guards: GuardCls | GuardCls[] | null) {
|
|
62
|
+
this.#agentAccess = guards;
|
|
62
63
|
return this;
|
|
63
64
|
}
|
|
64
65
|
/** Settings for whichever adaptor fills `LlmAdaptorRole`, injected into it as the `llmOption` use. */
|
|
@@ -83,7 +84,7 @@ export class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
83
84
|
getMcp(): boolean | McpServerOption | undefined {
|
|
84
85
|
return this.#mcp;
|
|
85
86
|
}
|
|
86
|
-
getAgentAccess():
|
|
87
|
+
getAgentAccess(): GuardCls | GuardCls[] | null | undefined {
|
|
87
88
|
return this.#agentAccess;
|
|
88
89
|
}
|
|
89
90
|
getLlm(env: Env): LlmOption {
|
|
@@ -212,7 +212,7 @@ export class SignalSerializer {
|
|
|
212
212
|
source: typeof source === "function" ? source(key) : source,
|
|
213
213
|
type: node.type,
|
|
214
214
|
transport,
|
|
215
|
-
method: node.type === "mutation" ? "POST" : transport === "http" ? "GET" : null,
|
|
215
|
+
method: node.type === "mutation" ? (info.signalOption.method ?? "POST") : transport === "http" ? "GET" : null,
|
|
216
216
|
path:
|
|
217
217
|
transport === "ws"
|
|
218
218
|
? SignalSerializer.#joinPath(prefix, websocketPrefix)
|
package/server/devtools/types.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { ConstantType, TextFieldRole } from "akanjs/constant";
|
|
12
12
|
import type { RootDictionary } from "akanjs/dictionary";
|
|
13
|
-
import type { ArgType, SerializedArg, SerializedReturns } from "akanjs/signal";
|
|
13
|
+
import type { ArgType, HttpMutationMethod, SerializedArg, SerializedReturns } from "akanjs/signal";
|
|
14
14
|
|
|
15
15
|
export interface DevtoolsIndex {
|
|
16
16
|
version: 1;
|
|
@@ -194,7 +194,7 @@ export interface RouteRow {
|
|
|
194
194
|
source: "declared" | "crud" | "slice";
|
|
195
195
|
type: "query" | "mutation" | "message" | "pubsub" | "prompt";
|
|
196
196
|
transport: "http" | "ws";
|
|
197
|
-
method: "GET" |
|
|
197
|
+
method: "GET" | HttpMutationMethod | null;
|
|
198
198
|
/** Fully prefixed, `:param` placeholders intact — e.g. `/api/user/:userId`. */
|
|
199
199
|
path: string;
|
|
200
200
|
guards: string[];
|
package/server/di/diLifecycle.ts
CHANGED
|
@@ -211,8 +211,11 @@ export class DiLifecycle {
|
|
|
211
211
|
wsRoutes: endpointWsRoutes,
|
|
212
212
|
routeOptions: endpointRouteOptions,
|
|
213
213
|
} = await this.#initializeEndpoint();
|
|
214
|
+
const routes: SignalRoutes["routes"] = {};
|
|
215
|
+
SignalResolver.mergeHttpRoutes(routes, sliceRoutes);
|
|
216
|
+
SignalResolver.mergeHttpRoutes(routes, endpointRoutes);
|
|
214
217
|
return {
|
|
215
|
-
routes
|
|
218
|
+
routes,
|
|
216
219
|
wsRoutes: { ...sliceWsRoutes, ...endpointWsRoutes },
|
|
217
220
|
routeOptions: { ...(sliceRouteOptions ?? {}), ...(endpointRouteOptions ?? {}) },
|
|
218
221
|
};
|
|
@@ -549,7 +552,7 @@ export class DiLifecycle {
|
|
|
549
552
|
live: this.live,
|
|
550
553
|
middleware: this.#middleware,
|
|
551
554
|
});
|
|
552
|
-
|
|
555
|
+
SignalResolver.mergeHttpRoutes(routes, sliceRoutes);
|
|
553
556
|
Object.assign(routeOptions, sliceRouteOptions);
|
|
554
557
|
Object.assign(wsRoutes, sliceWsRoutes);
|
|
555
558
|
this.registry.endpointCls.set(refName, sliceEndpointCls);
|
|
@@ -586,7 +589,7 @@ export class DiLifecycle {
|
|
|
586
589
|
live: this.live,
|
|
587
590
|
middleware: this.#middleware,
|
|
588
591
|
});
|
|
589
|
-
|
|
592
|
+
SignalResolver.mergeHttpRoutes(routes, endpointRoutes);
|
|
590
593
|
Object.assign(routeOptions, endpointRouteOptions);
|
|
591
594
|
Object.assign(wsRoutes, endpointWsRoutes);
|
|
592
595
|
this.registry.endpointCls.set(refName, endpointCls);
|
|
@@ -33,6 +33,9 @@ import type { SliceInfo } from "../../signal/sliceInfo";
|
|
|
33
33
|
import type { WebsocketMessageData, WebsocketSubscribeAck } from "../../signal/types";
|
|
34
34
|
import type { HttpRoutes, SignalRoutes, WebsocketRoutes } from "../types";
|
|
35
35
|
|
|
36
|
+
type HttpRouteHandler = (req: Bun.BunRequest) => Response | Promise<Response | undefined> | undefined;
|
|
37
|
+
type HttpMethodRoutes = Record<string, HttpRouteHandler>;
|
|
38
|
+
|
|
36
39
|
export class SignalResolver {
|
|
37
40
|
static logger = new Logger("SignalResolver");
|
|
38
41
|
|
|
@@ -308,6 +311,28 @@ export class SignalResolver {
|
|
|
308
311
|
Bun.ServerWebSocket<unknown>,
|
|
309
312
|
Map<string, SignalContext<WebSocketExecutionContext>>
|
|
310
313
|
>();
|
|
314
|
+
/**
|
|
315
|
+
* A path may legitimately carry several methods — a `query` GET and a `mutation` POST sharing a custom `path` —
|
|
316
|
+
* so methods merge rather than replace. The same method twice leaves one of the two endpoints unreachable with
|
|
317
|
+
* nothing said about it, and the shadowed half is as easily the guarded one, so it fails the boot instead.
|
|
318
|
+
*/
|
|
319
|
+
static #mountHttpRoute(routes: HttpRoutes, path: string, handlers: HttpMethodRoutes, owner?: string) {
|
|
320
|
+
const table = routes as Record<string, HttpMethodRoutes | undefined>;
|
|
321
|
+
const existing = table[path];
|
|
322
|
+
const conflict = Object.keys(handlers).find((method) => !!existing?.[method]);
|
|
323
|
+
if (conflict)
|
|
324
|
+
throw new Error(
|
|
325
|
+
`Route conflict: ${conflict} ${path} is declared more than once${owner ? ` (by "${owner}")` : ""}.`,
|
|
326
|
+
);
|
|
327
|
+
table[path] = { ...existing, ...handlers };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Same rule across endpoint classes, which are resolved one at a time and then folded into one table. */
|
|
331
|
+
static mergeHttpRoutes(target: HttpRoutes, source: HttpRoutes) {
|
|
332
|
+
for (const [path, handlers] of Object.entries((source ?? {}) as Record<string, HttpMethodRoutes>))
|
|
333
|
+
SignalResolver.#mountHttpRoute(target, path, handlers);
|
|
334
|
+
}
|
|
335
|
+
|
|
311
336
|
static resolveEndpoint(
|
|
312
337
|
endpointCls: EndpointCls,
|
|
313
338
|
endpoint: Endpoint,
|
|
@@ -341,26 +366,38 @@ export class SignalResolver {
|
|
|
341
366
|
}).init();
|
|
342
367
|
return await context.exec();
|
|
343
368
|
});
|
|
369
|
+
if (endpointInfo.signalOption.method && endpointInfo.type !== "mutation")
|
|
370
|
+
SignalResolver.logger.warn(
|
|
371
|
+
`"${key}" declares method ${endpointInfo.signalOption.method} on a ${endpointInfo.type}, which is ignored.`,
|
|
372
|
+
);
|
|
344
373
|
switch (endpointInfo.type) {
|
|
345
374
|
case "query":
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
375
|
+
SignalResolver.#mountHttpRoute(
|
|
376
|
+
routes,
|
|
377
|
+
path,
|
|
378
|
+
SignalResolver.#canUsePrimitiveQueryFastPath(endpointInfo, middleware)
|
|
379
|
+
? {
|
|
380
|
+
GET: async (req) => {
|
|
381
|
+
if (SignalResolver.#hasAuthCredential(req)) return await normalHttpHandler(req);
|
|
382
|
+
return await SignalContext.try(endpoint, endpointInfo, key, async () => {
|
|
383
|
+
const result = await endpointInfo.execFn?.call(endpoint);
|
|
384
|
+
return result instanceof Response ? result : Response.json(result);
|
|
385
|
+
});
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
: {
|
|
389
|
+
GET: normalHttpHandler,
|
|
354
390
|
},
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
GET: normalHttpHandler,
|
|
358
|
-
};
|
|
391
|
+
key,
|
|
392
|
+
);
|
|
359
393
|
break;
|
|
360
394
|
case "mutation":
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
395
|
+
SignalResolver.#mountHttpRoute(
|
|
396
|
+
routes,
|
|
397
|
+
path,
|
|
398
|
+
{ [endpointInfo.signalOption.method ?? "POST"]: normalHttpHandler },
|
|
399
|
+
key,
|
|
400
|
+
);
|
|
364
401
|
break;
|
|
365
402
|
case "prompt":
|
|
366
403
|
|
|
@@ -368,9 +405,7 @@ export class SignalResolver {
|
|
|
368
405
|
SignalResolver.logger.warn(
|
|
369
406
|
`Prompt "${key}" declares no guards, and its GET route is mounted whether or not this app enables MCP.`,
|
|
370
407
|
);
|
|
371
|
-
routes
|
|
372
|
-
GET: normalHttpHandler,
|
|
373
|
-
};
|
|
408
|
+
SignalResolver.#mountHttpRoute(routes, path, { GET: normalHttpHandler }, key);
|
|
374
409
|
break;
|
|
375
410
|
case "pubsub":
|
|
376
411
|
wsRoutes[key] = async (ws, message, event) => {
|
package/signal/guard.ts
CHANGED
|
@@ -28,3 +28,18 @@ export const guard = <T extends string>(name: T): GuardCls<T> => {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Guards read everything from the context they are handed and are already required to be side-effect free and
|
|
34
|
+
* safe to re-run — `SignalResolver.revalidateWsRooms` re-runs them outside of any request — so one instance per
|
|
35
|
+
* class serves every call instead of one per guard per request. Built on first use, not at registration: a guard
|
|
36
|
+
* may be declared long before the container it reads from is up.
|
|
37
|
+
*/
|
|
38
|
+
const instances = new WeakMap<GuardCls, Guard>();
|
|
39
|
+
export const guardOf = (GuardCls: GuardCls): Guard => {
|
|
40
|
+
const cached = instances.get(GuardCls);
|
|
41
|
+
if (cached) return cached;
|
|
42
|
+
const guard = new GuardCls();
|
|
43
|
+
instances.set(GuardCls, guard);
|
|
44
|
+
return guard;
|
|
45
|
+
};
|
package/signal/guards.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Logger } from "akanjs/common";
|
|
2
|
-
import type
|
|
2
|
+
import { type Guard, type GuardCls, type GuardScope, guardOf } from "./guard";
|
|
3
3
|
import type { SignalContext } from "./signalContext";
|
|
4
4
|
|
|
5
5
|
export class Public implements Guard {
|
|
@@ -18,40 +18,45 @@ export class None implements Guard {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export type AgentRelayPolicy = (context: SignalContext) => boolean | Promise<boolean>;
|
|
22
|
-
|
|
23
21
|
/**
|
|
24
22
|
* Gate for the `runAgentTurn` relay. Every tool runs in the caller's own browser session, so the LLM key is the
|
|
25
23
|
* one thing this endpoint spends — ungated, any visitor can bill the app's provider through fetch alone.
|
|
26
24
|
*
|
|
27
|
-
* The framework has no account model to gate on, so with no
|
|
28
|
-
* answer `None` gives. An app
|
|
29
|
-
* `
|
|
25
|
+
* The framework has no account model to gate on, so with no guard registered it refuses every call — the same
|
|
26
|
+
* answer `None` gives. An app names its own at boot, e.g. `AgentRelayAccess.use(Every)`, usually through
|
|
27
|
+
* `option.setAgentAccess(...)`. Several are ANDed, as an endpoint's own `guards` array is.
|
|
30
28
|
*/
|
|
31
29
|
export class AgentRelayAccess implements Guard {
|
|
32
30
|
|
|
33
31
|
static name = "AgentRelayAccess";
|
|
34
|
-
|
|
35
|
-
static scope: GuardScope = "account";
|
|
36
|
-
static #policy: AgentRelayPolicy | null = null;
|
|
32
|
+
static #guards: GuardCls[] = [];
|
|
37
33
|
static #logger = new Logger("AgentRelayAccess");
|
|
38
34
|
|
|
39
|
-
static use(
|
|
40
|
-
AgentRelayAccess.#
|
|
35
|
+
static use(guards: GuardCls | GuardCls[] | null) {
|
|
36
|
+
AgentRelayAccess.#guards = guards ? (Array.isArray(guards) ? [...guards] : [guards]) : [];
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
static get hasPolicy() {
|
|
44
|
-
return !!AgentRelayAccess.#
|
|
40
|
+
return !!AgentRelayAccess.#guards.length;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Whatever the registered guards need, since this one only forwards to them. With none registered it reads the
|
|
45
|
+
* caller and nothing else — the refusal is unconditional — so a listing may still evaluate it argument-free.
|
|
46
|
+
*/
|
|
47
|
+
static get scope(): GuardScope {
|
|
48
|
+
return AgentRelayAccess.#guards.some((GuardCls) => GuardCls.scope === "resource") ? "resource" : "account";
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
async canPass(context: SignalContext): Promise<boolean> {
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
52
|
+
const guards = AgentRelayAccess.#guards;
|
|
53
|
+
if (!guards.length) return false;
|
|
50
54
|
try {
|
|
51
|
-
|
|
55
|
+
for (const GuardCls of guards) if (!(await guardOf(GuardCls).canPass(context))) return false;
|
|
56
|
+
return true;
|
|
52
57
|
} catch (error) {
|
|
53
58
|
AgentRelayAccess.#logger.warn(
|
|
54
|
-
`agent relay
|
|
59
|
+
`agent relay guard threw, failing closed: ${error instanceof Error ? error.message : String(error)}`,
|
|
55
60
|
);
|
|
56
61
|
return false;
|
|
57
62
|
}
|
|
@@ -61,8 +61,9 @@ export const createOpenApiDocument = (
|
|
|
61
61
|
for (const [refName, signal] of Object.entries(serializedSignal)) {
|
|
62
62
|
if (excludeSignals.has(refName)) continue;
|
|
63
63
|
for (const [endpointKey, endpoint] of collectRestEndpoints(refName, signal)) {
|
|
64
|
-
const
|
|
65
|
-
if (!
|
|
64
|
+
const declaredMethod = httpMethods[endpoint.type as keyof typeof httpMethods];
|
|
65
|
+
if (!declaredMethod) continue;
|
|
66
|
+
const method = endpoint.type === "mutation" ? (endpoint.method?.toLowerCase() ?? declaredMethod) : declaredMethod;
|
|
66
67
|
|
|
67
68
|
const path = toOpenApiPath(FetchClient.makeHttpUrl(endpointKey, endpoint, signal.prefix, new Map()));
|
|
68
69
|
if (!options.includeNonStandardPaths && isNonStandardOpenApiPath(path)) continue;
|
|
@@ -65,6 +65,7 @@ export class FetchSerializer {
|
|
|
65
65
|
args: endpointInfo.args.map(FetchSerializer.#serializeArg),
|
|
66
66
|
returns: FetchSerializer.#serializeReturns(endpointInfo),
|
|
67
67
|
...(endpointInfo.signalOption.path ? { path: endpointInfo.signalOption.path } : {}),
|
|
68
|
+
...(endpointInfo.signalOption.method ? { method: endpointInfo.signalOption.method } : {}),
|
|
68
69
|
...(endpointInfo.signalOption.fileUpload ? { fileUpload: true } : {}),
|
|
69
70
|
...(guards?.length ? { guards } : {}),
|
|
70
71
|
};
|
package/signal/signalContext.ts
CHANGED
|
@@ -18,7 +18,7 @@ import type { Adaptor, AdaptorCls, DatabaseService, InjectRegistry, LiveRegistry
|
|
|
18
18
|
import type { Internal, InternalCls, InternalInfo, MiddlewareCls } from ".";
|
|
19
19
|
import type { EndpointInfo, EndpointType } from "./endpointInfo";
|
|
20
20
|
import { Exception } from "./exception";
|
|
21
|
-
import
|
|
21
|
+
import { guardOf } from "./guard";
|
|
22
22
|
|
|
23
23
|
import { Msg } from "./mcp/Msg";
|
|
24
24
|
import { isTraceEnabled, runWithTrace, SignalTrace, traceSpan } from "./trace";
|
|
@@ -128,25 +128,12 @@ export class SignalContext<
|
|
|
128
128
|
}
|
|
129
129
|
return this;
|
|
130
130
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Guards read everything from the context they are handed and are already required to be side-effect free and
|
|
133
|
-
* safe to re-run — `SignalResolver.revalidateWsRooms` re-runs them outside of any request — so one instance per
|
|
134
|
-
* class serves every call instead of one per guard per request.
|
|
135
|
-
*/
|
|
136
|
-
static #guards = new WeakMap<GuardCls, Guard>();
|
|
137
|
-
static #getGuard(GuardCls: GuardCls): Guard {
|
|
138
|
-
const cached = SignalContext.#guards.get(GuardCls);
|
|
139
|
-
if (cached) return cached;
|
|
140
|
-
const guard = new GuardCls();
|
|
141
|
-
SignalContext.#guards.set(GuardCls, guard);
|
|
142
|
-
return guard;
|
|
143
|
-
}
|
|
144
131
|
async #checkGuards() {
|
|
145
132
|
const guards = this.endpointInfo.signalOption.guards ?? [];
|
|
146
133
|
if (guards.length === 0) return;
|
|
147
134
|
await Promise.all(
|
|
148
135
|
guards.map(async (GuardCls) => {
|
|
149
|
-
const canPass = await
|
|
136
|
+
const canPass = await guardOf(GuardCls).canPass(this);
|
|
150
137
|
if (!canPass) throw new Exception.Forbidden(`Access denied by guard: ${GuardCls.name}`);
|
|
151
138
|
}),
|
|
152
139
|
);
|
|
@@ -179,7 +166,7 @@ export class SignalContext<
|
|
|
179
166
|
await this.#withMiddleware(
|
|
180
167
|
async () => {
|
|
181
168
|
for (const GuardCls of guards) {
|
|
182
|
-
if (!(await
|
|
169
|
+
if (!(await guardOf(GuardCls).canPass(this)))
|
|
183
170
|
throw new Exception.Forbidden(`Access denied by guard: ${GuardCls.name}`);
|
|
184
171
|
}
|
|
185
172
|
},
|
package/signal/types.ts
CHANGED
|
@@ -61,6 +61,8 @@ interface TimerOption {
|
|
|
61
61
|
enabled?: boolean;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
export type HttpMutationMethod = "POST" | "PATCH" | "PUT" | "DELETE";
|
|
65
|
+
|
|
64
66
|
export interface SignalOption<Response = any, Nullable extends boolean = false, _Key = keyof UnCls<Response>>
|
|
65
67
|
extends InitOption,
|
|
66
68
|
TimerOption {
|
|
@@ -76,6 +78,11 @@ export interface SignalOption<Response = any, Nullable extends boolean = false,
|
|
|
76
78
|
middlewares?: MiddlewareCls[];
|
|
77
79
|
prefix?: false | string;
|
|
78
80
|
globalPrefix?: false;
|
|
81
|
+
/**
|
|
82
|
+
* HTTP verb for a `mutation`, `POST` unless named. Only a foreign wire protocol needs the others — a client
|
|
83
|
+
* that cannot be changed and sends `PATCH /rest/v1/<table>`. Every other endpoint type ignores it.
|
|
84
|
+
*/
|
|
85
|
+
method?: HttpMutationMethod;
|
|
79
86
|
/** Marks this mutation as the framework file-upload endpoint (see resolveFileUploadCapability). */
|
|
80
87
|
fileUpload?: boolean;
|
|
81
88
|
|
|
@@ -92,6 +99,7 @@ interface SerializedSignalOption {
|
|
|
92
99
|
prefix?: false | string;
|
|
93
100
|
globalPrefix?: false;
|
|
94
101
|
guards?: string[];
|
|
102
|
+
method?: HttpMutationMethod;
|
|
95
103
|
fileUpload?: boolean;
|
|
96
104
|
}
|
|
97
105
|
export interface SerializedSlice extends SerializedSignalOption {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const baseDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "ping" | "pingBody" | "pingParam" | "pingQuery" | "wsPing" | "pubsubPing", never, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view">;
|
|
1
|
+
export declare const baseDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "ping" | "pingBody" | "pingParam" | "pingQuery" | "wsPing" | "pubsubPing", never, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view">;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { AgentEndpoint, AgentTurn, BaseEndpoint } from "akanjs/signal";
|
|
2
2
|
export declare const dictionary: {
|
|
3
|
-
base: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view">, never>;
|
|
3
|
+
base: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view">, never>;
|
|
4
4
|
agentTurn: import("./locale.d.ts").DictModule<import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc`, never>;
|
|
5
5
|
agent: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, "agent.error.llmUnavailable" | "agent.error.deepseekRequestFailed">;
|
|
6
6
|
};
|
|
7
|
-
export declare const Err: import("./trans.d.ts").ErrConstructor<"agent.error.llmUnavailable" | "agent.error.deepseekRequestFailed">, translate: (lang: "en" | "ko" | "zhChs" | "zhCht" | "ja", key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, data?: import("./trans.d.ts").TranslationData) => string, msg: {
|
|
8
|
-
info: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
9
|
-
success: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
10
|
-
error: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
11
|
-
warning: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
12
|
-
loading: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
13
|
-
}, getDictionary: (lang: "en" | "ko" | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "agent.error.llmUnavailable" | "agent.error.deepseekRequestFailed";
|
|
7
|
+
export declare const Err: import("./trans.d.ts").ErrConstructor<"agent.error.llmUnavailable" | "agent.error.deepseekRequestFailed">, translate: (lang: "en" | "ko" | "zhChs" | "zhCht" | "ja", key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, data?: import("./trans.d.ts").TranslationData) => string, msg: {
|
|
8
|
+
info: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
9
|
+
success: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
10
|
+
error: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
11
|
+
warning: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
12
|
+
loading: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
13
|
+
}, getDictionary: (lang: "en" | "ko" | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "error" | "remove" | "save" | "refresh" | "password" | "stop" | "send" | "skip" | "agent" | "ok" | "connecting" | "new" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "success" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "unauthorized" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentAnswer" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "approve" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "edit" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "agent.error.llmUnavailable" | "agent.error.deepseekRequestFailed";
|