akanjs 3.0.0-alpha.15 → 3.0.0-alpha.17

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.
Files changed (205) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/base/symbols.ts +1 -1
  4. package/common/index.ts +0 -1
  5. package/common/mcpExposure.ts +10 -17
  6. package/constant/index.ts +1 -0
  7. package/constant/labelOf.ts +17 -0
  8. package/dictionary/agent.dictionary.ts +31 -0
  9. package/dictionary/agentTurn.dictionary.ts +29 -0
  10. package/dictionary/base.dictionary.ts +8 -0
  11. package/dictionary/dictInfo.ts +3 -83
  12. package/dictionary/dictionary.ts +9 -3
  13. package/dictionary/locale.ts +2 -16
  14. package/fetch/agentTurn.ts +19 -0
  15. package/fetch/index.ts +1 -0
  16. package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
  17. package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
  18. package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
  19. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
  20. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
  21. package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
  22. package/package.json +10 -8
  23. package/server/akanApp.ts +13 -34
  24. package/server/akanOption.ts +56 -2
  25. package/server/akanServer.ts +27 -11
  26. package/server/animatedImage.ts +83 -0
  27. package/server/di/diLifecycle.ts +30 -2
  28. package/server/di/predefinedAdaptor.ts +6 -0
  29. package/server/imageOptimizer.ts +33 -46
  30. package/server/mcp/McpRouter.ts +11 -24
  31. package/service/agent.service.ts +14 -0
  32. package/service/base.service.ts +2 -1
  33. package/service/index.ts +1 -0
  34. package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
  35. package/service/predefinedAdaptor/index.ts +2 -0
  36. package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
  37. package/service/predefinedAdaptor/role.adaptor.ts +2 -0
  38. package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
  39. package/signal/agent.signal.ts +42 -0
  40. package/signal/agentTurn.ts +8 -0
  41. package/signal/agentTurnStream.ts +48 -0
  42. package/signal/base.signal.ts +2 -1
  43. package/signal/guard.ts +5 -3
  44. package/signal/guards.ts +49 -0
  45. package/signal/index.ts +3 -0
  46. package/signal/mcp/McpDocument.ts +22 -58
  47. package/signal/serializer/fetch.serializer.ts +0 -3
  48. package/signal/slice.ts +11 -24
  49. package/signal/types.ts +0 -32
  50. package/store/actionTag.ts +5 -0
  51. package/store/agent/AgentBridge.ts +70 -28
  52. package/store/agent/AgentContext.ts +74 -0
  53. package/store/agent/AgentPrompts.ts +82 -0
  54. package/store/agent/AgentVisibility.ts +68 -0
  55. package/store/agent/ScreenReader.ts +189 -0
  56. package/store/agent/StoreCatalogue.ts +34 -13
  57. package/store/agent/StoreSurfaceSource.ts +118 -0
  58. package/store/agent/index.ts +6 -0
  59. package/store/agent/storeSurface.ts +28 -0
  60. package/store/agentic/StToolBuilder.ts +199 -0
  61. package/store/agentic/attachAgentic.ts +22 -0
  62. package/store/agentic/index.ts +5 -0
  63. package/store/agentic/readableValue.ts +17 -0
  64. package/store/agentic/useStExpose.ts +18 -0
  65. package/store/agentic/useStState.ts +35 -0
  66. package/store/baseSt.ts +7 -0
  67. package/store/index.ts +1 -0
  68. package/store/rootStore.ts +2 -1
  69. package/store/store.ts +16 -3
  70. package/store/storeInstance.ts +112 -7
  71. package/store/storeRegistry.ts +7 -2
  72. package/store/types.ts +11 -0
  73. package/store/withSelector.ts +5 -4
  74. package/test/registerDom.ts +4 -0
  75. package/types/base/symbols.d.ts +1 -1
  76. package/types/common/index.d.ts +1 -1
  77. package/types/common/mcpExposure.d.ts +3 -12
  78. package/types/constant/index.d.ts +1 -0
  79. package/types/constant/labelOf.d.ts +6 -0
  80. package/types/dictionary/agent.dictionary.d.ts +1 -0
  81. package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
  82. package/types/dictionary/base.dictionary.d.ts +1 -1
  83. package/types/dictionary/dictInfo.d.ts +15 -46
  84. package/types/dictionary/dictionary.d.ts +11 -9
  85. package/types/dictionary/locale.d.ts +1 -9
  86. package/types/fetch/agentTurn.d.ts +593 -0
  87. package/types/fetch/index.d.ts +1 -0
  88. package/types/server/akanApp.d.ts +0 -6
  89. package/types/server/akanOption.d.ts +30 -2
  90. package/types/server/akanServer.d.ts +4 -4
  91. package/types/server/animatedImage.d.ts +7 -0
  92. package/types/server/di/predefinedAdaptor.d.ts +4 -1
  93. package/types/server/mcp/McpRouter.d.ts +9 -17
  94. package/types/service/agent.service.d.ts +12 -0
  95. package/types/service/base.service.d.ts +4 -0
  96. package/types/service/index.d.ts +1 -0
  97. package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
  98. package/types/service/predefinedAdaptor/index.d.ts +2 -0
  99. package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
  100. package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
  101. package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
  102. package/types/signal/agent.signal.d.ts +29 -0
  103. package/types/signal/agentTurn.d.ts +9 -0
  104. package/types/signal/agentTurnStream.d.ts +16 -0
  105. package/types/signal/base.signal.d.ts +1 -1
  106. package/types/signal/guard.d.ts +4 -3
  107. package/types/signal/guards.d.ts +19 -0
  108. package/types/signal/index.d.ts +3 -0
  109. package/types/signal/mcp/McpDocument.d.ts +7 -18
  110. package/types/signal/slice.d.ts +9 -11
  111. package/types/signal/types.d.ts +0 -30
  112. package/types/store/actionTag.d.ts +4 -0
  113. package/types/store/agent/AgentBridge.d.ts +13 -6
  114. package/types/store/agent/AgentContext.d.ts +16 -0
  115. package/types/store/agent/AgentPrompts.d.ts +31 -0
  116. package/types/store/agent/AgentVisibility.d.ts +21 -0
  117. package/types/store/agent/ScreenReader.d.ts +11 -0
  118. package/types/store/agent/StoreCatalogue.d.ts +5 -0
  119. package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
  120. package/types/store/agent/index.d.ts +6 -0
  121. package/types/store/agent/storeSurface.d.ts +14 -0
  122. package/types/store/agentic/StToolBuilder.d.ts +41 -0
  123. package/types/store/agentic/attachAgentic.d.ts +14 -0
  124. package/types/store/agentic/index.d.ts +5 -0
  125. package/types/store/agentic/readableValue.d.ts +3 -0
  126. package/types/store/agentic/useStExpose.d.ts +8 -0
  127. package/types/store/agentic/useStState.d.ts +12 -0
  128. package/types/store/agentic.d.ts +1 -0
  129. package/types/store/baseSt.d.ts +28 -21
  130. package/types/store/index.d.ts +1 -0
  131. package/types/store/rootStore.d.ts +2 -1
  132. package/types/store/store.d.ts +4 -2
  133. package/types/store/storeInstance.d.ts +19 -3
  134. package/types/store/storeRegistry.d.ts +2 -0
  135. package/types/store/types.d.ts +11 -0
  136. package/types/store/withSelector.d.ts +5 -4
  137. package/types/test/registerDom.d.ts +1 -0
  138. package/types/ui/Agent/Approval.d.ts +7 -0
  139. package/types/ui/Agent/Bubble.d.ts +13 -0
  140. package/types/ui/Agent/Chat.d.ts +24 -0
  141. package/types/ui/Agent/Context.d.ts +9 -0
  142. package/types/ui/Agent/Dock.d.ts +1 -1
  143. package/types/ui/Agent/Guide.d.ts +9 -0
  144. package/types/ui/Agent/StateKey.d.ts +2 -1
  145. package/types/ui/Agent/Zone.d.ts +23 -0
  146. package/types/ui/Agent/fetchRunner.d.ts +12 -0
  147. package/types/ui/Agent/index.d.ts +6 -0
  148. package/types/ui/Agent/index_.d.ts +1 -0
  149. package/types/ui/Agent/sessionHistory.d.ts +12 -0
  150. package/types/ui/Signal/RestApi.d.ts +2 -3
  151. package/types/ui/UiOverride/context.d.ts +2 -0
  152. package/types/ui/recipe/badgeRecipe.d.ts +2 -2
  153. package/types/ui/recipe/buttonRecipe.d.ts +2 -2
  154. package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
  155. package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
  156. package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
  157. package/types/vendor/use-agentic/Agentic.d.ts +21 -0
  158. package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
  159. package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
  160. package/types/vendor/use-agentic/index.d.ts +13 -0
  161. package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
  162. package/types/vendor/use-agentic/types.d.ts +133 -0
  163. package/types/vendor/use-agentic/useAgent.d.ts +4 -0
  164. package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
  165. package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
  166. package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
  167. package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
  168. package/types/vendor/use-agentic.d.ts +1 -0
  169. package/types/webkit/index.d.ts +2 -0
  170. package/types/webkit/useScreenScope.d.ts +18 -0
  171. package/ui/Agent/Approval.tsx +29 -0
  172. package/ui/Agent/Bubble.tsx +74 -0
  173. package/ui/Agent/Chat.tsx +225 -0
  174. package/ui/Agent/Context.tsx +38 -0
  175. package/ui/Agent/Dock.tsx +15 -4
  176. package/ui/Agent/Guide.tsx +16 -0
  177. package/ui/Agent/StateKey.tsx +3 -1
  178. package/ui/Agent/Zone.tsx +48 -0
  179. package/ui/Agent/fetchRunner.ts +30 -0
  180. package/ui/Agent/index.ts +6 -1
  181. package/ui/Agent/index_.tsx +4 -0
  182. package/ui/Agent/sessionHistory.ts +33 -0
  183. package/ui/Load/Units.tsx +11 -2
  184. package/ui/Load/View.tsx +7 -2
  185. package/ui/Signal/RestApi.tsx +24 -37
  186. package/ui/System/ThemeToggle.tsx +55 -33
  187. package/ui/UiOverride/context.ts +2 -0
  188. package/vendor/use-agentic/AgentProvider.tsx +39 -0
  189. package/vendor/use-agentic/AgentScope.tsx +20 -0
  190. package/vendor/use-agentic/AgentSession.ts +292 -0
  191. package/vendor/use-agentic/Agentic.tsx +44 -0
  192. package/vendor/use-agentic/AgenticSurface.ts +294 -0
  193. package/vendor/use-agentic/WIRE.md +57 -0
  194. package/vendor/use-agentic/httpRunner.ts +115 -0
  195. package/vendor/use-agentic/index.ts +14 -0
  196. package/vendor/use-agentic/surfaceContext.ts +9 -0
  197. package/vendor/use-agentic/types.ts +144 -0
  198. package/vendor/use-agentic/useAgent.ts +17 -0
  199. package/vendor/use-agentic/useAgentGuide.ts +16 -0
  200. package/vendor/use-agentic/useAgentResource.ts +30 -0
  201. package/vendor/use-agentic/useAgentState.ts +61 -0
  202. package/vendor/use-agentic/useAgentTool.ts +55 -0
  203. package/webkit/index.ts +2 -0
  204. package/webkit/lazy.tsx +5 -1
  205. package/webkit/useScreenScope.tsx +49 -0
