@things-factory/ai-assistant 10.1.28 β 10.1.29
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/client/components/assistant-chat.ts +51 -7
- package/client/components/assistant-mode.test.ts +20 -1
- package/client/components/assistant-mode.ts +20 -0
- package/client/components/panel-aria.test.ts +20 -0
- package/client/utils/assistant-session-controller.ts +14 -1
- package/client/utils/assistant-session-transport.ts +2 -2
- package/dist-client/components/assistant-chat.d.ts +12 -0
- package/dist-client/components/assistant-chat.js +48 -6
- package/dist-client/components/assistant-chat.js.map +1 -1
- package/dist-client/components/assistant-mode.d.ts +22 -0
- package/dist-client/components/assistant-mode.js +16 -0
- package/dist-client/components/assistant-mode.js.map +1 -1
- package/dist-client/components/assistant-mode.test.js +17 -1
- package/dist-client/components/assistant-mode.test.js.map +1 -1
- package/dist-client/components/panel-aria.test.js +18 -0
- package/dist-client/components/panel-aria.test.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/assistant-session-controller.d.ts +10 -0
- package/dist-client/utils/assistant-session-controller.js.map +1 -1
- package/dist-client/utils/assistant-session-transport.js +2 -2
- package/dist-client/utils/assistant-session-transport.js.map +1 -1
- package/dist-server/door-declaration-report.d.ts +14 -0
- package/dist-server/door-declaration-report.js +54 -0
- package/dist-server/door-declaration-report.js.map +1 -0
- package/dist-server/service/assistant-chat-resolver.js +19 -0
- package/dist-server/service/assistant-chat-resolver.js.map +1 -1
- package/dist-server/service/assistant-mode/assistant-mode-resolver.d.ts +8 -0
- package/dist-server/service/assistant-mode/assistant-mode-resolver.js +8 -0
- package/dist-server/service/assistant-mode/assistant-mode-resolver.js.map +1 -1
- package/dist-server/service/assistant-mode/resolve.d.ts +10 -0
- package/dist-server/service/assistant-mode/resolve.js +5 -0
- package/dist-server/service/assistant-mode/resolve.js.map +1 -1
- package/dist-server/service/assistant-mode/types.d.ts +21 -0
- package/dist-server/service/assistant-mode/types.js.map +1 -1
- package/dist-server/service/chat-message/carried-turns.js +14 -2
- package/dist-server/service/chat-message/carried-turns.js.map +1 -1
- package/dist-server/service/chat-message/door-access.d.ts +19 -7
- package/dist-server/service/chat-message/door-access.js +19 -11
- package/dist-server/service/chat-message/door-access.js.map +1 -1
- package/dist-server/service/chat-message/reader-gate.js +6 -4
- package/dist-server/service/chat-message/reader-gate.js.map +1 -1
- package/dist-server/service/chat-session/chat-session.d.ts +12 -0
- package/dist-server/service/chat-session/chat-session.js +12 -11
- package/dist-server/service/chat-session/chat-session.js.map +1 -1
- package/dist-server/service/chat-session/session-anchor.d.ts +10 -1
- package/dist-server/service/chat-session/session-anchor.js +12 -4
- package/dist-server/service/chat-session/session-anchor.js.map +1 -1
- package/dist-server/service/chat-session/session-inbox.d.ts +2 -0
- package/dist-server/service/chat-session/session-inbox.js.map +1 -1
- package/dist-server/service/chat-session/session-kind.d.ts +14 -0
- package/dist-server/service/chat-session/session-kind.js +30 -0
- package/dist-server/service/chat-session/session-kind.js.map +1 -0
- package/dist-server/service/chat-session/session-visibility.js +8 -1
- package/dist-server/service/chat-session/session-visibility.js.map +1 -1
- package/dist-server/service/chat-session-resolver.d.ts +2 -0
- package/dist-server/service/chat-session-resolver.js +4 -0
- package/dist-server/service/chat-session-resolver.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -0
- package/dist-server/service/index.js +2 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/testing/mode-conformance.d.ts +10 -0
- package/dist-server/service/testing/mode-conformance.js +13 -0
- package/dist-server/service/testing/mode-conformance.js.map +1 -1
- package/dist-server/tool-registry-boot-report.js +7 -0
- package/dist-server/tool-registry-boot-report.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/server/door-declaration-report.test.ts +53 -0
- package/server/door-declaration-report.ts +61 -0
- package/server/service/assistant-chat-resolver.ts +21 -0
- package/server/service/assistant-mode/assistant-mode-resolver.ts +6 -0
- package/server/service/assistant-mode/resolve.test.ts +42 -0
- package/server/service/assistant-mode/resolve.ts +9 -0
- package/server/service/assistant-mode/types.ts +18 -0
- package/server/service/chat-message/carried-turns.test.ts +13 -2
- package/server/service/chat-message/carried-turns.ts +16 -3
- package/server/service/chat-message/door-access.test.ts +72 -0
- package/server/service/chat-message/door-access.ts +43 -23
- package/server/service/chat-message/fold-history-window.test.ts +184 -0
- package/server/service/chat-message/reader-gate.ts +6 -4
- package/server/service/chat-session/chat-session.ts +15 -0
- package/server/service/chat-session/session-anchor.ts +12 -3
- package/server/service/chat-session/session-inbox.ts +2 -0
- package/server/service/chat-session/session-kind.test.ts +24 -0
- package/server/service/chat-session/session-kind.ts +32 -0
- package/server/service/chat-session/session-visibility.test.ts +16 -0
- package/server/service/chat-session/session-visibility.ts +9 -1
- package/server/service/chat-session-resolver.ts +4 -0
- package/server/service/index.ts +2 -0
- package/server/service/testing/mode-conformance.ts +15 -0
- package/server/tool-registry-boot-report.ts +6 -0
- package/translations/en.json +3 -2
- package/translations/ja.json +3 -2
- package/translations/ko.json +3 -2
- package/translations/ms.json +3 -2
- package/translations/zh.json +3 -2
|
@@ -44,6 +44,16 @@ export interface AssistantModeView {
|
|
|
44
44
|
catalogEntries: any[];
|
|
45
45
|
proposalChoices: any[];
|
|
46
46
|
placeholder?: string;
|
|
47
|
+
/** λΉ λνμ μ λͺ©κ³Ό ν μ€ β μ΄ λνκ° λ¬΄μμ νλ μ리μΈμ§. host μμ±λ³΄λ€ μμ λ€. */
|
|
48
|
+
intro?: {
|
|
49
|
+
title: string;
|
|
50
|
+
subtitle: string;
|
|
51
|
+
};
|
|
52
|
+
/** λΉ λνμ μμ β μ΄ λνμμ μ€μ λ‘ ν μ μλ λ§. host μμ±λ³΄λ€ μμ λ€. */
|
|
53
|
+
examples?: Array<{
|
|
54
|
+
label: string;
|
|
55
|
+
items: string[];
|
|
56
|
+
}>;
|
|
47
57
|
footerNotice?: string;
|
|
48
58
|
stagedNotice?: string;
|
|
49
59
|
}
|
|
@@ -107,3 +117,15 @@ export interface AssistantModeChoice {
|
|
|
107
117
|
* κ³ λ₯Ό κ²μ΄ νλλΏμ΄λ©΄ κΈ°μ΅μ λ³΄μ§ μλλ€ β κ³ λ₯Έ μ μ΄ μλ νλ©΄μ΄λ€.
|
|
108
118
|
*/
|
|
109
119
|
export declare function pickInitialMode(current: string | undefined, choices: ReadonlyArray<AssistantModeChoice>, remembered: string | undefined): string | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* λͺ©λ‘μμ κ³ λ₯Έ λνλ‘ λ°λΌκ° κ²μΈκ° β ADR-0072 κ²°μ 3.
|
|
122
|
+
*
|
|
123
|
+
* λͺ©λ‘μ ν λμμ λνλ₯Ό **λͺ¨λ** λ³΄μ¬ μ£Όκ³ , κ·Έ λμ μμλ λνκ° λ μ€ μ μλ€(A17). κ³ λ₯Έ κ²μ΄ μ§κΈ
|
|
124
|
+
* μ΄λ¦° λνμ λ€λ₯Έλ° νλ©΄μ΄ κ·Έλλ‘ μμΌλ©΄ λ¬Έμ΄ κ±°μ νκ³ (`session-kind-mismatch`), λͺ©λ‘μ λ리λλ° μ
|
|
125
|
+
* μ΄λ¦¬λ λͺ©λ‘μ΄ λλ€ β μ μΈμ μκ³ κΈΈμ΄ μλ κ·Έ λͺ¨μμ΄λ€.
|
|
126
|
+
*
|
|
127
|
+
* μΉΈμ΄ μκΈ° μ μ λ μΈμ
μλ κ°μ΄ μλ€. κ·Έλλ μ§κΈ λνλ‘ λλ€ β μλ²κ° λ€μ ν΄μ μ§κΈ λνλ‘ μ°λλ€.
|
|
128
|
+
*
|
|
129
|
+
* `undefined` λ γκ·Έλλ‘ λλ€γλ λ»μ΄λ€.
|
|
130
|
+
*/
|
|
131
|
+
export declare function followPickedConversation(pickedKind: string | undefined | null, currentKind: string | undefined): string | undefined;
|
|
@@ -77,4 +77,20 @@ export function pickInitialMode(current, choices, remembered) {
|
|
|
77
77
|
return current;
|
|
78
78
|
return choices.some(choice => choice.kind === remembered) ? remembered : current;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* λͺ©λ‘μμ κ³ λ₯Έ λνλ‘ λ°λΌκ° κ²μΈκ° β ADR-0072 κ²°μ 3.
|
|
82
|
+
*
|
|
83
|
+
* λͺ©λ‘μ ν λμμ λνλ₯Ό **λͺ¨λ** λ³΄μ¬ μ£Όκ³ , κ·Έ λμ μμλ λνκ° λ μ€ μ μλ€(A17). κ³ λ₯Έ κ²μ΄ μ§κΈ
|
|
84
|
+
* μ΄λ¦° λνμ λ€λ₯Έλ° νλ©΄μ΄ κ·Έλλ‘ μμΌλ©΄ λ¬Έμ΄ κ±°μ νκ³ (`session-kind-mismatch`), λͺ©λ‘μ λ리λλ° μ
|
|
85
|
+
* μ΄λ¦¬λ λͺ©λ‘μ΄ λλ€ β μ μΈμ μκ³ κΈΈμ΄ μλ κ·Έ λͺ¨μμ΄λ€.
|
|
86
|
+
*
|
|
87
|
+
* μΉΈμ΄ μκΈ° μ μ λ μΈμ
μλ κ°μ΄ μλ€. κ·Έλλ μ§κΈ λνλ‘ λλ€ β μλ²κ° λ€μ ν΄μ μ§κΈ λνλ‘ μ°λλ€.
|
|
88
|
+
*
|
|
89
|
+
* `undefined` λ γκ·Έλλ‘ λλ€γλ λ»μ΄λ€.
|
|
90
|
+
*/
|
|
91
|
+
export function followPickedConversation(pickedKind, currentKind) {
|
|
92
|
+
if (!pickedKind || pickedKind === currentKind)
|
|
93
|
+
return undefined;
|
|
94
|
+
return pickedKind;
|
|
95
|
+
}
|
|
80
96
|
//# sourceMappingURL=assistant-mode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-mode.js","sourceRoot":"","sources":["../../client/components/assistant-mode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assistant-mode.js","sourceRoot":"","sources":["../../client/components/assistant-mode.ts"],"names":[],"mappings":"AAyDA,6FAA6F;AAC7F,MAAM,UAAU,uBAAuB,CAAC,CAAiB,EAAE,CAAiB;IAC1E,OAAO,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,IAAI,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,IAAI,EAAE,EAAE,CAAA;AACxF,CAAC;AAoBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA+B,EAC/B,GAAkC,EAClC,QAAuC,EACvC,IAAwB;IAExB,IAAI,IAAI,EAAE,CAAC;QACT,kFAAkF;QAClF,MAAM,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;QAClE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,eAAe;YAC7B,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,EAAE;YAC7C,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,EAAE;YAC7C,eAAe,EAAE,OAAO,EAAE,eAAe,IAAI,EAAE;YAC/C,WAAW,EAAE,OAAO,EAAE,WAAW;YACjC,YAAY,EAAE,OAAO,EAAE,YAAY;YACnC,YAAY,EAAE,OAAO,EAAE,YAAY;SACpC,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,CAAuC,GAAM,EAA2B,EAAE,CACpF,GAAW,CAAC,GAAG,CAAC,IAAK,QAAgB,CAAC,GAAG,CAAC,CAAA;IAE7C,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,CAAA;IACzC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,uGAAuG;YACrG,qGAAqG;YACrG,qCAAqC,CACxC,CAAA;IACH,CAAC;IAED,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,YAAY;QACZ,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;QAC5C,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;QAC5C,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC;QAClC,eAAe,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAC9C,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC;KACnC,CAAA;AACH,CAAC;AASD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA2B,EAC3B,OAA2C,EAC3C,UAA8B;IAE9B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IACtC,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,OAAO;QAAE,OAAO,OAAO,CAAA;IACzD,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAA;AAClF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,wBAAwB,CAAC,UAAqC,EAAE,WAA+B;IAC7G,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,WAAW;QAAE,OAAO,SAAS,CAAA;IAC/D,OAAO,UAAU,CAAA;AACnB,CAAC","sourcesContent":["/**\n * A mode is what a conversation *is*: which conversation this is, and what it is about.\n *\n * Those two used to be nine. The browser declared the persona, the tool categories, the model and\n * the limits and sent them with every turn, which meant a caller holding the door's privilege\n * chose its own authority β and it meant a screen could describe a conversation one way while the\n * server answered it another. Since ADR-0061 decision 7 the app server registers the mode and the\n * browser names it:\n *\n * ```ts\n * html`<ox-assistant-chat .mode=${{ kind: 'twin.space', target: spaceId, hostContext: { spaceId } }}></ox-assistant-chat>`\n * ```\n *\n * What the panel shows β the `/` sentences, the `@` catalog, the two notices β comes from the same\n * declaration, fetched from the server already written in the person's language, so the panel and\n * the door cannot offer different conversations.\n */\nexport interface AssistantMode {\n /**\n * Which conversation this is β a `<app>.<surface>` kind the app server registered.\n */\n kind: string\n\n /**\n * What it is about: the space, the station, the model being edited.\n *\n * **With `kind`, this is the conversation's lifetime.** When either changes the chat closes what\n * is on screen and starts again β a conversation about station 3 is not a conversation about\n * station 7, and leaving the old one up means the person reads an answer about a screen they are\n * no longer looking at.\n */\n target?: string\n\n /**\n * What the host knows about the subject; travels with each request.\n *\n * **The model never sees this** β it reaches the tools as `ctx.host` and nothing else (ADR-0061\n * decision 7). Anything the model must know is answered by a read tool.\n */\n hostContext?: any\n}\n\n/** What the server said this mode offers, already in the request's locale. */\nexport interface AssistantModeView {\n kind: string\n slashTemplates: any[]\n catalogEntries: any[]\n proposalChoices: any[]\n placeholder?: string\n /** λΉ λνμ μ λͺ©κ³Ό ν μ€ β μ΄ λνκ° λ¬΄μμ νλ μ리μΈμ§. host μμ±λ³΄λ€ μμ λ€. */\n intro?: { title: string; subtitle: string }\n /** λΉ λνμ μμ β μ΄ λνμμ μ€μ λ‘ ν μ μλ λ§. host μμ±λ³΄λ€ μμ λ€. */\n examples?: Array<{ label: string; items: string[] }>\n footerNotice?: string\n stagedNotice?: string\n}\n\n/** True when these two describe different conversations, so the old one should be closed. */\nexport function isDifferentConversation(a?: AssistantMode, b?: AssistantMode): boolean {\n return `${a?.kind ?? ''}|${a?.target ?? ''}` !== `${b?.kind ?? ''}|${b?.target ?? ''}`\n}\n\n/** Everything a conversation needs, after the mode, the host's own properties, the registered\n * defaults and the server's answer have been reconciled. */\nexport interface ConversationSettings {\n /** Set when a mode names this conversation; absent for a host that declares none. */\n kind?: string\n target?: string\n hostContext?: any\n chatEndpoint: 'boardAIChat' | 'assistantChat'\n catalogEntries: any[]\n slashTemplates: any[]\n /** What the empty input says. A mode's comes translated from the server. */\n placeholder?: string\n /** Sentences, not keys β a mode's come translated from the server, a host's from its own i18n. */\n footerNotice?: string\n proposalChoices: any[]\n stagedNotice?: string\n}\n\n/**\n * Reconcile the places a setting can come from.\n *\n * **A host that declares a mode gets the mode and nothing else.** What the mode does not offer is\n * not filled in from the element's own properties or from the defaults another package registered.\n * Filling it back in is how the defect this type removes returned β board-ai registers board\n * authoring's `/add-monitor`, its component `@` catalog and its \"previewed on the board\" line\n * globally, and plant's factory mode, which declares no slash list, offered them on a factory\n * screen once the board modeller had been loaded.\n *\n * A mode's offering arrives asynchronously, so until the server has answered a mode offers\n * nothing. Standing the defaults in during that gap would show the board's list for a moment on a\n * screen that does not edit boards.\n *\n * A host that declares no mode gets exactly what it got before modes existed β its own properties,\n * falling back to the registered defaults β and it must name its own door: the `boardAIChat`\n * default was removed with decision 7, because a missing door should show when a surface is\n * declared, not when a person says something.\n */\nexport function resolveConversation(\n mode: AssistantMode | undefined,\n own: Partial<ConversationSettings>,\n defaults: Partial<ConversationSettings>,\n view?: AssistantModeView\n): ConversationSettings {\n if (mode) {\n /* A view for another kind is the previous conversation's answer arriving late. */\n const offered = view && view.kind === mode.kind ? view : undefined\n return {\n kind: mode.kind,\n target: mode.target,\n hostContext: mode.hostContext,\n chatEndpoint: 'assistantChat',\n catalogEntries: offered?.catalogEntries ?? [],\n slashTemplates: offered?.slashTemplates ?? [],\n proposalChoices: offered?.proposalChoices ?? [],\n placeholder: offered?.placeholder,\n footerNotice: offered?.footerNotice,\n stagedNotice: offered?.stagedNotice\n }\n }\n\n const pick = <K extends keyof ConversationSettings>(key: K): ConversationSettings[K] =>\n (own as any)[key] ?? (defaults as any)[key]\n\n const chatEndpoint = pick('chatEndpoint')\n if (!chatEndpoint) {\n throw new Error(\n '[ox-assistant-chat] a surface with no mode must name its chatEndpoint. The `boardAIChat` default was ' +\n 'removed (ADR-0061 decision 7) β apps declare a mode and talk to `assistantChat`; the board product ' +\n 'names `boardAIChat` on the element.'\n )\n }\n\n return {\n hostContext: pick('hostContext'),\n placeholder: pick('placeholder'),\n chatEndpoint,\n catalogEntries: pick('catalogEntries') ?? [],\n slashTemplates: pick('slashTemplates') ?? [],\n footerNotice: pick('footerNotice'),\n proposalChoices: pick('proposalChoices') ?? [],\n stagedNotice: pick('stagedNotice')\n }\n}\n\n/** ν subject μμ μ€ μ μλ λν νλ β μλ²κ° μ€ λͺ©λ‘μ ν μ€. */\nexport interface AssistantModeChoice {\n kind: string\n label: string\n isDefault: boolean\n}\n\n/**\n * μ΄ νλ©΄μ μ΄ λ μ΄λ λνλ‘ μ€ κ²μΈκ° β ADR-0072 A17 β .\n *\n * ββ μ κΈ°μ΅νλ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n * 보λλ₯Ό μ΄ λλ§λ€ μ μ λνλ‘ λλμκ°λ©΄, νμ₯μ λ¬ΌμΌλ €κ³ μ¨ μ¬λμ νλ©΄μ μ΄ λλ§λ€ κ°μ μμ§μ\n * λ€μ νλ€. κΈ°μ΅μ μ΄ λΈλΌμ°μ μλ§ λ¨λλ€ β μλ²μ μΉΈμ λ§λ€μ§ μλλ€.\n *\n * ββ κΈ°μ΅μ μΈμ λ²λ¦¬λ ββββββββββββββββββββββββββββββββββββββββββββββββββββ\n * κΈ°μ΅ν μ’
λ₯κ° μ§κΈ λͺ©λ‘μ μμΌλ©΄ λ°λ₯΄μ§ μλλ€. λνκ° νλ μμ΄μ§ νμΌλ‘ λ°λμλλ° κ·Έ μ΄λ¦μΌλ‘\n * μ΄λ €κ³ νλ©΄ λνκ° μ μ΄λ¦¬κ³ , μ¬λμ μκΈ°κ° λ¬΄μμ μλͺ»νλμ§ μ κΈΈμ΄ μλ€. κ·Έλλ host κ° μ€\n * λνλ‘ λλ€.\n *\n * κ³ λ₯Ό κ²μ΄ νλλΏμ΄λ©΄ κΈ°μ΅μ λ³΄μ§ μλλ€ β κ³ λ₯Έ μ μ΄ μλ νλ©΄μ΄λ€.\n */\nexport function pickInitialMode(\n current: string | undefined,\n choices: ReadonlyArray<AssistantModeChoice>,\n remembered: string | undefined\n): string | undefined {\n if (choices.length < 2) return current\n if (!remembered || remembered === current) return current\n return choices.some(choice => choice.kind === remembered) ? remembered : current\n}\n\n/**\n * λͺ©λ‘μμ κ³ λ₯Έ λνλ‘ λ°λΌκ° κ²μΈκ° β ADR-0072 κ²°μ 3.\n *\n * λͺ©λ‘μ ν λμμ λνλ₯Ό **λͺ¨λ** λ³΄μ¬ μ£Όκ³ , κ·Έ λμ μμλ λνκ° λ μ€ μ μλ€(A17). κ³ λ₯Έ κ²μ΄ μ§κΈ\n * μ΄λ¦° λνμ λ€λ₯Έλ° νλ©΄μ΄ κ·Έλλ‘ μμΌλ©΄ λ¬Έμ΄ κ±°μ νκ³ (`session-kind-mismatch`), λͺ©λ‘μ λ리λλ° μ\n * μ΄λ¦¬λ λͺ©λ‘μ΄ λλ€ β μ μΈμ μκ³ κΈΈμ΄ μλ κ·Έ λͺ¨μμ΄λ€.\n *\n * μΉΈμ΄ μκΈ° μ μ λ μΈμ
μλ κ°μ΄ μλ€. κ·Έλλ μ§κΈ λνλ‘ λλ€ β μλ²κ° λ€μ ν΄μ μ§κΈ λνλ‘ μ°λλ€.\n *\n * `undefined` λ γκ·Έλλ‘ λλ€γλ λ»μ΄λ€.\n */\nexport function followPickedConversation(pickedKind: string | undefined | null, currentKind: string | undefined): string | undefined {\n if (!pickedKind || pickedKind === currentKind) return undefined\n return pickedKind\n}\n"]}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the slash list was a module global. A mode's wording now comes from the same declaration the
|
|
10
10
|
* door reads, so the two cannot describe different conversations.
|
|
11
11
|
*/
|
|
12
|
-
import { isDifferentConversation, resolveConversation, pickInitialMode } from './assistant-mode';
|
|
12
|
+
import { isDifferentConversation, resolveConversation, pickInitialMode, followPickedConversation } from './assistant-mode';
|
|
13
13
|
const MODE = { kind: 'twin.space', target: 'S-12', hostContext: { spaceId: 'S-12' } };
|
|
14
14
|
/** What the server said this mode offers, already in the request's locale. */
|
|
15
15
|
const MODE_VIEW = {
|
|
@@ -103,4 +103,20 @@ describe('pickInitialMode', () => {
|
|
|
103
103
|
expect(pickInitialMode('twin.board', choices, undefined)).toBe('twin.board');
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
|
+
/*
|
|
107
|
+
* ADR-0072 κ²°μ 3 β λͺ©λ‘μμ κ³ λ₯Έ λνλ‘ νλ©΄μ΄ λ°λΌκ°λ€.
|
|
108
|
+
*/
|
|
109
|
+
describe('followPickedConversation', () => {
|
|
110
|
+
it('β
λ€λ₯Έ λνμ μΈμ
μ κ³ λ₯΄λ©΄ κ·Έ λνλ‘ κ°λ€ β μ λ°λΌκ°λ©΄ λ¬Έμ΄ κ±°μ νλ€', () => {
|
|
111
|
+
expect(followPickedConversation('figure.catalog', 'figure.modeller')).toBe('figure.catalog');
|
|
112
|
+
});
|
|
113
|
+
it('κ°μ λνλ©΄ κ·Έλλ‘ λλ€', () => {
|
|
114
|
+
expect(followPickedConversation('figure.modeller', 'figure.modeller')).toBeUndefined();
|
|
115
|
+
});
|
|
116
|
+
it('β
μΉΈμ΄ μκΈ° μ μΈμ
μ μ§κΈ λνλ‘ λλ€ β μλ²κ° λ€μ ν΄μ μ°λλ€', () => {
|
|
117
|
+
expect(followPickedConversation(undefined, 'figure.modeller')).toBeUndefined();
|
|
118
|
+
expect(followPickedConversation(null, 'figure.modeller')).toBeUndefined();
|
|
119
|
+
expect(followPickedConversation('', 'figure.modeller')).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
106
122
|
//# sourceMappingURL=assistant-mode.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-mode.test.js","sourceRoot":"","sources":["../../client/components/assistant-mode.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * A mode is one value, and the point of it is that the parts of a conversation cannot disagree\n * with each other. Since ADR-0061 decision 7 the parts live on the server: the browser names the\n * conversation (`kind`) and its subject (`target`), and the persona, the tool categories, the\n * model and the limits are the app server's.\n *\n * The defect this still guards against shipped: a screen whose prompt said \"you do not edit boards\n * here\" offered `/add-monitor` in the same panel, because the prompt was an element property and\n * the slash list was a module global. A mode's wording now comes from the same declaration the\n * door reads, so the two cannot describe different conversations.\n */\nimport { isDifferentConversation, resolveConversation, type AssistantMode, pickInitialMode } from './assistant-mode'\n\nconst MODE: AssistantMode = { kind: 'twin.space', target: 'S-12', hostContext: { spaceId: 'S-12' } }\n\n/** What the server said this mode offers, already in the request's locale. */\nconst MODE_VIEW = {\n kind: 'twin.space',\n slashTemplates: [{ name: 'status', description: 'summarize', template: 'μ΄ κ³΅κ°μ μ§κΈ μνλ₯Ό μμ½ν΄μ€' }],\n catalogEntries: [],\n proposalChoices: [],\n footerNotice: undefined,\n stagedNotice: undefined\n}\n\n/** The board product, which declares no mode and names its own door. */\nconst HOST_PROPERTIES = {\n hostContext: { boardId: 'B-1' },\n chatEndpoint: 'boardAIChat' as const\n}\n\nconst GLOBAL_DEFAULTS = {\n catalogEntries: [{ type: 'rect' }],\n slashTemplates: [{ name: 'add-monitor', template: 'λͺ¨λν°λ₯Ό μΆκ°ν΄μ€' }],\n footerNotice: 'previewed on the board'\n}\n\ndescribe('a mode names the conversation; the server says what it offers', () => {\n test('β
the subject travels, and the door is the neutral one', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, MODE_VIEW)\n\n expect(c.kind).toBe('twin.space')\n expect(c.target).toBe('S-12')\n expect(c.hostContext).toEqual({ spaceId: 'S-12' })\n expect(c.chatEndpoint).toBe('assistantChat')\n })\n\n test('β
what the mode offers comes from the server, not from what another package registered', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, MODE_VIEW)\n\n expect(c.slashTemplates).toEqual(MODE_VIEW.slashTemplates)\n expect(JSON.stringify(c.slashTemplates)).not.toContain('add-monitor')\n expect(c.catalogEntries).toEqual([])\n expect(c.footerNotice).toBeUndefined()\n })\n\n test('β
before the server has answered, a mode offers nothing β the defaults do not stand in', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, undefined)\n\n expect(c.slashTemplates).toEqual([])\n expect(c.catalogEntries).toEqual([])\n })\n\n test('a view for another kind is ignored β the panel is showing this conversation', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, { ...MODE_VIEW, kind: 'twin.board' })\n\n expect(c.slashTemplates).toEqual([])\n })\n})\n\ndescribe('a host with no mode', () => {\n test('gets its own properties and the registered defaults, as before modes existed', () => {\n const c = resolveConversation(undefined, HOST_PROPERTIES, GLOBAL_DEFAULTS)\n\n expect(c.hostContext).toEqual({ boardId: 'B-1' })\n expect(c.slashTemplates).toEqual(GLOBAL_DEFAULTS.slashTemplates)\n expect(c.footerNotice).toBe('previewed on the board')\n expect(c.chatEndpoint).toBe('boardAIChat')\n })\n\n test('β
must name its door β there is no default any more', () => {\n expect(() => resolveConversation(undefined, {}, {})).toThrow(/chatEndpoint/)\n })\n})\n\ndescribe('isDifferentConversation', () => {\n const station3: AssistantMode = { kind: 'plant.station', target: '3' }\n\n test('β
a different subject ends the conversation, and so does a different kind', () => {\n expect(isDifferentConversation(station3, { kind: 'plant.station', target: '7' })).toBe(true)\n expect(isDifferentConversation(station3, { kind: 'plant.factory', target: '3' })).toBe(true)\n expect(isDifferentConversation(undefined, station3)).toBe(true)\n })\n\n test('the same subject, described again, does not', () => {\n expect(isDifferentConversation(station3, { ...station3, hostContext: { reread: true } })).toBe(false)\n expect(isDifferentConversation(undefined, undefined)).toBe(false)\n })\n})\n\n/*\n * ADR-0072 A17 β β νλ©΄μ μ΄ λ μ΄λ λνλ‘ μλ.\n *\n * λμ΄λ¦¬λ κ²μ κ³ λ₯Έ λνμ΄μ§ μΈμ
μ΄ μλλ€. κ·Έλ¦¬κ³ μμ΄μ§ λνλ‘ λμ΄λ¦¬μ§ μλλ€ β κ·Έλ¬λ©΄ λνκ°\n * μ μ΄λ¦¬κ³ μ¬λμ μκΈ°κ° λ¬΄μμ μλͺ»νλμ§ μ κΈΈμ΄ μλ€.\n */\ndescribe('pickInitialMode', () => {\n const choices = [\n { kind: 'twin.board', label: 'μ΄ κ·Έλ¦Ό κ³ μΉκΈ°', isDefault: true },\n { kind: 'twin.space', label: 'μ΄ νμ₯ μ§κΈ', isDefault: false }\n ]\n\n it('β
μ§λλ²μ κ³ λ₯Έ λνλ‘ λμκ°λ€ β λ§€λ² κ°μ μμ§μ λ€μ νμ§ μλλ€', () => {\n expect(pickInitialMode('twin.board', choices, 'twin.space')).toBe('twin.space')\n })\n\n it('β
μ§κΈ λͺ©λ‘μ μλ κΈ°μ΅μ λ°λ₯΄μ§ μλλ€ β μ μ΄λ¦¬λ λνλ‘ λ€μ΄κ°λ€', () => {\n expect(pickInitialMode('twin.board', choices, 'twin.gone')).toBe('twin.board')\n })\n\n it('β
κ³ λ₯Ό κ²μ΄ νλλΏμ΄λ©΄ κΈ°μ΅μ λ³΄μ§ μλλ€ β κ³ λ₯Έ μ μ΄ μλ νλ©΄μ΄λ€', () => {\n expect(pickInitialMode('plant.station', [choices[0]], 'twin.space')).toBe('plant.station')\n })\n\n it('κΈ°μ΅μ΄ μμΌλ©΄ host κ° μ€ κ²μΌλ‘ μ λ€', () => {\n expect(pickInitialMode('twin.board', choices, undefined)).toBe('twin.board')\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-mode.test.js","sourceRoot":"","sources":["../../client/components/assistant-mode.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * A mode is one value, and the point of it is that the parts of a conversation cannot disagree\n * with each other. Since ADR-0061 decision 7 the parts live on the server: the browser names the\n * conversation (`kind`) and its subject (`target`), and the persona, the tool categories, the\n * model and the limits are the app server's.\n *\n * The defect this still guards against shipped: a screen whose prompt said \"you do not edit boards\n * here\" offered `/add-monitor` in the same panel, because the prompt was an element property and\n * the slash list was a module global. A mode's wording now comes from the same declaration the\n * door reads, so the two cannot describe different conversations.\n */\nimport { isDifferentConversation, resolveConversation, type AssistantMode, pickInitialMode, followPickedConversation } from './assistant-mode'\n\nconst MODE: AssistantMode = { kind: 'twin.space', target: 'S-12', hostContext: { spaceId: 'S-12' } }\n\n/** What the server said this mode offers, already in the request's locale. */\nconst MODE_VIEW = {\n kind: 'twin.space',\n slashTemplates: [{ name: 'status', description: 'summarize', template: 'μ΄ κ³΅κ°μ μ§κΈ μνλ₯Ό μμ½ν΄μ€' }],\n catalogEntries: [],\n proposalChoices: [],\n footerNotice: undefined,\n stagedNotice: undefined\n}\n\n/** The board product, which declares no mode and names its own door. */\nconst HOST_PROPERTIES = {\n hostContext: { boardId: 'B-1' },\n chatEndpoint: 'boardAIChat' as const\n}\n\nconst GLOBAL_DEFAULTS = {\n catalogEntries: [{ type: 'rect' }],\n slashTemplates: [{ name: 'add-monitor', template: 'λͺ¨λν°λ₯Ό μΆκ°ν΄μ€' }],\n footerNotice: 'previewed on the board'\n}\n\ndescribe('a mode names the conversation; the server says what it offers', () => {\n test('β
the subject travels, and the door is the neutral one', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, MODE_VIEW)\n\n expect(c.kind).toBe('twin.space')\n expect(c.target).toBe('S-12')\n expect(c.hostContext).toEqual({ spaceId: 'S-12' })\n expect(c.chatEndpoint).toBe('assistantChat')\n })\n\n test('β
what the mode offers comes from the server, not from what another package registered', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, MODE_VIEW)\n\n expect(c.slashTemplates).toEqual(MODE_VIEW.slashTemplates)\n expect(JSON.stringify(c.slashTemplates)).not.toContain('add-monitor')\n expect(c.catalogEntries).toEqual([])\n expect(c.footerNotice).toBeUndefined()\n })\n\n test('β
before the server has answered, a mode offers nothing β the defaults do not stand in', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, undefined)\n\n expect(c.slashTemplates).toEqual([])\n expect(c.catalogEntries).toEqual([])\n })\n\n test('a view for another kind is ignored β the panel is showing this conversation', () => {\n const c = resolveConversation(MODE, HOST_PROPERTIES, GLOBAL_DEFAULTS, { ...MODE_VIEW, kind: 'twin.board' })\n\n expect(c.slashTemplates).toEqual([])\n })\n})\n\ndescribe('a host with no mode', () => {\n test('gets its own properties and the registered defaults, as before modes existed', () => {\n const c = resolveConversation(undefined, HOST_PROPERTIES, GLOBAL_DEFAULTS)\n\n expect(c.hostContext).toEqual({ boardId: 'B-1' })\n expect(c.slashTemplates).toEqual(GLOBAL_DEFAULTS.slashTemplates)\n expect(c.footerNotice).toBe('previewed on the board')\n expect(c.chatEndpoint).toBe('boardAIChat')\n })\n\n test('β
must name its door β there is no default any more', () => {\n expect(() => resolveConversation(undefined, {}, {})).toThrow(/chatEndpoint/)\n })\n})\n\ndescribe('isDifferentConversation', () => {\n const station3: AssistantMode = { kind: 'plant.station', target: '3' }\n\n test('β
a different subject ends the conversation, and so does a different kind', () => {\n expect(isDifferentConversation(station3, { kind: 'plant.station', target: '7' })).toBe(true)\n expect(isDifferentConversation(station3, { kind: 'plant.factory', target: '3' })).toBe(true)\n expect(isDifferentConversation(undefined, station3)).toBe(true)\n })\n\n test('the same subject, described again, does not', () => {\n expect(isDifferentConversation(station3, { ...station3, hostContext: { reread: true } })).toBe(false)\n expect(isDifferentConversation(undefined, undefined)).toBe(false)\n })\n})\n\n/*\n * ADR-0072 A17 β β νλ©΄μ μ΄ λ μ΄λ λνλ‘ μλ.\n *\n * λμ΄λ¦¬λ κ²μ κ³ λ₯Έ λνμ΄μ§ μΈμ
μ΄ μλλ€. κ·Έλ¦¬κ³ μμ΄μ§ λνλ‘ λμ΄λ¦¬μ§ μλλ€ β κ·Έλ¬λ©΄ λνκ°\n * μ μ΄λ¦¬κ³ μ¬λμ μκΈ°κ° λ¬΄μμ μλͺ»νλμ§ μ κΈΈμ΄ μλ€.\n */\ndescribe('pickInitialMode', () => {\n const choices = [\n { kind: 'twin.board', label: 'μ΄ κ·Έλ¦Ό κ³ μΉκΈ°', isDefault: true },\n { kind: 'twin.space', label: 'μ΄ νμ₯ μ§κΈ', isDefault: false }\n ]\n\n it('β
μ§λλ²μ κ³ λ₯Έ λνλ‘ λμκ°λ€ β λ§€λ² κ°μ μμ§μ λ€μ νμ§ μλλ€', () => {\n expect(pickInitialMode('twin.board', choices, 'twin.space')).toBe('twin.space')\n })\n\n it('β
μ§κΈ λͺ©λ‘μ μλ κΈ°μ΅μ λ°λ₯΄μ§ μλλ€ β μ μ΄λ¦¬λ λνλ‘ λ€μ΄κ°λ€', () => {\n expect(pickInitialMode('twin.board', choices, 'twin.gone')).toBe('twin.board')\n })\n\n it('β
κ³ λ₯Ό κ²μ΄ νλλΏμ΄λ©΄ κΈ°μ΅μ λ³΄μ§ μλλ€ β κ³ λ₯Έ μ μ΄ μλ νλ©΄μ΄λ€', () => {\n expect(pickInitialMode('plant.station', [choices[0]], 'twin.space')).toBe('plant.station')\n })\n\n it('κΈ°μ΅μ΄ μμΌλ©΄ host κ° μ€ κ²μΌλ‘ μ λ€', () => {\n expect(pickInitialMode('twin.board', choices, undefined)).toBe('twin.board')\n })\n})\n\n/*\n * ADR-0072 κ²°μ 3 β λͺ©λ‘μμ κ³ λ₯Έ λνλ‘ νλ©΄μ΄ λ°λΌκ°λ€.\n */\ndescribe('followPickedConversation', () => {\n it('β
λ€λ₯Έ λνμ μΈμ
μ κ³ λ₯΄λ©΄ κ·Έ λνλ‘ κ°λ€ β μ λ°λΌκ°λ©΄ λ¬Έμ΄ κ±°μ νλ€', () => {\n expect(followPickedConversation('figure.catalog', 'figure.modeller')).toBe('figure.catalog')\n })\n\n it('κ°μ λνλ©΄ κ·Έλλ‘ λλ€', () => {\n expect(followPickedConversation('figure.modeller', 'figure.modeller')).toBeUndefined()\n })\n\n it('β
μΉΈμ΄ μκΈ° μ μΈμ
μ μ§κΈ λνλ‘ λλ€ β μλ²κ° λ€μ ν΄μ μ°λλ€', () => {\n expect(followPickedConversation(undefined, 'figure.modeller')).toBeUndefined()\n expect(followPickedConversation(null, 'figure.modeller')).toBeUndefined()\n expect(followPickedConversation('', 'figure.modeller')).toBeUndefined()\n })\n})\n"]}
|
|
@@ -28,4 +28,22 @@ describe('the panel does not raise a second tab axis', () => {
|
|
|
28
28
|
expect(bare('assistant-session-toolbar.ts')).toContain('role="tablist"');
|
|
29
29
|
});
|
|
30
30
|
});
|
|
31
|
+
/*
|
|
32
|
+
* 첨λΆλ **λλ κ²λ§** κΆνλ€ β ADR-0071 보ν¬(2026-09-18).
|
|
33
|
+
*
|
|
34
|
+
* `.json` Β· `.txt` Β· `.csv` λ λ°κ³ μμλλ°, κ·Έ νμΌλ€μ μ€λ €λ§ κ°κ³ λͺ¨λΈμ λΆλ μ½λκ° μμλ€. μ¬λμ΄
|
|
35
|
+
* CSV λ₯Ό λΆμ΄κ³ λ¬ΌμΌλ©΄ νμΌ μΉ©μ΄ λ¨κ³ λ΅λ μλ€ β κ·Έ λ΅μ νμΌμ λ³Έ μ μ΄ μκ³ μ€λ₯λ μ λ¬λ€.
|
|
36
|
+
* μ΄λ―Έμ§λ `hostContext.image` λ‘ μ¬λ ν΄μ λΆλ κΈΈμ΄ μλ€.
|
|
37
|
+
*/
|
|
38
|
+
describe('the attach control offers only what has a path', () => {
|
|
39
|
+
it('β
μ΄λ―Έμ§λ§ λ°λλ€ β μ½νμ§ μλ κ²μ νλ©΄μ΄ κΆνμ§ μλλ€', () => {
|
|
40
|
+
/*
|
|
41
|
+
* μ¬κΈ°μλ μ£Όμμ μ λ²κΈ΄λ€. `image/*` μμ²΄κ° `/*` λ₯Ό νκ³ μμ΄μ, μ£Όμ λ²κΈ°κ°κ° κ·Έ μ리λ₯Ό μ£Όμμ
|
|
42
|
+
* μμμΌλ‘ μ½κ³ λ€μ `*` + `/` κΉμ§ μ§μ λ²λ¦°λ€ β κ°μ΄ μ¬λΌμ§κ³ μνμ γμλ€γκ³ λ΅νλ€.
|
|
43
|
+
* μ΄ κ°μ μ£Όμμ μ ν μΌμ΄ μμΌλ―λ‘ μλ¬Έμμ κ·Έλλ‘ μ½λλ€.
|
|
44
|
+
*/
|
|
45
|
+
const accept = readFileSync(join(__dirname, 'assistant-chat.ts'), 'utf-8').match(/accept="([^"]*)"/);
|
|
46
|
+
expect(accept?.[1]).toBe('image/*');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
31
49
|
//# sourceMappingURL=panel-aria.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel-aria.test.js","sourceRoot":"","sources":["../../client/components/panel-aria.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC;SAChD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;AACjC,CAAC;AAED,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IAC1D,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAE7F,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["/*\n * ν¨λ μμ κ³ λ₯΄λ μΆμ΄ λμΌ λ β λ λ€ γνγμ΄λΌκ³ λ§νμ§ μλλ€.\n *\n * ββ μ μ΄ μνμ΄ μλ ββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n * λν κ³ λ₯΄κ°λ₯Ό μΉ© μ€λ‘ λ§λ€λ©΄μ `role=\"tablist\"` λ₯Ό λ¬μλ€. λ°λ‘ μλκ° μΈμ
νμ΄κ³ κ·Έμͺ½λ tablist\n * λΌμ, νλ©΄ λλ
κΈ°λ‘ λ€μΌλ©΄ γν λͺ©λ‘, λνγ λ€μμ γν λͺ©λ‘, Conversation historyγ κ° μ΄μ΄μ‘λ€.\n * κ³ λ₯΄λ μΆμ΄ λμΈλ° λ λ€ κ°μ μ΄λ¦μΌλ‘ λΆλ¦°λ€. λμΌλ‘ 보면 λ©μ©‘ν΄μ νλ©΄μμλ μ μ‘νλ€ β\n * UX λ μΈμ΄ μμ€λ₯Ό μ½κ³ μ‘μλ€(2026-09-18).\n *\n * ν μΆμ μΈμ
toolbar(`assistant-session-toolbar.ts`)κ° κ°λλ€. μ΄ ν¨λμ μκΈ° ν μΆμ μΈμ°μ§ μλλ€.\n * ARIA νμ μ’μ° νμ΄ν μ΄λκ³Ό `tabpanel` μ΄ ν¨κ» μμ΄μΌ μ±λ¦½νλλ°, μ¬κΈ°μλ λ λ€ μλ€.\n *\n * μ£Όμμ λ²κ²¨ λΈλ€ β μ λ¬Έλ¨μ μ ν `role=\"tablist\"` κ° κ²μ¬λ₯Ό ν΅κ³Όμν€λ©΄ κ·Έ κ²μ¬λ μκΈ° μ°λ¬Έμ μΌλ€.\n */\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nfunction bare(name: string): string {\n return readFileSync(join(__dirname, name), 'utf-8')\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/^\\s*\\/\\/.*$/gm, '')\n}\n\ndescribe('the panel does not raise a second tab axis', () => {\n it('β
assistant-chat λ tablist/tab μ μ μΈνμ§ μλλ€ β κ·Έ μΆμ μΈμ
toolbarμ κ²μ΄λ€', () => {\n const found = [...bare('assistant-chat.ts').matchAll(/role=\"(tablist|tab)\"/g)].map(m => m[1])\n\n expect(found).toEqual([])\n })\n\n it('μΈμ
toolbarλ κ·Έ μΆμ κ³μ κ°λλ€ β μ μνμ΄ μΆμ μμ λΌλ λ»μΌλ‘ μ½νμ§ μλλ‘', () => {\n expect(bare('assistant-session-toolbar.ts')).toContain('role=\"tablist\"')\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"panel-aria.test.js","sourceRoot":"","sources":["../../client/components/panel-aria.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC;SAChD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;AACjC,CAAC;AAED,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IAC1D,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAE7F,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,QAAQ,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC9D,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C;;;;WAIG;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QAEpG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["/*\n * ν¨λ μμ κ³ λ₯΄λ μΆμ΄ λμΌ λ β λ λ€ γνγμ΄λΌκ³ λ§νμ§ μλλ€.\n *\n * ββ μ μ΄ μνμ΄ μλ ββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n * λν κ³ λ₯΄κ°λ₯Ό μΉ© μ€λ‘ λ§λ€λ©΄μ `role=\"tablist\"` λ₯Ό λ¬μλ€. λ°λ‘ μλκ° μΈμ
νμ΄κ³ κ·Έμͺ½λ tablist\n * λΌμ, νλ©΄ λλ
κΈ°λ‘ λ€μΌλ©΄ γν λͺ©λ‘, λνγ λ€μμ γν λͺ©λ‘, Conversation historyγ κ° μ΄μ΄μ‘λ€.\n * κ³ λ₯΄λ μΆμ΄ λμΈλ° λ λ€ κ°μ μ΄λ¦μΌλ‘ λΆλ¦°λ€. λμΌλ‘ 보면 λ©μ©‘ν΄μ νλ©΄μμλ μ μ‘νλ€ β\n * UX λ μΈμ΄ μμ€λ₯Ό μ½κ³ μ‘μλ€(2026-09-18).\n *\n * ν μΆμ μΈμ
toolbar(`assistant-session-toolbar.ts`)κ° κ°λλ€. μ΄ ν¨λμ μκΈ° ν μΆμ μΈμ°μ§ μλλ€.\n * ARIA νμ μ’μ° νμ΄ν μ΄λκ³Ό `tabpanel` μ΄ ν¨κ» μμ΄μΌ μ±λ¦½νλλ°, μ¬κΈ°μλ λ λ€ μλ€.\n *\n * μ£Όμμ λ²κ²¨ λΈλ€ β μ λ¬Έλ¨μ μ ν `role=\"tablist\"` κ° κ²μ¬λ₯Ό ν΅κ³Όμν€λ©΄ κ·Έ κ²μ¬λ μκΈ° μ°λ¬Έμ μΌλ€.\n */\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nfunction bare(name: string): string {\n return readFileSync(join(__dirname, name), 'utf-8')\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/^\\s*\\/\\/.*$/gm, '')\n}\n\ndescribe('the panel does not raise a second tab axis', () => {\n it('β
assistant-chat λ tablist/tab μ μ μΈνμ§ μλλ€ β κ·Έ μΆμ μΈμ
toolbarμ κ²μ΄λ€', () => {\n const found = [...bare('assistant-chat.ts').matchAll(/role=\"(tablist|tab)\"/g)].map(m => m[1])\n\n expect(found).toEqual([])\n })\n\n it('μΈμ
toolbarλ κ·Έ μΆμ κ³μ κ°λλ€ β μ μνμ΄ μΆμ μμ λΌλ λ»μΌλ‘ μ½νμ§ μλλ‘', () => {\n expect(bare('assistant-session-toolbar.ts')).toContain('role=\"tablist\"')\n })\n})\n\n/*\n * 첨λΆλ **λλ κ²λ§** κΆνλ€ β ADR-0071 보ν¬(2026-09-18).\n *\n * `.json` Β· `.txt` Β· `.csv` λ λ°κ³ μμλλ°, κ·Έ νμΌλ€μ μ€λ €λ§ κ°κ³ λͺ¨λΈμ λΆλ μ½λκ° μμλ€. μ¬λμ΄\n * CSV λ₯Ό λΆμ΄κ³ λ¬ΌμΌλ©΄ νμΌ μΉ©μ΄ λ¨κ³ λ΅λ μλ€ β κ·Έ λ΅μ νμΌμ λ³Έ μ μ΄ μκ³ μ€λ₯λ μ λ¬λ€.\n * μ΄λ―Έμ§λ `hostContext.image` λ‘ μ¬λ ν΄μ λΆλ κΈΈμ΄ μλ€.\n */\ndescribe('the attach control offers only what has a path', () => {\n it('β
μ΄λ―Έμ§λ§ λ°λλ€ β μ½νμ§ μλ κ²μ νλ©΄μ΄ κΆνμ§ μλλ€', () => {\n /*\n * μ¬κΈ°μλ μ£Όμμ μ λ²κΈ΄λ€. `image/*` μμ²΄κ° `/*` λ₯Ό νκ³ μμ΄μ, μ£Όμ λ²κΈ°κ°κ° κ·Έ μ리λ₯Ό μ£Όμμ\n * μμμΌλ‘ μ½κ³ λ€μ `*` + `/` κΉμ§ μ§μ λ²λ¦°λ€ β κ°μ΄ μ¬λΌμ§κ³ μνμ γμλ€γκ³ λ΅νλ€.\n * μ΄ κ°μ μ£Όμμ μ ν μΌμ΄ μμΌλ―λ‘ μλ¬Έμμ κ·Έλλ‘ μ½λλ€.\n */\n const accept = readFileSync(join(__dirname, 'assistant-chat.ts'), 'utf-8').match(/accept=\"([^\"]*)\"/)\n\n expect(accept?.[1]).toBe('image/*')\n })\n})\n"]}
|