@things-factory/ai-assistant 10.1.123 → 10.1.125
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 +23 -27
- package/client/utils/assistant-navigation.test.ts +22 -0
- package/dist-client/components/assistant-chat.js +21 -26
- package/dist-client/components/assistant-chat.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/assistant-navigation.test.js +20 -0
- package/dist-client/utils/assistant-navigation.test.js.map +1 -1
- package/package.json +2 -2
- package/test/assistant-request-context.test.ts +3 -1
|
@@ -34,4 +34,24 @@ describe('navigation wiring', () => {
|
|
|
34
34
|
expect(dock).toContain("errorCode: 'conversation-screen-changed'");
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
|
+
describe('a carried draft survives opening a new conversation', () => {
|
|
38
|
+
test('automatic review starts after cleanup and is sent once per request', () => {
|
|
39
|
+
const source = readFileSync(join(__dirname, '../components/assistant-chat.ts'), 'utf8');
|
|
40
|
+
const update = source.slice(source.indexOf(' updated(changed:'), source.indexOf(' disconnectedCallback()', source.indexOf(' updated(changed:')));
|
|
41
|
+
const placement = update.indexOf('if (this.autoAsk &&');
|
|
42
|
+
expect(placement).toBeGreaterThan(update.indexOf("if (changed.has('sessionId')"));
|
|
43
|
+
expect(update.slice(placement)).not.toContain("this.input = ''");
|
|
44
|
+
expect(update.slice(placement)).toContain('!== this._autoAsked');
|
|
45
|
+
expect(update.slice(placement)).toContain('void this.send()');
|
|
46
|
+
});
|
|
47
|
+
test('draft placement follows subject, mode and session cleanup', () => {
|
|
48
|
+
const source = readFileSync(join(__dirname, '../components/assistant-chat.ts'), 'utf8');
|
|
49
|
+
const update = source.slice(source.indexOf(' updated(changed:'), source.indexOf(' disconnectedCallback()', source.indexOf(' updated(changed:')));
|
|
50
|
+
const placement = update.indexOf('const draft = assistantDraftDecision(');
|
|
51
|
+
expect(placement).toBeGreaterThan(update.indexOf("if (changed.has('subject'))"));
|
|
52
|
+
expect(placement).toBeGreaterThan(update.indexOf("if (changed.has('mode')"));
|
|
53
|
+
expect(placement).toBeGreaterThan(update.indexOf("if (changed.has('sessionId')"));
|
|
54
|
+
expect(update.slice(placement)).not.toContain("this.input = ''");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
37
57
|
//# sourceMappingURL=assistant-navigation.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-navigation.test.js","sourceRoot":"","sources":["../../client/utils/assistant-navigation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,QAAQ,CAAC,oEAAoE,EAAE,GAAG,EAAE;IAClF,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,iDAAiD,EAAE,MAAM,CAAC,EAAE;QACnF,KAAK,MAAM,WAAW,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YACxC,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACzF,CAAC;IACH,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzG,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC/E,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACvG,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,iBAAiB,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACxG,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iCAAiC,CAAC,EAAE,MAAM,CAAC,CAAA;IACrF,IAAI,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAA;QACxD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAA;QACrD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAA;QACjD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACtF,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,sCAAsC,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACvE,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,0CAA0C,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { surfaceTransition } from './assistant-navigation.js'\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\ndescribe('a screen offers context without taking over an active conversation', () => {\n test.each([false, true])('a different identity resets even when active=%s', active => {\n for (const sameSubject of [false, true]) {\n expect(surfaceTransition({ identityChanged: true, sameSubject, active })).toBe('reset')\n }\n })\n test('an empty conversation follows the screen', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: false, active: false })).toBe('follow')\n })\n test('an existing conversation, draft or ongoing response offers a switch', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: false, active: true })).toBe('offer')\n })\n test('returning to the same subject refreshes without reopening', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: true, active: true })).toBe('refresh')\n })\n})\n\ndescribe('navigation wiring', () => {\n const dock = readFileSync(join(__dirname, '../components/assistant-dock.ts'), 'utf8')\n test('history hides rather than unmounts the chat and its unsent input', () => {\n expect(dock).toContain('?hidden=${this.showingHistory}')\n expect(dock).toContain('ready && !this.loading && !this.failure')\n })\n test('identity changes clear a carried ask and reread capability', () => {\n expect(dock).toContain(\"if (transition === 'reset')\")\n expect(dock).toContain('this.asking = undefined')\n expect(dock).toContain(\"this.capability = 'unknown'\")\n })\n test('all direct board actions check the current screen, not the retained editor', () => {\n expect(dock).toContain('if (!this.mayApplyOnScreen()) return')\n expect(dock.match(/if \\(this.mayApplyOnScreen\\(\\)\\)/g)).toHaveLength(2)\n expect(dock).toContain(\"errorCode: 'conversation-screen-changed'\")\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-navigation.test.js","sourceRoot":"","sources":["../../client/utils/assistant-navigation.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { surfaceTransition } from './assistant-navigation.js'\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\ndescribe('a screen offers context without taking over an active conversation', () => {\n test.each([false, true])('a different identity resets even when active=%s', active => {\n for (const sameSubject of [false, true]) {\n expect(surfaceTransition({ identityChanged: true, sameSubject, active })).toBe('reset')\n }\n })\n test('an empty conversation follows the screen', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: false, active: false })).toBe('follow')\n })\n test('an existing conversation, draft or ongoing response offers a switch', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: false, active: true })).toBe('offer')\n })\n test('returning to the same subject refreshes without reopening', () => {\n expect(surfaceTransition({ identityChanged: false, sameSubject: true, active: true })).toBe('refresh')\n })\n})\n\ndescribe('navigation wiring', () => {\n const dock = readFileSync(join(__dirname, '../components/assistant-dock.ts'), 'utf8')\n test('history hides rather than unmounts the chat and its unsent input', () => {\n expect(dock).toContain('?hidden=${this.showingHistory}')\n expect(dock).toContain('ready && !this.loading && !this.failure')\n })\n test('identity changes clear a carried ask and reread capability', () => {\n expect(dock).toContain(\"if (transition === 'reset')\")\n expect(dock).toContain('this.asking = undefined')\n expect(dock).toContain(\"this.capability = 'unknown'\")\n })\n test('all direct board actions check the current screen, not the retained editor', () => {\n expect(dock).toContain('if (!this.mayApplyOnScreen()) return')\n expect(dock.match(/if \\(this.mayApplyOnScreen\\(\\)\\)/g)).toHaveLength(2)\n expect(dock).toContain(\"errorCode: 'conversation-screen-changed'\")\n })\n})\n\n\ndescribe('a carried draft survives opening a new conversation', () => {\n test('automatic review starts after cleanup and is sent once per request', () => {\n const source = readFileSync(join(__dirname, '../components/assistant-chat.ts'), 'utf8')\n const update = source.slice(source.indexOf(' updated(changed:'), source.indexOf(' disconnectedCallback()', source.indexOf(' updated(changed:')))\n const placement = update.indexOf('if (this.autoAsk &&')\n expect(placement).toBeGreaterThan(update.indexOf(\"if (changed.has('sessionId')\"))\n expect(update.slice(placement)).not.toContain(\"this.input = ''\")\n expect(update.slice(placement)).toContain('!== this._autoAsked')\n expect(update.slice(placement)).toContain('void this.send()')\n })\n test('draft placement follows subject, mode and session cleanup', () => {\n const source = readFileSync(join(__dirname, '../components/assistant-chat.ts'), 'utf8')\n const update = source.slice(source.indexOf(' updated(changed:'), source.indexOf(' disconnectedCallback()', source.indexOf(' updated(changed:')))\n const placement = update.indexOf('const draft = assistantDraftDecision(')\n expect(placement).toBeGreaterThan(update.indexOf(\"if (changed.has('subject'))\"))\n expect(placement).toBeGreaterThan(update.indexOf(\"if (changed.has('mode')\"))\n expect(placement).toBeGreaterThan(update.indexOf(\"if (changed.has('sessionId')\"))\n expect(update.slice(placement)).not.toContain(\"this.input = ''\")\n })\n})\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/ai-assistant",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.125",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"things-factory": true,
|
|
6
6
|
"author": "heartyoh",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"copyfiles": "^2.4.1",
|
|
53
53
|
"rimraf": "^5.0.0"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "74e02381ea5f179dca2b7516078eb2709ac28ffe"
|
|
56
56
|
}
|
|
@@ -63,7 +63,9 @@ test('no draft, nothing to do', () => {
|
|
|
63
63
|
|
|
64
64
|
test('the component places the draft and never sends it', () => {
|
|
65
65
|
const chat = readFileSync(join(__dirname, '../client/components/assistant-chat.ts'), 'utf8')
|
|
66
|
-
const
|
|
66
|
+
const start = chat.indexOf(' updated(changed')
|
|
67
|
+
const updated = chat.slice(start, chat.indexOf('// 자동 스크롤', start))
|
|
68
|
+
assert.ok(updated.includes('assistantDraftDecision('), 'the draft decision is made in updated()')
|
|
67
69
|
const draftPart = updated.slice(updated.indexOf('assistantDraftDecision('))
|
|
68
70
|
assert.match(draftPart, /this\.input = this\.draft!/)
|
|
69
71
|
assert.doesNotMatch(draftPart, /this\.send\(\)/)
|