package/README.ko.md CHANGED
@@ -26,7 +26,7 @@ generated reference가 같은 의도에서 이어집니다.
26
26
 
27
27
  ## 요구사항
28
28
 
29
- - [Bun](https://bun.sh) `>=1.3.13`
29
+ - [Bun](https://bun.sh) `>=1.4.0`
30
30
  - TypeScript 중심의 애플리케이션 코드
31
31
  - React 기반 UI surface
32
32
 
package/README.md CHANGED
@@ -25,7 +25,7 @@ server, app packaging, deployment artifacts, and generated references.
25
25
 
26
26
  ## Requirements
27
27
 
28
- - [Bun](https://bun.sh) `>=1.3.13`
28
+ - [Bun](https://bun.sh) `>=1.4.0`
29
29
  - TypeScript-first application code
30
30
  - React-based UI surfaces
31
31
 
package/base/symbols.ts CHANGED
@@ -13,7 +13,7 @@ export const STATE_META = Symbol.for("akan.state");
13
13
  export const STATE_INIT_META = Symbol.for("akan.state.init");
14
14
  export const STATE_DERIVED_META = Symbol.for("akan.state.derived");
15
15
  export const ACTION_META = Symbol.for("akan.action");
16
- /** Which module declared each action, which is the dictionary node its words are written in. */
16
+ /** Which module declared each action. See `ActionOwner`. */
17
17
  export const ACTION_OWNER_META = Symbol.for("akan.action.owner");
18
18
  /** What a dispatcher does, carried on the function so a component handed one can annotate the DOM with it. */
19
19
  export const ACTION_TAG = Symbol.for("akan.action.tag");
package/common/index.ts CHANGED
@@ -30,7 +30,6 @@ export { lowerlize } from "./lowerlize";
30
30
  export {
31
31
  isMcpDescribableArg,
32
32
  type McpExposureEndpoint,
33
- type McpExposureHints,
34
33
  type McpExposureOption,
35
34
  mcpBaseVerbOf,
36
35
  mcpHintsOf,
@@ -8,7 +8,7 @@ import { capitalize } from "./capitalize";
8
8
  * eventually disagree, and an audit surface that disagrees with the catalogue is worse than none.
9
9
  *
10
10
  * Every rejection returns the sentence an author reads, at boot in the server log and in the explorer. Fail-closed
11
- * with no reason is what left a deliberate `mcp: { expose: true }` vanishing with nowhere to look but the source.
11
+ * with no reason leaves an author whose endpoint is missing from the catalogue nowhere to look but the source.
12
12
  */
13
13
  export interface McpExposureEndpoint {
14
14
  type: string;
@@ -26,20 +26,10 @@ export interface McpExposureOption {
26
26
  readOnly?: boolean;
27
27
  }
28
28
 
29
- /** The author's overrides for the hints derived below. */
30
- export interface McpExposureHints {
31
- readOnly?: boolean;
32
- destructive?: boolean;
33
- idempotent?: boolean;
34
- }
35
-
36
29
  /** `Any` publishes as the empty schema, which tells a model nothing — so it is left out rather than described. */
37
30
  export const isMcpDescribableArg = (arg: { refName: string }) => arg.refName !== "Any";
38
31
 
39
- /**
40
- * Which slice-level verb opts in each CRUD endpoint a model generates. They carry no signal option of their own,
41
- * so `mcp: { get: true }` on the slice is the only place their exposure can be written.
42
- */
32
+ /** Which CRUD verb a generated endpoint key is, or `null` when the key is not one of the five. */
43
33
  export const mcpBaseVerbOf = (refName: string, key: string) => {
44
34
  const cap = capitalize(refName);
45
35
  if (key === refName || key === `light${cap}`) return "get" as const;
@@ -54,19 +44,22 @@ export const mcpBaseVerbOf = (refName: string, key: string) => {
54
44
  * and never stand in for a guard. `openWorldHint` is always false: every endpoint reaches this app's own
55
45
  * database, not the wider internet.
56
46
  */
57
- export const mcpHintsOf = (key: string, endpoint: { type: string }, mcp: McpExposureHints = {}) => {
58
- const readOnly = mcp.readOnly ?? endpoint.type === "query";
59
- const destructive = mcp.destructive ?? (!readOnly && /^(remove|delete)/.test(key));
47
+ export const mcpHintsOf = (key: string, endpoint: { type: string }) => {
48
+ const readOnly = endpoint.type === "query";
49
+ const destructive = !readOnly && /^(remove|delete)/.test(key);
60
50
  return {
61
51
  readOnlyHint: readOnly,
62
52
  destructiveHint: destructive,
63
- idempotentHint: mcp.idempotent ?? (readOnly || /^(set|update)/.test(key)),
53
+ idempotentHint: readOnly || /^(set|update)/.test(key),
64
54
  openWorldHint: false,
65
55
  };
66
56
  };
67
57
 
68
58
  /** The sentence explaining why this endpoint is not in the catalogue, or `null` when it is. */
69
59
  export const mcpRefusalOf = (endpoint: McpExposureEndpoint, { readOnly }: McpExposureOption = {}): string | null => {
60
+
61
+ if (!endpoint.guards?.length)
62
+ return "it declares no guards, and exposure follows them — write `guards: [Public]` if anonymous access is the intent.";
70
63
  if (endpoint.type === "prompt") return mcpPromptRefusalOf(endpoint);
71
64
  if (endpoint.type === "pubsub" || endpoint.type === "message")
72
65
  return `\`${endpoint.type}\` rides the websocket, and its internal arguments read a socket an MCP request does not have.`;
@@ -76,7 +69,7 @@ export const mcpRefusalOf = (endpoint: McpExposureEndpoint, { readOnly }: McpExp
76
69
  return `a return typed \`${endpoint.returns.refName}\` cannot be described to a model.`;
77
70
  if (endpoint.fileUpload || endpoint.args.some((arg) => arg.refName === "Upload"))
78
71
  return "a file upload has no MCP representation.";
79
- if (endpoint.type === "mutation" && !endpoint.guards?.some((name) => name !== "Public"))
72
+ if (endpoint.type === "mutation" && !endpoint.guards.some((name) => name !== "Public"))
80
73
  return "a mutation needs a real guard — `[Public]` is having none, spelled out.";
81
74
  const opaque = endpoint.args.find((arg) => !isMcpDescribableArg(arg) && arg.type !== "search" && !arg.nullable);
82
75
  if (opaque)
package/constant/index.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./deserialize";
5
5
  export * from "./fieldInfo";
6
6
  export * from "./getDefault";
7
7
  export * from "./immerify";
8
+ export * from "./labelOf";
8
9
  export * from "./mask";
9
10
  export * from "./purify";
10
11
  export * from "./serialize";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The one line a human scans for, derived from what the model already declared: the `text: "title"` search role
3
+ * names exactly that field, so an agent-facing label costs no new declaration. Falls back to the conventional
4
+ * `title`/`name` keys; the id is the caller's floor.
5
+ */
6
+ export const labelOf = (model: unknown, value: unknown): string | undefined => {
7
+ if (!value || typeof value !== "object") return undefined;
8
+ const source = value as Record<string, unknown>;
9
+ const paths = (model as { text?: { title?: readonly string[] } } | null)?.text?.title;
10
+ const titlePath = paths?.find((path) => !path.includes(".") && !path.includes("["));
11
+ for (const key of [titlePath, "title", "name"]) {
12
+ if (!key) continue;
13
+ const candidate = source[key];
14
+ if (typeof candidate === "string" && candidate) return candidate;
15
+ }
16
+ return undefined;
17
+ };
@@ -0,0 +1,31 @@
1
+ import type { AgentEndpoint } from "akanjs/signal";
2
+
3
+ import { serviceDictionary } from "./dictInfo";
4
+
5
+ export const agentDictionary = serviceDictionary(["en", "ko"])
6
+ .endpoint<AgentEndpoint>((fn) => ({
7
+ runAgentTurn: fn(["Run Agent Turn", "에이전트 턴 실행"])
8
+ .desc([
9
+ "Relays one in-page agent turn to the model and returns its answer; tools execute in the caller's browser",
10
+ "인페이지 에이전트 턴 하나를 모델에 릴레이하고 응답을 돌려준다. 툴 실행은 호출자의 브라우저에서 한다",
11
+ ])
12
+ .arg((t) => ({
13
+ messages: t(["Messages", "메시지"]).desc(["The whole transcript in wire shape", "와이어 형태의 전체 대화"]),
14
+ tools: t(["Tools", "툴"]).desc(["The published tool catalogue, schemas only", "게시된 툴 카탈로그 (스키마만)"]),
15
+ context: t(["Context", "컨텍스트"]).desc([
16
+ "Screen context blocks, forwarded as data",
17
+ "화면 컨텍스트 블록 (데이터로 전달)",
18
+ ]),
19
+ instructions: t(["Instructions", "지시문"]).desc(["App-level system instructions", "앱 수준 시스템 지시문"]),
20
+ })),
21
+ }))
22
+ .error({
23
+ llmUnavailable: [
24
+ "The agent model is unavailable — no LLM adaptor answered this turn",
25
+ "에이전트 모델을 사용할 수 없습니다. 이번 턴에 응답한 LLM 어댑터가 없습니다",
26
+ ],
27
+ deepseekRequestFailed: [
28
+ "DeepSeek request failed with status {status}",
29
+ "DeepSeek 요청이 실패했습니다 (status {status})",
30
+ ],
31
+ });
@@ -0,0 +1,29 @@
1
+ import type { AgentStop, AgentTurn } from "akanjs/signal";
2
+
3
+ import { scalarDictionary } from "./dictInfo";
4
+
5
+ export const agentTurnDictionary = scalarDictionary(["en", "ko"])
6
+ .of((t) =>
7
+ t(["Agent Turn", "에이전트 턴"]).desc([
8
+ "One assistant answer of an in-page agent turn",
9
+ "인페이지 에이전트 턴의 어시스턴트 응답 하나",
10
+ ]),
11
+ )
12
+ .model<AgentTurn>((t) => ({
13
+ text: t(["Text", "텍스트"]).desc([
14
+ "What the assistant said; empty when the turn is only tool calls",
15
+ "어시스턴트가 말한 내용. 툴 호출뿐인 턴에서는 비어 있다",
16
+ ]),
17
+ toolCalls: t(["Tool Calls", "툴 호출"]).desc([
18
+ "Tool calls the client should execute, as { id, name, args }",
19
+ "클라이언트가 실행할 툴 호출 목록 ({ id, name, args })",
20
+ ]),
21
+ stop: t(["Stop", "종료 사유"]).desc([
22
+ "Why the turn ended — end, or toolUse when tool results are awaited",
23
+ "턴이 끝난 이유 — end 또는 툴 결과를 기다리는 toolUse",
24
+ ]),
25
+ }))
26
+ .enum<AgentStop>("agentStop", (t) => ({
27
+ end: t(["End", "종료"]).desc(["The final answer", "최종 응답"]),
28
+ toolUse: t(["Tool Use", "툴 사용"]).desc(["The model awaits tool results", "모델이 툴 결과를 기다린다"]),
29
+ }));
@@ -48,6 +48,14 @@ export const baseDictionary = serviceDictionary(["en", "ko"])
48
48
  ok: ["OK", "확인"],
49
49
  cancel: ["Cancel", "취소"],
50
50
  unauthorized: ["Unauthorized", "권한 없음"],
51
+ agent: ["Agent", "에이전트"],
52
+ agentIntro: ["Ask about this page or tell the agent what to do.", "이 화면에 대해 묻거나 할 일을 지시해 보세요."],
53
+ agentPlaceholder: ["Message the agent...", "에이전트에게 메시지..."],
54
+ agentClear: ["Clear conversation", "대화 비우기"],
55
+ send: ["Send", "보내기"],
56
+ stop: ["Stop", "중지"],
57
+ approve: ["Approve", "승인"],
58
+ decline: ["Decline", "거절"],
51
59
  confirmClose: ["Are you sure you want to close the modal?", "모달을 닫으시겠습니까?"],
52
60
  textTooShortError: ["More than {minlength} characters needed.", "{minlength}자 이상 필요합니다."],
53
61
  textTooLongError: ["Less than {maxlength} characters needed.", "{maxlength}자 이하로 필요합니다."],
@@ -56,17 +56,6 @@ type DictEndpointShape<Endpoint> =
56
56
  : Endpoint extends Record<string, EndpointInfo>
57
57
  ? EndpointCompactShape<Endpoint>
58
58
  : Record<never, never>;
59
- /**
60
- * The actions of a store, which is every method on it that dispatches.
61
- *
62
- * Derived from the shape rather than from a marker like `ENDPOINT_DICT_SHAPE`, because a store's custom actions
63
- * are declared on the subclass — after `store()` has already returned, so there is nothing for it to stamp. What
64
- * makes the shape readable anyway is that `st.do.<action>()` is typed `void`: an action returns nothing, so the
65
- * void-returning methods are exactly the actions and `get` / `pick` / `slice` fall out on their own.
66
- */
67
- type DictStoreShape<Store> = {
68
- [K in keyof Store as Store[K] extends (...args: never[]) => void | Promise<void> ? K & string : never]: true;
69
- };
70
59
  type DictArgNames<ArgNames> = ArgNames extends readonly string[] ? ArgNames[number] : never;
71
60
  type DictFilterQuery<Filter> = DictFilterShape<Filter>["query"];
72
61
  type DictFilterSort<Filter> = DictFilterShape<Filter>["sort"];
@@ -151,7 +140,6 @@ export class ModelDictInfo<
151
140
  BaseSignalKey extends string = never,
152
141
  SliceKey extends string = "",
153
142
  EndpointKey extends string = never,
154
- StoreKey extends string = never,
155
143
  ErrorKey extends string = never,
156
144
  EtcKey extends string = never,
157
145
  > {
@@ -257,9 +245,6 @@ export class ModelDictInfo<
257
245
  endpointDictionary: { [K in EndpointKey]: FunctionTranslation<Languages> } = {} as {
258
246
  [K in EndpointKey]: FunctionTranslation<Languages>;
259
247
  };
260
- storeDictionary: { [K in StoreKey]: FieldTranslation<Languages> } = {} as {
261
- [K in StoreKey]: FieldTranslation<Languages>;
262
- };
263
248
  errorDictionary: { [K in ErrorKey]: Languages } = {} as {
264
249
  [K in ErrorKey]: Languages;
265
250
  };
@@ -293,7 +278,6 @@ export class ModelDictInfo<
293
278
  BaseSignalKey,
294
279
  SliceKey,
295
280
  EndpointKey,
296
- StoreKey,
297
281
  ErrorKey,
298
282
  EtcKey
299
283
  >;
@@ -318,7 +302,6 @@ export class ModelDictInfo<
318
302
  BaseSignalKey,
319
303
  SliceKey,
320
304
  EndpointKey,
321
- StoreKey,
322
305
  ErrorKey,
323
306
  EtcKey
324
307
  >;
@@ -344,7 +327,6 @@ export class ModelDictInfo<
344
327
  BaseSignalKey,
345
328
  SliceKey,
346
329
  EndpointKey,
347
- StoreKey,
348
330
  ErrorKey,
349
331
  EtcKey
350
332
  >;
@@ -369,7 +351,6 @@ export class ModelDictInfo<
369
351
  BaseSignalKey,
370
352
  SliceKey,
371
353
  EndpointKey,
372
- StoreKey,
373
354
  ErrorKey,
374
355
  EtcKey
375
356
  >;
@@ -394,7 +375,6 @@ export class ModelDictInfo<
394
375
  BaseSignalKey,
395
376
  SliceKey,
396
377
  EndpointKey,
397
- StoreKey,
398
378
  ErrorKey,
399
379
  EtcKey
400
380
  >;
@@ -420,7 +400,6 @@ export class ModelDictInfo<
420
400
  BaseSignalKey,
421
401
  keyof DictSliceShape<Slice> & string,
422
402
  EndpointKey,
423
- StoreKey,
424
403
  ErrorKey,
425
404
  EtcKey
426
405
  >;
@@ -446,41 +425,6 @@ export class ModelDictInfo<
446
425
  BaseSignalKey,
447
426
  SliceKey,
448
427
  keyof DictEndpointShape<Endpoint> & string,
449
- StoreKey,
450
- ErrorKey,
451
- EtcKey
452
- >;
453
- }
454
- /**
455
- * What a store's custom actions are called, in the words a person would use.
456
- *
457
- * Optional, and the only stage that is: an action whose name matches the endpoint it wraps already reads as
458
- * that endpoint's `.desc()`, which is most of them — the house naming rule (`st.do.X` reads the same as
459
- * `fetch.X`) is what makes that true. This stage is for the rest, where inheriting the endpoint's words would
460
- * be actively wrong: nine `getSummaryListIn*` actions that all call one endpoint, or `logout` over
461
- * `signoutUser`, where the store name is the verb a user would say and the endpoint name is the verb the API
462
- * has. `akan quality scan` names those and no others.
463
- *
464
- * Labels only, no `.arg()`. Parameter names are not in a class's type the way an endpoint builder's are, and an
465
- * action mostly takes none anyway — its data comes from the form state the user already filled in.
466
- */
467
- store<Store>(
468
- translate: (t: (trans: Languages) => FieldTranslation<Languages>) => Partial<{
469
- [K in keyof DictStoreShape<Store>]: FieldTranslation<Languages>;
470
- }>,
471
- ) {
472
- Object.assign(this.storeDictionary, translate(FieldTranslation.translate));
473
- return this as unknown as ModelDictInfo<
474
- Languages,
475
- ModelKey,
476
- InsightKey,
477
- QueryKey,
478
- SortKey,
479
- EnumKey,
480
- BaseSignalKey,
481
- SliceKey,
482
- EndpointKey,
483
- StoreKey | (keyof DictStoreShape<Store> & string),
484
428
  ErrorKey,
485
429
  EtcKey
486
430
  >;
@@ -497,7 +441,6 @@ export class ModelDictInfo<
497
441
  BaseSignalKey,
498
442
  SliceKey,
499
443
  EndpointKey,
500
- StoreKey,
501
444
  ErrorKey | (keyof ErrorDict & string),
502
445
  EtcKey
503
446
  >;
@@ -514,7 +457,6 @@ export class ModelDictInfo<
514
457
  BaseSignalKey,
515
458
  SliceKey,
516
459
  EndpointKey,
517
- StoreKey,
518
460
  ErrorKey,
519
461
  EtcKey | (keyof EtcDict & string)
520
462
  >;
@@ -531,7 +473,6 @@ export class ModelDictInfo<
531
473
  GetBaseSignalKey<RefName>,
532
474
  SliceKey,
533
475
  EndpointKey,
534
- StoreKey,
535
476
  ErrorKey,
536
477
  EtcKey
537
478
  >;
@@ -555,7 +496,6 @@ export class ModelDictInfo<
555
496
  this.#registerBaseSignalToRoot(refName, rootDict);
556
497
  this.#registerSliceToRoot(refName, rootDict);
557
498
  this.#registerEndpointToRoot(refName, rootDict);
558
- this.#registerStoreToRoot(refName, rootDict);
559
499
  this.#registerErrorToRoot(refName, rootDict);
560
500
  this.#registerModelToRoot(refName, rootDict);
561
501
  this.#registerEtcToRoot(refName, rootDict);
@@ -838,22 +778,6 @@ export class ModelDictInfo<
838
778
  });
839
779
  }
840
780
  /** Under its own `store` node rather than beside `signal`, because the two hold the same key by design. */
841
- #registerStoreToRoot(refName: string, rootDict: RootDictionary) {
842
- this.languages.forEach((language) => {
843
- ensureNode(getRootModelNode(rootDict, language, refName), "store");
844
- });
845
- Object.entries(this.storeDictionary as { [key: string]: FieldTranslation<Languages> }).forEach(([key, value]) => {
846
- value.trans.forEach((t, idx) => {
847
- ensureNode(ensureNode(getTranslatedRootModelNode(rootDict, this.languages, idx, refName), "store"), key).t = t;
848
- });
849
- value.descTrans?.forEach((t, idx) => {
850
- ensureNode(
851
- ensureNode(ensureNode(getTranslatedRootModelNode(rootDict, this.languages, idx, refName), "store"), key),
852
- "desc",
853
- ).t = t;
854
- });
855
- });
856
- }
857
781
  #registerErrorToRoot(refName: string, rootDict: RootDictionary) {
858
782
  this.languages.forEach((language) => {
859
783
  ensureNode(getRootModelNode(rootDict, language, refName), "error");
@@ -883,12 +807,11 @@ export class ModelDictInfo<
883
807
  /**
884
808
  * Every parameter of `ModelDictInfo` is listed here positionally, so a parameter added to the class has to be
885
809
  * added to all three lists below in the same slot. Omitting one does not fail to compile — inference silently
886
- * shifts, so the last parameter falls off the end and becomes its default `never`: adding `StoreKey` before
887
- * `ErrorKey` once cost an extending app the whole of the lib's `EtcKey` (`.translate()`) union, which reads at
888
- * the call site as `l("<model>.<key>")` no longer existing.
810
+ * shifts, so the last parameter falls off the end and becomes its default `never`, which reads at the call site
811
+ * as `l("<model>.<key>")` no longer existing.
889
812
  */
890
813
 
891
- type AnyModelDictInfo = ModelDictInfo<any, any, any, any, any, any, any, any, any, any, any, any>;
814
+ type AnyModelDictInfo = ModelDictInfo<any, any, any, any, any, any, any, any, any, any, any>;
892
815
 
893
816
  type MergeTwoModelDicts<ModelDict1, ModelDict2> =
894
817
  ModelDict1 extends ModelDictInfo<
@@ -901,7 +824,6 @@ type MergeTwoModelDicts<ModelDict1, ModelDict2> =
901
824
  infer BaseSignalKey1,
902
825
  infer SliceKey1,
903
826
  infer EndpointKey1,
904
- infer StoreKey1,
905
827
  infer ErrorKey1,
906
828
  infer EtcKey1
907
829
  >
@@ -915,7 +837,6 @@ type MergeTwoModelDicts<ModelDict1, ModelDict2> =
915
837
  infer BaseSignalKey2,
916
838
  infer SliceKey2,
917
839
  infer EndpointKey2,
918
- infer StoreKey2,
919
840
  infer ErrorKey2,
920
841
  infer EtcKey2
921
842
  >
@@ -929,7 +850,6 @@ type MergeTwoModelDicts<ModelDict1, ModelDict2> =
929
850
  BaseSignalKey1 | BaseSignalKey2,
930
851
  SliceKey1 | SliceKey2,
931
852
  EndpointKey1 | EndpointKey2,
932
- StoreKey1 | StoreKey2,
933
853
  ErrorKey1 | ErrorKey2,
934
854
  EtcKey1 | EtcKey2
935
855
  >
@@ -1,10 +1,16 @@
1
- import type { BaseEndpoint } from "akanjs/signal";
1
+ import type { AgentEndpoint, AgentTurn, BaseEndpoint } from "akanjs/signal";
2
2
 
3
+ import { agentDictionary } from "./agent.dictionary";
4
+ import { agentTurnDictionary } from "./agentTurn.dictionary";
3
5
  import { baseDictionary } from "./base.dictionary";
4
- import { registerServiceTrans } from "./locale";
6
+ import { registerScalarTrans, registerServiceTrans } from "./locale";
5
7
  import { makeTrans } from "./trans";
6
8
 
7
- export const dictionary = { base: registerServiceTrans<"base", BaseEndpoint, typeof baseDictionary>(baseDictionary) };
9
+ export const dictionary = {
10
+ base: registerServiceTrans<"base", BaseEndpoint, typeof baseDictionary>(baseDictionary),
11
+ agentTurn: registerScalarTrans<"agentTurn", AgentTurn, typeof agentTurnDictionary>(agentTurnDictionary),
12
+ agent: registerServiceTrans<"agent", AgentEndpoint, typeof agentDictionary>(agentDictionary),
13
+ };
8
14
 
9
15
  export const { Err, translate, msg, getDictionary, getAllDictionary, __Dict_Key__, __Error_Key__ } =
10
16
  makeTrans(dictionary);
@@ -168,14 +168,6 @@ export type ModelTrans<
168
168
  }>;
169
169
  error: { [K in ErrorKey]: Trans };
170
170
  } & { [K in EtcKey]: Trans };
171
- /**
172
- * Store action labels, keyed off the resolved `.store()` keys rather than off the store class.
173
- *
174
- * The endpoint half needs the class because it reads argument names out of it. A store entry is a label and a
175
- * description with no arguments to name, so the keys the stage already resolved are the whole of it — which is
176
- * also why a generated `dict.ts` passes no store type at all.
177
- */
178
- export type StoreTranslatorKey<T extends string, StoreKey extends string> = `${T}.store.${StoreKey}${"" | ".desc"}`;
179
171
  export type ModelTranslatorKey<T extends string, Model, Insight, Filter, Slice, Endpoint, EtcKey extends string> =
180
172
  | `${T}.modelName`
181
173
  | `${T}.modelDesc`
@@ -242,14 +234,11 @@ export const registerModelTrans = <
242
234
  infer _BaseSignalKey,
243
235
  infer _SliceKey,
244
236
  infer _EndpointKey,
245
- infer StoreKey,
246
237
  infer ErrorKey,
247
238
  infer EtcKey
248
239
  >
249
240
  ? DictModule<
250
- | ModelTranslatorKey<RefName, Model, Insight, Filter, Slice, Endpoint, EtcKey>
251
- | EnumTranslatorKey<EnumKey>
252
- | StoreTranslatorKey<RefName, StoreKey>,
241
+ ModelTranslatorKey<RefName, Model, Insight, Filter, Slice, Endpoint, EtcKey> | EnumTranslatorKey<EnumKey>,
253
242
  `${RefName}.error.${ErrorKey}`
254
243
  >
255
244
  : never => {
@@ -263,14 +252,11 @@ export const registerModelTrans = <
263
252
  infer _BaseSignalKey,
264
253
  infer _SliceKey,
265
254
  infer _EndpointKey,
266
- infer StoreKey,
267
255
  infer ErrorKey,
268
256
  infer EtcKey
269
257
  >
270
258
  ? DictModule<
271
- | ModelTranslatorKey<RefName, Model, Insight, Filter, Slice, Endpoint, EtcKey>
272
- | EnumTranslatorKey<EnumKey>
273
- | StoreTranslatorKey<RefName, StoreKey>,
259
+ ModelTranslatorKey<RefName, Model, Insight, Filter, Slice, Endpoint, EtcKey> | EnumTranslatorKey<EnumKey>,
274
260
  `${RefName}.error.${ErrorKey}`
275
261
  >
276
262
  : never;
@@ -0,0 +1,19 @@
1
+ import { Any, enumOf } from "akanjs/base";
2
+ import { ConstantRegistry, via } from "akanjs/constant";
3
+
4
+ export class AgentStop extends enumOf("agentStop", ["end", "toolUse"] as const) {}
5
+
6
+ export class AgentTurn extends via((field) => ({
7
+ text: field(String, { default: "" }), // the assistant's words; empty when the turn is only tool calls
8
+ toolCalls: field([Any]), // { id, name, args } per call — args carries the tool's own schema, not a model's
9
+ stop: field(AgentStop, { default: "end" }),
10
+ })) {
11
+ isToolUse() {
12
+ return this.stop === "toolUse";
13
+ }
14
+ }
15
+
16
+ export const agentTurnConstant = ConstantRegistry.buildScalar("agentTurn" as const, AgentTurn, {
17
+ AgentTurn,
18
+ AgentStop,
19
+ });
package/fetch/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./agentTurn";
1
2
  export * from "./client";
2
3
  export * from "./fetchType";
3
4
  export * from "./requestStorage";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akanjs",
3
- "version": "3.0.0-alpha.15",
3
+ "version": "3.0.0-alpha.17",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -180,7 +180,6 @@
180
180
  "dependencies": {
181
181
  "dayjs": "^1.11.20",
182
182
  "immer": "^11.1.8",
183
- "sharp": "^0.34.5",
184
183
  "tailwind-merge": "^3.3.1",
185
184
  "tailwind-variants": "^3.3.0"
186
185
  },
@@ -202,6 +201,7 @@
202
201
  "@capacitor/preferences": "^8.0.1",
203
202
  "@capacitor/push-notifications": "^8.1.1",
204
203
  "@capgo/capacitor-updater": "^8.46.1",
204
+ "@happy-dom/global-registrator": "^20.11.2",
205
205
  "@libsql/client": "^0.17.3",
206
206
  "@playwright/test": "^1.60.0",
207
207
  "@react-spring/web": "^10.1.0",
@@ -210,8 +210,8 @@
210
210
  "capacitor-plugin-safe-area": "^5.0.0",
211
211
  "chance": "^1.1.13",
212
212
  "cordova-plugin-purchase": "^13.16.0",
213
- "croner": "^10.0.1",
214
213
  "firebase": "^12.13.0",
214
+ "happy-dom": "^20.11.2",
215
215
  "ioredis": "^5.10.1",
216
216
  "mermaid": "^11.15.0",
217
217
  "postgres": "^3.4.9",
@@ -225,7 +225,6 @@
225
225
  "react-simple-pull-to-refresh": "^1.3.4",
226
226
  "react-spring": "^10.0.4",
227
227
  "scheduler": "^0.27.0",
228
- "sharp": "^0.34.5",
229
228
  "tailwind-scrollbar": "^4.0.2",
230
229
  "typescript": "^6.0.3"
231
230
  },
@@ -281,6 +280,9 @@
281
280
  "@capgo/capacitor-updater": {
282
281
  "optional": true
283
282
  },
283
+ "@happy-dom/global-registrator": {
284
+ "optional": true
285
+ },
284
286
  "@libsql/client": {
285
287
  "optional": true
286
288
  },
@@ -305,10 +307,10 @@
305
307
  "cordova-plugin-purchase": {
306
308
  "optional": true
307
309
  },
308
- "croner": {
310
+ "firebase": {
309
311
  "optional": true
310
312
  },
311
- "firebase": {
313
+ "happy-dom": {
312
314
  "optional": true
313
315
  },
314
316
  "ioredis": {
@@ -359,13 +361,13 @@
359
361
  },
360
362
  "devDependencies": {
361
363
  "@biomejs/biome": "2.5.8",
362
- "@types/bun": "^1.3.14"
364
+ "@types/bun": "^1.4.0"
363
365
  },
364
366
  "bun": {
365
367
  "platform": "bun"
366
368
  },
367
369
  "engines": {
368
- "bun": ">=1.3.13"
370
+ "bun": ">=1.4.0"
369
371
  },
370
372
  "main": "./index.ts"
371
373
  }