@trismegisto/spine 3.3.6 → 3.3.7
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/README.md +2 -2
- package/fesm2022/{trismegisto-spine-layout-ai-agent-chat.component-C5JljPYD.mjs → trismegisto-spine-layout-ai-agent-chat.component-LlxtxNA5.mjs} +2 -2
- package/fesm2022/{trismegisto-spine-layout-ai-agent-chat.component-C5JljPYD.mjs.map → trismegisto-spine-layout-ai-agent-chat.component-LlxtxNA5.mjs.map} +1 -1
- package/fesm2022/trismegisto-spine-layout-ai-agent-transcript-BNcgbrV_.mjs +438 -0
- package/fesm2022/trismegisto-spine-layout-ai-agent-transcript-BNcgbrV_.mjs.map +1 -0
- package/fesm2022/{trismegisto-spine-layout-suggestions-page.component-Bh3VGlOR.mjs → trismegisto-spine-layout-suggestions-page.component-BEGFNlvw.mjs} +2 -2
- package/fesm2022/{trismegisto-spine-layout-suggestions-page.component-Bh3VGlOR.mjs.map → trismegisto-spine-layout-suggestions-page.component-BEGFNlvw.mjs.map} +1 -1
- package/fesm2022/{trismegisto-spine-layout-trismegisto-spine-layout-B47sMo_4.mjs → trismegisto-spine-layout-trismegisto-spine-layout-D3vetDC_.mjs} +88 -25
- package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-D3vetDC_.mjs.map +1 -0
- package/fesm2022/trismegisto-spine-layout.mjs +1 -1
- package/fesm2022/trismegisto-spine.mjs +18 -0
- package/fesm2022/trismegisto-spine.mjs.map +1 -1
- package/package.json +6 -6
- package/types/trismegisto-spine.d.ts +8 -2
- package/types/trismegisto-spine.d.ts.map +1 -1
- package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-B47sMo_4.mjs.map +0 -1
|
@@ -1915,19 +1915,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
|
|
|
1915
1915
|
const TOKEN_HEADER = 'x-access-token';
|
|
1916
1916
|
const WS_PROTOCOL = 'graphql-transport-ws';
|
|
1917
1917
|
const SUBSCRIPTION_ID = '1';
|
|
1918
|
-
|
|
1919
|
-
|
|
1918
|
+
// Nenhuma operação leva o agente: o gateway o descobre pelo client do token.
|
|
1919
|
+
const EVENTS_QUERY = `subscription ($conversationId: ID!) {
|
|
1920
|
+
agentEvents(conversationId: $conversationId) { type text tool title ok detail message }
|
|
1920
1921
|
}`;
|
|
1921
|
-
const SEND_MUTATION = `mutation ($
|
|
1922
|
-
sendAgentMessage(
|
|
1922
|
+
const SEND_MUTATION = `mutation ($input: SendAgentMessageInput!) {
|
|
1923
|
+
sendAgentMessage(input: $input) { status message }
|
|
1923
1924
|
}`;
|
|
1924
|
-
const RATE_MUTATION = `mutation ($
|
|
1925
|
-
rateAgentMessage(
|
|
1925
|
+
const RATE_MUTATION = `mutation ($input: RateAgentMessageInput!) {
|
|
1926
|
+
rateAgentMessage(input: $input) { status message }
|
|
1926
1927
|
}`;
|
|
1927
|
-
const CONVERSATION_QUERY = `query ($
|
|
1928
|
-
agentConversation(
|
|
1928
|
+
const CONVERSATION_QUERY = `query ($conversationId: ID!) {
|
|
1929
|
+
agentConversation(conversationId: $conversationId) { status data { role text steps { tool title ok detail } } }
|
|
1929
1930
|
}`;
|
|
1930
|
-
const
|
|
1931
|
+
const AGENT_QUERY = `query { agent { status data { suggestions } } }`;
|
|
1931
1932
|
/**
|
|
1932
1933
|
* Assina os eventos de uma conversa e devolve a função que encerra a assinatura. Usa o WebSocket do navegador, com o
|
|
1933
1934
|
* protocolo do graphql-ws: o shell também atende apps sem GraphQL, que não têm o pacote `graphql-ws` instalado.
|
|
@@ -1976,7 +1977,7 @@ async function sendAgentMessage(url, token, variables, text) {
|
|
|
1976
1977
|
headers: { 'content-type': 'application/json', [TOKEN_HEADER]: token },
|
|
1977
1978
|
body: JSON.stringify({
|
|
1978
1979
|
query: SEND_MUTATION,
|
|
1979
|
-
variables: {
|
|
1980
|
+
variables: { input: { conversationId: variables.conversationId, text } },
|
|
1980
1981
|
}),
|
|
1981
1982
|
});
|
|
1982
1983
|
const body = await response.json();
|
|
@@ -1989,22 +1990,21 @@ async function rateAgentMessage(url, token, variables, messageIndex, rating, cor
|
|
|
1989
1990
|
headers: { 'content-type': 'application/json', [TOKEN_HEADER]: token },
|
|
1990
1991
|
body: JSON.stringify({
|
|
1991
1992
|
query: RATE_MUTATION,
|
|
1992
|
-
variables: {
|
|
1993
|
+
variables: { input: { conversationId: variables.conversationId, messageIndex, rating, correction } },
|
|
1993
1994
|
}),
|
|
1994
1995
|
});
|
|
1995
1996
|
const body = await response.json();
|
|
1996
1997
|
return body?.data?.rateAgentMessage ?? { status: response.status >= 400 ? response.status : 500, message: '' };
|
|
1997
1998
|
}
|
|
1998
|
-
/** Perguntas prontas que o agente oferece.
|
|
1999
|
-
async function fetchAgentSuggestions(url, token
|
|
1999
|
+
/** Perguntas prontas que o agente oferece. */
|
|
2000
|
+
async function fetchAgentSuggestions(url, token) {
|
|
2000
2001
|
const response = await fetch(url, {
|
|
2001
2002
|
method: 'POST',
|
|
2002
2003
|
headers: { 'content-type': 'application/json', [TOKEN_HEADER]: token },
|
|
2003
|
-
body: JSON.stringify({ query:
|
|
2004
|
+
body: JSON.stringify({ query: AGENT_QUERY }),
|
|
2004
2005
|
});
|
|
2005
2006
|
const body = await response.json();
|
|
2006
|
-
|
|
2007
|
-
return agents.find((agent) => agent.id === agentId)?.suggestions ?? [];
|
|
2007
|
+
return body?.data?.agent?.data?.suggestions ?? [];
|
|
2008
2008
|
}
|
|
2009
2009
|
/** As perguntas e respostas de uma conversa que já existe; vazia se ela expirou. */
|
|
2010
2010
|
async function fetchAgentConversation(url, token, variables) {
|
|
@@ -2060,7 +2060,8 @@ function writeStored(key, value) {
|
|
|
2060
2060
|
*/
|
|
2061
2061
|
class SpineAiAgentService {
|
|
2062
2062
|
constructor() {
|
|
2063
|
-
this.
|
|
2063
|
+
this.spine = inject(SPINE_CONFIG, { optional: true });
|
|
2064
|
+
this.config = this.spine?.features?.aiAgent ?? null;
|
|
2064
2065
|
this.auth = inject(AuthorizationService);
|
|
2065
2066
|
this.text = inject(SPINE_MESSAGES).aiAgentChat;
|
|
2066
2067
|
this.enabled = !!this.config;
|
|
@@ -2089,7 +2090,8 @@ class SpineAiAgentService {
|
|
|
2089
2090
|
this.position = signal(readPlacement().position ?? null, ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
2090
2091
|
/** A pessoa pediu o painel agora: a conversa recebe o foco. Ao recarregar a tela, não. */
|
|
2091
2092
|
this.focusOnOpen = false;
|
|
2092
|
-
|
|
2093
|
+
// Por app: vários apps podem morar na mesma origem, e o localStorage é dela.
|
|
2094
|
+
this.storageKey = `${STORAGE_PREFIX}${this.spine?.clientId ?? ''}`;
|
|
2093
2095
|
this.storedConversation = readStored(this.storageKey);
|
|
2094
2096
|
this.conversationId = this.storedConversation ?? this.newConversationId();
|
|
2095
2097
|
this.restored = !this.storedConversation;
|
|
@@ -2147,7 +2149,7 @@ class SpineAiAgentService {
|
|
|
2147
2149
|
if (!this.config || !token || this.suggestionsLoaded)
|
|
2148
2150
|
return;
|
|
2149
2151
|
this.suggestionsLoaded = true;
|
|
2150
|
-
fetchAgentSuggestions(this.config.http, token
|
|
2152
|
+
fetchAgentSuggestions(this.config.http, token).then((suggestions) => this.suggestions.set(suggestions), () => { this.suggestionsLoaded = false; });
|
|
2151
2153
|
}
|
|
2152
2154
|
/** Traz de volta a conversa guardada, uma vez. Se falhar, ou se ela expirou, o chat só começa vazio. */
|
|
2153
2155
|
restoreConversation() {
|
|
@@ -2156,7 +2158,7 @@ class SpineAiAgentService {
|
|
|
2156
2158
|
return;
|
|
2157
2159
|
this.restored = true;
|
|
2158
2160
|
const conversationId = this.conversationId;
|
|
2159
|
-
fetchAgentConversation(this.config.http, token, {
|
|
2161
|
+
fetchAgentConversation(this.config.http, token, { conversationId }).then((messages) => {
|
|
2160
2162
|
// A pessoa pode ter começado a escrever antes de a resposta chegar: o que está na tela vence.
|
|
2161
2163
|
if (this.entries().length || conversationId !== this.conversationId)
|
|
2162
2164
|
return;
|
|
@@ -2182,7 +2184,7 @@ class SpineAiAgentService {
|
|
|
2182
2184
|
const index = saved.findIndex((entry) => entry.id === entryId);
|
|
2183
2185
|
if (!this.config || !token || index < 1)
|
|
2184
2186
|
return false;
|
|
2185
|
-
const variables = {
|
|
2187
|
+
const variables = { conversationId: this.conversationId };
|
|
2186
2188
|
try {
|
|
2187
2189
|
const { status } = await rateAgentMessage(this.config.http, token, variables, index, rating, correction);
|
|
2188
2190
|
if (status >= 400)
|
|
@@ -2194,6 +2196,46 @@ class SpineAiAgentService {
|
|
|
2194
2196
|
this.update(entryId, (entry) => ({ ...entry, rating }));
|
|
2195
2197
|
return true;
|
|
2196
2198
|
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Baixa a conversa da tela em PDF, gerado aqui no navegador: nada sai para o backend. O gerador vem só no clique, para
|
|
2201
|
+
* não pesar em quem nunca baixa. Devolve `false` se não houver o que baixar ou se a geração falhar.
|
|
2202
|
+
*/
|
|
2203
|
+
async downloadTranscript() {
|
|
2204
|
+
const entries = this.entries().filter((entry) => entry.text.trim() || entry.steps.length);
|
|
2205
|
+
if (!entries.length)
|
|
2206
|
+
return false;
|
|
2207
|
+
try {
|
|
2208
|
+
const { buildTranscriptPdf, transcriptFileName } = await import('./trismegisto-spine-layout-ai-agent-transcript-BNcgbrV_.mjs');
|
|
2209
|
+
const now = new Date();
|
|
2210
|
+
const person = this.auth.profile?.name;
|
|
2211
|
+
const pdf = buildTranscriptPdf({
|
|
2212
|
+
title: this.title,
|
|
2213
|
+
subtitle: [this.spine?.appName, person, now.toLocaleString()].filter(Boolean).join(' · '),
|
|
2214
|
+
personLabel: person || this.text.you,
|
|
2215
|
+
agentLabel: this.title,
|
|
2216
|
+
queriesLabel: this.text.transcriptQueries,
|
|
2217
|
+
failedLabel: this.text.transcriptStepFailed,
|
|
2218
|
+
pageLabel: this.text.transcriptPage,
|
|
2219
|
+
entries: entries.map((entry) => ({
|
|
2220
|
+
role: entry.role,
|
|
2221
|
+
text: entry.text,
|
|
2222
|
+
error: entry.error,
|
|
2223
|
+
steps: entry.steps.map((step) => ({ title: step.title, detail: step.detail, failed: step.status === 'error' })),
|
|
2224
|
+
})),
|
|
2225
|
+
});
|
|
2226
|
+
const url = URL.createObjectURL(new Blob([pdf.slice().buffer], { type: 'application/pdf' }));
|
|
2227
|
+
const link = document.createElement('a');
|
|
2228
|
+
link.href = url;
|
|
2229
|
+
link.download = transcriptFileName(this.title, this.text.transcriptFile, now);
|
|
2230
|
+
link.click();
|
|
2231
|
+
// O navegador só lê o endereço depois do clique: revogar na hora cancelaria o download em alguns deles.
|
|
2232
|
+
setTimeout(() => URL.revokeObjectURL(url), 10_000);
|
|
2233
|
+
return true;
|
|
2234
|
+
}
|
|
2235
|
+
catch {
|
|
2236
|
+
return false;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2197
2239
|
/** Repete a última pergunta depois de um erro. Resposta que falhou não entra no histórico do backend. */
|
|
2198
2240
|
retry() {
|
|
2199
2241
|
const entries = this.entries();
|
|
@@ -2216,7 +2258,7 @@ class SpineAiAgentService {
|
|
|
2216
2258
|
return;
|
|
2217
2259
|
}
|
|
2218
2260
|
this.running.set(true);
|
|
2219
|
-
this.listen(answerId, {
|
|
2261
|
+
this.listen(answerId, { conversationId: this.conversationId }, text);
|
|
2220
2262
|
}
|
|
2221
2263
|
listen(answerId, variables, question) {
|
|
2222
2264
|
const token = this.auth.getToken();
|
|
@@ -7558,7 +7600,7 @@ function registerPage() {
|
|
|
7558
7600
|
route_redirect: SPINE_SUGGESTIONS_PAGE_PATH,
|
|
7559
7601
|
description: text.description,
|
|
7560
7602
|
},
|
|
7561
|
-
load: () => import('./trismegisto-spine-layout-suggestions-page.component-
|
|
7603
|
+
load: () => import('./trismegisto-spine-layout-suggestions-page.component-BEGFNlvw.mjs').then((m) => m.SpineSuggestionsPageComponent),
|
|
7562
7604
|
});
|
|
7563
7605
|
});
|
|
7564
7606
|
}
|
|
@@ -8703,6 +8745,7 @@ class SpineAiAgentLauncherComponent {
|
|
|
8703
8745
|
constructor() {
|
|
8704
8746
|
this.agent = inject(SpineAiAgentService);
|
|
8705
8747
|
this.text = inject(SPINE_MESSAGES).aiAgentChat;
|
|
8748
|
+
this.toast = inject(HermesToastService);
|
|
8706
8749
|
this.panelId = PANEL_ID;
|
|
8707
8750
|
this.titleId = TITLE_ID;
|
|
8708
8751
|
/** Tamanho do painel: continua como a pessoa deixou ao fechar e abrir. */
|
|
@@ -8761,7 +8804,7 @@ class SpineAiAgentLauncherComponent {
|
|
|
8761
8804
|
const focus = this.agent.focusOnOpen;
|
|
8762
8805
|
this.agent.focusOnOpen = false;
|
|
8763
8806
|
if (!this.chat()) {
|
|
8764
|
-
const { SpineAiAgentChatComponent } = await import('./trismegisto-spine-layout-ai-agent-chat.component-
|
|
8807
|
+
const { SpineAiAgentChatComponent } = await import('./trismegisto-spine-layout-ai-agent-chat.component-LlxtxNA5.mjs');
|
|
8765
8808
|
this.chat.set(SpineAiAgentChatComponent);
|
|
8766
8809
|
}
|
|
8767
8810
|
this.agent.loadSuggestions();
|
|
@@ -8797,6 +8840,10 @@ class SpineAiAgentLauncherComponent {
|
|
|
8797
8840
|
this.agent.dock();
|
|
8798
8841
|
afterNextRender(() => this.focusEntry(), { injector: this.injector });
|
|
8799
8842
|
}
|
|
8843
|
+
async downloadTranscript() {
|
|
8844
|
+
if (!(await this.agent.downloadTranscript()))
|
|
8845
|
+
this.toast.error(this.text.transcriptDownloadError);
|
|
8846
|
+
}
|
|
8800
8847
|
undock() {
|
|
8801
8848
|
this.agent.undock();
|
|
8802
8849
|
afterNextRender(() => this.focusEntry(), { injector: this.injector });
|
|
@@ -8870,6 +8917,14 @@ class SpineAiAgentLauncherComponent {
|
|
|
8870
8917
|
[disabled]="agent.running() || !agent.entries().length"
|
|
8871
8918
|
(clicked)="agent.reset()"
|
|
8872
8919
|
/>
|
|
8920
|
+
<hm-icon-button
|
|
8921
|
+
emphasis="subtle"
|
|
8922
|
+
size="small"
|
|
8923
|
+
icon="download"
|
|
8924
|
+
[label]="text.transcriptDownload"
|
|
8925
|
+
[disabled]="agent.running() || !agent.entries().length"
|
|
8926
|
+
(clicked)="downloadTranscript()"
|
|
8927
|
+
/>
|
|
8873
8928
|
<hm-icon-button
|
|
8874
8929
|
emphasis="subtle"
|
|
8875
8930
|
size="small"
|
|
@@ -8977,6 +9032,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
|
|
|
8977
9032
|
[disabled]="agent.running() || !agent.entries().length"
|
|
8978
9033
|
(clicked)="agent.reset()"
|
|
8979
9034
|
/>
|
|
9035
|
+
<hm-icon-button
|
|
9036
|
+
emphasis="subtle"
|
|
9037
|
+
size="small"
|
|
9038
|
+
icon="download"
|
|
9039
|
+
[label]="text.transcriptDownload"
|
|
9040
|
+
[disabled]="agent.running() || !agent.entries().length"
|
|
9041
|
+
(clicked)="downloadTranscript()"
|
|
9042
|
+
/>
|
|
8980
9043
|
<hm-icon-button
|
|
8981
9044
|
emphasis="subtle"
|
|
8982
9045
|
size="small"
|
|
@@ -9716,4 +9779,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
|
|
|
9716
9779
|
*/
|
|
9717
9780
|
|
|
9718
9781
|
export { SpineAppTokensService as $, AppLauncherComponent as A, SPINE_INBOX_POLL_MS as B, SPINE_INBOX_SOURCES as C, SPINE_MARKDOWN_PURIFY_CONFIG as D, SPINE_PREFERENCES_SAVE_DELAY_MS as E, SPINE_RATING_COMMENT_MAX as F, SPINE_RATING_SCORE_MAX as G, HeaderComponent as H, SPINE_SETTINGS_ALIASES as I, SPINE_SETTINGS_KEYS as J, SPINE_SETTINGS_SECTIONS as K, LayoutComponent as L, McpConnectComponent as M, NEW_SCREEN_VALUE as N, SPINE_SUGGESTIONS_PAGE_ID as O, SPINE_SUGGESTION_LIMITS as P, SPINE_SUGGESTION_PUBLIC_SORTS as Q, SPINE_SUGGESTION_PUBLIC_STATUSES as R, SpineSuggestionsService as S, SPINE_SUGGESTION_STATUS_ICONS as T, SPINE_WORKSPACE_LIMITS as U, SettingsPanelComponent as V, ShortcutService as W, ShortcutsCheatsheetComponent as X, SidebarComponent as Y, SpineAccountPreferencesService as Z, SpineAccountSecurityService as _, SpineInboxService as a, SpineBrandComponent as a0, SpineConnectionBannerComponent as a1, SpineDocsComponent as a2, SpineDocsService as a3, SpineIdleService as a4, SpineIdleWarningComponent as a5, SpineInboxButtonComponent as a6, SpineInitialSetupComponent as a7, SpineInitialSetupService as a8, SpineLogoutService as a9, spineParamsOf as aA, spinePathOf as aB, spineScoreBand as aC, spineStarFills as aD, spineSuggestionsEnabled as aE, spineTagColor as aF, stable as aG, SpineMyGroupsService as aa, SpineNewsComponent as ab, SpineNewsService as ac, SpineNoticesService as ad, SpinePageActionsDirective as ae, SpinePageActionsSlot as af, SpineRatingStarsComponent as ag, SpineRatingsService as ah, SpineSettingsService as ai, SpineStartPageService as aj, SpineUnsavedChangesService as ak, SpineWorkspaceNavService as al, accountErrorCode as am, argosAccountApi as an, buildMcpConfig as ao, effectiveIdleMinutes as ap, idleLimits as aq, isInternalPath as ar, provideSettingsSection as as, provideSpineInboxSource as at, provideSpineSuggestionsPage as au, ratingTargetKey as av, registerSpineUnsavedChanges as aw, resolveSettingsSection as ax, sanitizeSpineMarkdownHtml as ay, spineNormalizeUrl as az, SpineSuggestionChatComponent as b, SPINE_SUGGESTION_STATUS_COLORS as c, SPINE_SUGGESTION_KIND_COLORS as d, SPINE_SUGGESTION_KIND_ICONS as e, SPINE_SUGGESTION_WAITING_COLORS as f, SPINE_SUGGESTION_VISIBLE_SORTS as g, SPINE_SUGGESTION_REASONS as h, SPINE_SUGGESTION_STATUSES as i, SPINE_SUGGESTION_KINDS as j, SPINE_SUGGESTION_WAITING as k, SPINE_TAB as l, SPINE_SUGGESTION_PAGE_PARAM as m, SPINE_SUGGESTION_TAB_PARAM as n, SPINE_SUGGESTION_TAB_CONVERSATION as o, screenName as p, screenModule as q, SPINE_SUGGESTIONS_PAGE_PATH as r, suggestionScreens as s, SpineSuggestionsDialogComponent as t, SpineTagRowComponent as u, SpineAiAgentService as v, SpineMarkdownComponent as w, SPINE_BRAND as x, SPINE_GLOBAL_PREFERENCE_KEYS as y, SPINE_IDLE_WARNING_SECONDS as z };
|
|
9719
|
-
//# sourceMappingURL=trismegisto-spine-layout-trismegisto-spine-layout-
|
|
9782
|
+
//# sourceMappingURL=trismegisto-spine-layout-trismegisto-spine-layout-D3vetDC_.mjs.map
|