@things-factory/ai-assistant 10.1.46 → 10.1.47
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 +3 -1
- package/client/components/assistant-mode.ts +27 -0
- package/client/components/chat-input-builder.ts +8 -1
- package/client/index.ts +2 -0
- package/client/utils/assistant-capability-read.ts +24 -0
- package/client/utils/assistant-capability.test.ts +17 -0
- package/client/utils/assistant-capability.ts +19 -0
- package/dist-client/components/assistant-chat.js +3 -1
- package/dist-client/components/assistant-chat.js.map +1 -1
- package/dist-client/components/assistant-mode.js +24 -0
- package/dist-client/components/assistant-mode.js.map +1 -1
- package/dist-client/components/chat-input-builder.d.ts +9 -0
- package/dist-client/components/chat-input-builder.js +2 -1
- package/dist-client/components/chat-input-builder.js.map +1 -1
- package/dist-client/index.d.ts +2 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/assistant-capability-read.d.ts +6 -0
- package/dist-client/utils/assistant-capability-read.js +23 -0
- package/dist-client/utils/assistant-capability-read.js.map +1 -0
- package/dist-client/utils/assistant-capability.d.ts +4 -0
- package/dist-client/utils/assistant-capability.js +17 -0
- package/dist-client/utils/assistant-capability.js.map +1 -0
- package/dist-client/utils/assistant-capability.test.d.ts +1 -0
- package/dist-client/utils/assistant-capability.test.js +16 -0
- package/dist-client/utils/assistant-capability.test.js.map +1 -0
- package/dist-server/service/assistant-chat-resolver.js +1 -1
- package/dist-server/service/assistant-chat-resolver.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -0
- package/dist-server/service/index.js +3 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/server/service/assistant-chat-resolver.ts +1 -1
- package/server/service/chat-message/fold-session-history.test.ts +18 -0
- package/server/service/index.ts +1 -0
|
@@ -4529,7 +4529,9 @@ export class OxAssistantChat extends LitElement {
|
|
|
4529
4529
|
categories: this.categories,
|
|
4530
4530
|
componentSchemas: this.componentSchemas,
|
|
4531
4531
|
selectedRefids: this.selectedRefids ?? [],
|
|
4532
|
-
mentions
|
|
4532
|
+
mentions,
|
|
4533
|
+
/* With a declared mode the server owns persona and tools; the board door still carries the board. */
|
|
4534
|
+
mode: this.conversation.kind ? { kind: this.conversation.kind, target: this.conversation.target } : undefined
|
|
4533
4535
|
})
|
|
4534
4536
|
}
|
|
4535
4537
|
})
|
|
@@ -103,6 +103,33 @@ export function resolveConversation(
|
|
|
103
103
|
defaults: Partial<ConversationSettings>,
|
|
104
104
|
view?: AssistantModeView
|
|
105
105
|
): ConversationSettings {
|
|
106
|
+
if (mode && own.chatEndpoint === 'boardAIChat') {
|
|
107
|
+
/*
|
|
108
|
+
* The board door with a declared mode. The mode decides persona and tools on the server; the
|
|
109
|
+
* door stays `boardAIChat` because only it carries the board document and returns patches -
|
|
110
|
+
* `assistantChat` has no document. What the panel offers comes from the mode where the mode
|
|
111
|
+
* declares it, and from the board's own defaults (the # component catalog, the slash
|
|
112
|
+
* templates) where it does not, so a mode that declares nothing does not empty the panel.
|
|
113
|
+
*/
|
|
114
|
+
const offered = view && view.kind === mode.kind ? view : undefined
|
|
115
|
+
const pickOwn = <K extends keyof ConversationSettings>(key: K): ConversationSettings[K] =>
|
|
116
|
+
(own as any)[key] ?? (defaults as any)[key]
|
|
117
|
+
const orOwn = (list: any[] | undefined, key: 'catalogEntries' | 'slashTemplates' | 'proposalChoices') =>
|
|
118
|
+
list && list.length > 0 ? list : (pickOwn(key) as any[]) ?? []
|
|
119
|
+
return {
|
|
120
|
+
kind: mode.kind,
|
|
121
|
+
target: mode.target,
|
|
122
|
+
hostContext: mode.hostContext ?? pickOwn('hostContext'),
|
|
123
|
+
chatEndpoint: 'boardAIChat',
|
|
124
|
+
catalogEntries: orOwn(offered?.catalogEntries, 'catalogEntries'),
|
|
125
|
+
slashTemplates: orOwn(offered?.slashTemplates, 'slashTemplates'),
|
|
126
|
+
proposalChoices: orOwn(offered?.proposalChoices, 'proposalChoices'),
|
|
127
|
+
placeholder: offered?.placeholder ?? pickOwn('placeholder'),
|
|
128
|
+
footerNotice: offered?.footerNotice ?? pickOwn('footerNotice'),
|
|
129
|
+
stagedNotice: offered?.stagedNotice ?? pickOwn('stagedNotice')
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
106
133
|
if (mode) {
|
|
107
134
|
/* A view for another kind is the previous conversation's answer arriving late. */
|
|
108
135
|
const offered = view && view.kind === mode.kind ? view : undefined
|
|
@@ -40,6 +40,12 @@ export interface ChatMutationInputArgs {
|
|
|
40
40
|
* server 가 mention map 으로 LLM 에 정확한 refid 정보 첨부 (사용자 노출 0).
|
|
41
41
|
*/
|
|
42
42
|
mentions?: Array<{ token: string; refid: number }>
|
|
43
|
+
/**
|
|
44
|
+
* The registered conversation this board chat is (ADR-0061 decision 7). When sent, the server
|
|
45
|
+
* takes the persona, tool categories, model and limits from that mode and ignores the per-request
|
|
46
|
+
* ones above. Omitted for a surface that declares no mode.
|
|
47
|
+
*/
|
|
48
|
+
mode?: { kind: string; target?: string }
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/**
|
|
@@ -64,7 +70,8 @@ export function buildChatMutationInput(args: ChatMutationInputArgs): Record<stri
|
|
|
64
70
|
categories: args.categories,
|
|
65
71
|
componentSchemas: args.componentSchemas,
|
|
66
72
|
selectedRefids: args.selectedRefids,
|
|
67
|
-
...(args.mentions && args.mentions.length > 0 && { mentions: args.mentions })
|
|
73
|
+
...(args.mentions && args.mentions.length > 0 && { mentions: args.mentions }),
|
|
74
|
+
...(args.mode?.kind ? { mode: { kind: args.mode.kind, ...(args.mode.target ? { target: args.mode.target } : {}) } } : {})
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
|
package/client/index.ts
CHANGED
|
@@ -15,3 +15,5 @@ export * from './utils/assistant-session-controller.js'
|
|
|
15
15
|
export * from './utils/assistant-session-transport.js'
|
|
16
16
|
export * from './components/assistant-session-toolbar.js'
|
|
17
17
|
export * from './utils/assistant-request-context.js'
|
|
18
|
+
export * from './utils/assistant-capability.js'
|
|
19
|
+
export * from './utils/assistant-capability-read.js'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { client } from '@operato/graphql'
|
|
2
|
+
import gql from 'graphql-tag'
|
|
3
|
+
|
|
4
|
+
import { capabilityOf, type AiCapability } from './assistant-capability.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Asks `aiCapability` (standard A7-a). A GraphQL error is thrown for the caller to show; the caller keeps
|
|
8
|
+
* `unknown` meanwhile and asks again — it does not remember a failed read as an answer.
|
|
9
|
+
*/
|
|
10
|
+
export async function readAiCapability(): Promise<AiCapability> {
|
|
11
|
+
const result = await client.query({
|
|
12
|
+
query: gql`
|
|
13
|
+
query {
|
|
14
|
+
aiCapability {
|
|
15
|
+
state
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
fetchPolicy: 'no-cache'
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if (result.errors?.length) throw new Error(result.errors[0].message)
|
|
23
|
+
return capabilityOf(result.data?.aiCapability)
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A7-a — the third state is never read as the first.
|
|
3
|
+
*/
|
|
4
|
+
import { capabilityOf } from './assistant-capability'
|
|
5
|
+
|
|
6
|
+
describe('capabilityOf', () => {
|
|
7
|
+
it('passes the two answers the door gives', () => {
|
|
8
|
+
expect(capabilityOf({ state: 'configured' })).toBe('configured')
|
|
9
|
+
expect(capabilityOf({ state: 'not-configured' })).toBe('not-configured')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('★ not asked yet, and an answer it cannot read, are unknown — never configured', () => {
|
|
13
|
+
for (const answer of [undefined, null, {}, { state: null }, { state: 'yes' }, { state: 'CONFIGURED' }]) {
|
|
14
|
+
expect(capabilityOf(answer as any)).toBe('unknown')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Whether this deployment has an AI to answer — the rule every dock reads before offering a conversation.
|
|
3
|
+
*
|
|
4
|
+
* AI standard A7-a: a screen does not find out by failing. Without this a dock takes the question, sends
|
|
5
|
+
* it, and only then shows the provider's error. `aiCapability` answers first.
|
|
6
|
+
*
|
|
7
|
+
* Three states, and the third is the screen's own: not asked yet, or an answer that could not be read.
|
|
8
|
+
* It is never folded into `configured` — that is where the question started (a button that was always on).
|
|
9
|
+
*
|
|
10
|
+
* Pure, so it is tested without GraphQL. The read is `readAiCapability` (`assistant-capability-read.ts`).
|
|
11
|
+
* Warehouse and twin each held a copy of this until it moved here (2026-09-24).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type AiCapability = 'configured' | 'not-configured' | 'unknown'
|
|
15
|
+
|
|
16
|
+
export function capabilityOf(answer: { state?: string | null } | null | undefined): AiCapability {
|
|
17
|
+
const state = answer?.state
|
|
18
|
+
return state === 'configured' || state === 'not-configured' ? state : 'unknown'
|
|
19
|
+
}
|
|
@@ -4039,7 +4039,9 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
|
|
|
4039
4039
|
categories: this.categories,
|
|
4040
4040
|
componentSchemas: this.componentSchemas,
|
|
4041
4041
|
selectedRefids: this.selectedRefids ?? [],
|
|
4042
|
-
mentions
|
|
4042
|
+
mentions,
|
|
4043
|
+
/* With a declared mode the server owns persona and tools; the board door still carries the board. */
|
|
4044
|
+
mode: this.conversation.kind ? { kind: this.conversation.kind, target: this.conversation.target } : undefined
|
|
4043
4045
|
})
|
|
4044
4046
|
}
|
|
4045
4047
|
});
|