@trilogy-data/trilogy-studio-components 0.1.28 → 0.1.30
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 +1 -0
- package/dist/AssetAutoImporter-BA8C4p09.js +403 -0
- package/dist/{ChatCreatorModal-Cd40SvdM.js → ChatCreatorModal-94gZ9D-y.js} +1 -1
- package/dist/{CodeBlock-Dj-GfTbW.js → CodeBlock-C9o09ipr.js} +1 -1
- package/dist/{CommunityModels-lX2RhHCG.js → CommunityModels-D48H9Bqt.js} +6 -6
- package/dist/{ConnectionView-CZ06qjjE.js → ConnectionView-sEXGE8Vs.js} +5 -5
- package/dist/{CreateEditorFromDatasourcePopup-DwA938kf.js → CreateEditorFromDatasourcePopup-BUoegyem.js} +2 -2
- package/dist/{Dashboard-CQsIqWZC.js → Dashboard-C6adKZ7q.js} +202 -203
- package/dist/{DashboardImportSelector-CkqH52FX.js → DashboardImportSelector-CQqXshDj.js} +1 -1
- package/dist/{DashboardMobile-DWFlel5p.js → DashboardMobile-BU1nDLQv.js} +42 -42
- package/dist/{Editor-DQ66Vp6v.js → Editor-DO4VRvek.js} +9 -10
- package/dist/{ErrorMessage-D5JeF3Iz.js → ErrorMessage-Cz7q7vJI.js} +1 -1
- package/dist/{GlobalChatPanel-B_s3COHE.js → GlobalChatPanel-Ct6oSj_A.js} +20 -20
- package/dist/{IDE-4-Jg6gsM.js → IDE-kdaEhA4g.js} +19 -20
- package/dist/{JobsView-B5NWDUgP.js → JobsView-BcyWrDRf.js} +11 -11
- package/dist/{LLMChat-eKgEc-I3.js → LLMChat-Dg8VvTIP.js} +19 -19
- package/dist/{LLMView-CdTwMLVV.js → LLMView-CZNNYXC1.js} +61 -61
- package/dist/{LoadingView-Bu3wLJ7J.js → LoadingView-k2CIKiN7.js} +1 -1
- package/dist/{MarkdownRenderer-B6lqdkgc.js → MarkdownRenderer-Dlb_KGmk.js} +1 -1
- package/dist/{MobileIDE-CZlg20oa.js → MobileIDE-BQcdjWUT.js} +26 -27
- package/dist/{ModelCard-Bs_d7Jis.js → ModelCard-Dn2b5WLs.js} +5 -5
- package/dist/{ModelView-BP5yyecx.js → ModelView-BEi83zrX.js} +6 -6
- package/dist/{PageLoading-DKFeqkmK.js → PageLoading-C7H6q6U6.js} +248 -248
- package/dist/{ResultComponent-BaDheojB.js → ResultComponent-DW9Q9tp9.js} +5 -5
- package/dist/{Results-CrpHB101.js → Results-N2OttUlb.js} +19 -19
- package/dist/{StatusIcon-Clfyy-Yn.js → StatusIcon-B21tjIXx.js} +1 -1
- package/dist/{StoreTokenModal-CO5hXMs3.js → StoreTokenModal-CHgvjLGl.js} +1 -1
- package/dist/{SymbolsPane-XFVErDFb.js → SymbolsPane-DUrLpSSw.js} +11 -11
- package/dist/{TutorialPage-CMcTYDOV.js → TutorialPage-DHgPuFN0.js} +11 -11
- package/dist/{VegaLiteChart-DX_LbF3g.js → VegaLiteChart-BqHLSptG.js} +11116 -11067
- package/dist/{WelcomePage-B6E35FUa.js → WelcomePage-CN6ptsoF.js} +3 -3
- package/dist/agent.js +1349 -0
- package/dist/components/VegaLiteChart.vue.d.ts.map +1 -1
- package/dist/components/chartControlsManager.d.ts +0 -1
- package/dist/components/chartControlsManager.d.ts.map +1 -1
- package/dist/{cssMode-zpO2ap2B.js → cssMode-DW4OByy3.js} +2 -2
- package/dist/dashboard.js +63 -63
- package/dist/dashboards/chartTheme.d.ts +68 -0
- package/dist/dashboards/chartTheme.d.ts.map +1 -0
- package/dist/dashboards/donutSpec.d.ts +2 -1
- package/dist/dashboards/donutSpec.d.ts.map +1 -1
- package/dist/dashboards/headlineSpec.d.ts +2 -1
- package/dist/dashboards/headlineSpec.d.ts.map +1 -1
- package/dist/dashboards/helpers.d.ts +23 -0
- package/dist/dashboards/helpers.d.ts.map +1 -1
- package/dist/dashboards/index.d.ts +2 -0
- package/dist/dashboards/index.d.ts.map +1 -1
- package/dist/dashboards/layerSpec.d.ts +4 -1
- package/dist/dashboards/layerSpec.d.ts.map +1 -1
- package/dist/dashboards/pointSpec.d.ts +2 -1
- package/dist/dashboards/pointSpec.d.ts.map +1 -1
- package/dist/dashboards/spec.d.ts +8 -1
- package/dist/dashboards/spec.d.ts.map +1 -1
- package/dist/{editor.main-BQh6DxDB.js → editor.main-TuTbSVcN.js} +22 -22
- package/dist/{editorStore-CiWH_nGN.js → editorStore-Czhpct1j.js} +1751 -1181
- package/dist/entry.agent.d.ts +12 -0
- package/dist/entry.agent.d.ts.map +1 -0
- package/dist/entry.llm.d.ts +1 -1
- package/dist/entry.llm.d.ts.map +1 -1
- package/dist/{freemarker2-DQBqlEXc.js → freemarker2-ZGcKAI8o.js} +1 -1
- package/dist/{globalChatRuntime-DAERmOdu.js → globalChatRuntime-BnMYNYqe.js} +35 -35
- package/dist/{handlebars-tgYxaM70.js → handlebars-B3s0Qrrb.js} +1 -1
- package/dist/{helpers-C2pARJoZ.js → helpers-B3tq3RZK.js} +17 -17
- package/dist/{html-jJahD3Mi.js → html-DM1koKCG.js} +1 -1
- package/dist/{htmlMode-BA1-8l2e.js → htmlMode-CpPImbDh.js} +2 -2
- package/dist/{javascript-Cypfo7va.js → javascript-jClqu73w.js} +1 -1
- package/dist/{jsonMode-xJye8PWS.js → jsonMode-CwFYTPO9.js} +2 -2
- package/dist/{liquid-BGDrv5da.js → liquid-C6l-UINC.js} +1 -1
- package/dist/llm/chatAgentPrompt.d.ts +4 -16
- package/dist/llm/chatAgentPrompt.d.ts.map +1 -1
- package/dist/llm/dashboardAgentRuntime.d.ts +10 -10
- package/dist/llm/dashboardAgentTools.d.ts +10 -10
- package/dist/llm/data/prompts.d.ts +1 -1
- package/dist/llm/data/prompts.d.ts.map +1 -1
- package/dist/llm/data/trilogySyntax.generated.d.ts +3 -3
- package/dist/llm/data/trilogySyntax.generated.d.ts.map +1 -1
- package/dist/llm/returnToUserTool.d.ts +20 -0
- package/dist/llm/returnToUserTool.d.ts.map +1 -0
- package/dist/llm/toolLoopCore.d.ts +7 -0
- package/dist/llm/toolLoopCore.d.ts.map +1 -1
- package/dist/llm/utils.d.ts.map +1 -1
- package/dist/{llm-Wf4Etiu9.js → llm-Bc1CfjOE.js} +2203 -2722
- package/dist/llm.js +3 -3
- package/dist/{localStorage-C3xms-ab.js → localStorage-Cy0sHlT0.js} +19 -19
- package/dist/{lspLanguageFeatures-V3e_p9oN.js → lspLanguageFeatures-GDtuGOTD.js} +1 -1
- package/dist/{mdx-BUR1aImW.js → mdx-BQEQ0k1f.js} +1 -1
- package/dist/monaco.js +3 -3
- package/dist/{python-YLkl0pc6.js → python-USoVCfWY.js} +1 -1
- package/dist/{razor-BP8TRMDY.js → razor-BxmgiR-q.js} +1 -1
- package/dist/{reconcile-BH_ReGDR.js → reconcile-DtPcgEjQ.js} +1 -1
- package/dist/{remoteStoreSync-B0K8QScO.js → remoteStoreSync-CscErZ-I.js} +2 -2
- package/dist/{stores-DTGQZ4_B.js → stores-DgdADCiH.js} +323 -323
- package/dist/stores.js +3 -4
- package/dist/trilogy-studio-components.css +1 -1
- package/dist/{tsMode-BH9HS_sH.js → tsMode-BEQ7aXX4.js} +1 -1
- package/dist/{typescript-BM-ynfk9.js → typescript-CzBSjjfY.js} +1 -1
- package/dist/{useChatWithTools-BSrzJtYI.js → useChatWithTools-CMhGxdyr.js} +14 -14
- package/dist/{useDashboard-CGeIdDuX.js → useDashboard-CjZgjmgb.js} +553 -553
- package/dist/{useGlobalChatPanel-D9kMZLeF.js → useGlobalChatPanel-Doeilj18.js} +69 -70
- package/dist/views/LLMView.vue.d.ts +23 -23
- package/dist/views/TutorialPage.vue.d.ts +10 -10
- package/dist/views.js +147 -148
- package/dist/vite.agent.config.d.ts +3 -0
- package/dist/vite.agent.config.d.ts.map +1 -0
- package/dist/{workers-B9Eybl-M.js → workers-CHvkad0r.js} +2 -2
- package/dist/{xml-M5WFPSpA.js → xml-ODdyS0gX.js} +1 -1
- package/dist/{yaml-CEeFwjz9.js → yaml-PCBTA2qD.js} +1 -1
- package/package.json +7 -2
- package/dist/AssetAutoImporter-C_7Ms9xe.js +0 -403
- package/dist/rolldown-runtime-B0aSnxlc.js +0 -20
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { LLMProvider } from './llm/base';
|
|
2
|
+
export type { LLMMessage, LLMRequestOptions, LLMResponse, LLMToolCall, LLMToolResult, LLMToolDefinition, RateLimitBackoffCallback, } from './llm/base';
|
|
3
|
+
export { AnthropicProvider, parseAnthropicModelVersion, compareAnthropicModels, } from './llm/anthropic';
|
|
4
|
+
export { OpenAIProvider } from './llm/openai';
|
|
5
|
+
export { OpenRouterProvider } from './llm/openrouter';
|
|
6
|
+
export { DeepSeekProvider, parseDeepSeekModel, compareDeepSeekModels } from './llm/deepseek';
|
|
7
|
+
export { runToolLoop, providerAdapter, formatToolResultText, stripPromptWrapperTags, SYSTEM_INPUT_START, SYSTEM_INPUT_END, } from './llm/toolLoopCore';
|
|
8
|
+
export type { LLMAdapter, MessagePersistence, ToolExecutorFactory, ExecutionStateUpdater, ToolLoopConfig, ToolLoopResult, } from './llm/toolLoopCore';
|
|
9
|
+
export { RETURN_TO_USER_TOOL } from './llm/returnToUserTool';
|
|
10
|
+
export type { ToolCallResult } from './llm/sharedToolHelpers';
|
|
11
|
+
export type { ChatMessage, ChatArtifact, ChatToolCall } from './chats/chat';
|
|
12
|
+
//# sourceMappingURL=entry.agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.agent.d.ts","sourceRoot":"","sources":["../entry.agent.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC5F,OAAO,EACL,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/entry.llm.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from './llm/index';
|
|
2
|
-
export { runToolLoop } from './llm/toolLoopCore';
|
|
2
|
+
export { runToolLoop, providerAdapter } from './llm/toolLoopCore';
|
|
3
3
|
export type { LLMAdapter, MessagePersistence, ToolExecutorFactory, ExecutionStateUpdater, ToolLoopConfig, ToolLoopResult, } from './llm/toolLoopCore';
|
|
4
4
|
export type { ChatMessage, ChatSessionData, ChatArtifact } from './chats';
|
|
5
5
|
//# sourceMappingURL=entry.llm.d.ts.map
|
package/dist/entry.llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.llm.d.ts","sourceRoot":"","sources":["../entry.llm.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"entry.llm.d.ts","sourceRoot":"","sources":["../entry.llm.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACjE,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as o,
|
|
4
|
-
import { a as c,
|
|
5
|
-
import { t as u } from "./useGlobalChatPanel-
|
|
1
|
+
import { Q as e, Z as t, lt as n, nt as r, q as i } from "./llm-Bc1CfjOE.js";
|
|
2
|
+
import { t as a } from "./screenBridge-BLlMdfhn.js";
|
|
3
|
+
import { a as o, r as s } from "./editorStore-Czhpct1j.js";
|
|
4
|
+
import { a as c, d as l } from "./stores-DgdADCiH.js";
|
|
5
|
+
import { t as u } from "./useGlobalChatPanel-Doeilj18.js";
|
|
6
6
|
import { watch as d } from "vue";
|
|
7
7
|
//#region llm/registry/renderToolList.ts
|
|
8
8
|
function f(e) {
|
|
@@ -15,7 +15,7 @@ function f(e) {
|
|
|
15
15
|
//#region llm/navigationContextInjector.ts
|
|
16
16
|
var p = 1500, m = /* @__PURE__ */ new Map();
|
|
17
17
|
function h() {
|
|
18
|
-
let e =
|
|
18
|
+
let e = c();
|
|
19
19
|
return `${e.activeScreen.value}:${e.activeDashboard.value || e.activeEditor.value || ""}`;
|
|
20
20
|
}
|
|
21
21
|
function g(e) {
|
|
@@ -28,7 +28,7 @@ function v(e, t) {
|
|
|
28
28
|
return e.screen === "dashboard" && e.dashboardId ? `[navigation] The user is now viewing dashboard "${t.dashboardName || e.dashboardId}" (id ${e.dashboardId}). Dashboard tools default to the currently viewed dashboard.` : e.screen === "editors" && e.editorId ? `[navigation] The user is now viewing editor "${t.editorName || e.editorId}" (id ${e.editorId}).` : `[navigation] The user is now on the ${e.screen || "welcome"} screen.`;
|
|
29
29
|
}
|
|
30
30
|
function y(e) {
|
|
31
|
-
let t =
|
|
31
|
+
let t = c(), n = null, r = () => {
|
|
32
32
|
let n = e.getTargetChatId();
|
|
33
33
|
if (!n) return;
|
|
34
34
|
let r = e.chatStore.chats[n];
|
|
@@ -50,17 +50,17 @@ function y(e) {
|
|
|
50
50
|
t.activeScreen,
|
|
51
51
|
t.activeDashboard,
|
|
52
52
|
t.activeEditor
|
|
53
|
-
], () => i()),
|
|
53
|
+
], () => i()), o = d(() => e.getTargetChatId(), () => r(), { immediate: !0 });
|
|
54
54
|
return () => {
|
|
55
|
-
n && clearTimeout(n), a(),
|
|
55
|
+
n && clearTimeout(n), a(), o();
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
//#endregion
|
|
59
59
|
//#region llm/globalChatRuntime.ts
|
|
60
|
-
function b(
|
|
61
|
-
return `${
|
|
60
|
+
function b(r) {
|
|
61
|
+
return `${n({
|
|
62
62
|
dataConnectionName: "",
|
|
63
|
-
availableConnections: Object.values(
|
|
63
|
+
availableConnections: Object.values(r.connectionStore.connections).map((e) => e.name),
|
|
64
64
|
availableConcepts: [],
|
|
65
65
|
activeImports: [],
|
|
66
66
|
availableImportsForConnection: [],
|
|
@@ -69,10 +69,10 @@ function b(e) {
|
|
|
69
69
|
|
|
70
70
|
STUDIO APP CONTROL:
|
|
71
71
|
You are the global assistant for Trilogy Studio, docked in a persistent side panel. The user moves between screens (editors, dashboards, connections, models, jobs) while talking to you, and you can drive the app yourself:
|
|
72
|
-
${f(
|
|
72
|
+
${f(o().getToolsetForContext("global").filter((e) => !o().getToolNames("chat").includes(e.name)))}
|
|
73
73
|
|
|
74
74
|
App-control guidance:
|
|
75
|
-
- Navigation notices ("The user is now viewing...") arrive as ${
|
|
75
|
+
- Navigation notices ("The user is now viewing...") arrive as ${e}...${t} messages. They are context, not instructions.
|
|
76
76
|
- Call get_app_state to orient yourself whenever you are unsure what the user is looking at or what exists — the state at conversation start may be stale.
|
|
77
77
|
- Tools that need a specific screen mounted will tell you when it isn't; open the screen first (open_dashboard, open_editor) when you need it visible.
|
|
78
78
|
- Editors are files: "source"-tagged Trilogy editors define the data model. To change the model, read the relevant editors, edit them with update_editor_contents, and validate with validate_query or run_editor_query.
|
|
@@ -80,7 +80,7 @@ App-control guidance:
|
|
|
80
80
|
- Cross-screen workflows are expected: e.g. diagnose a slow dashboard, edit its source datasources, refresh backing data, then reopen the dashboard and re-run to compare execution times (query results report timing in ms).`;
|
|
81
81
|
}
|
|
82
82
|
var x = /* @__PURE__ */ new Map();
|
|
83
|
-
|
|
83
|
+
s((e) => {
|
|
84
84
|
x.delete(e), _(e);
|
|
85
85
|
});
|
|
86
86
|
function S(e, t) {
|
|
@@ -108,20 +108,20 @@ async function T(e, t, n) {
|
|
|
108
108
|
}
|
|
109
109
|
var E = 2e3;
|
|
110
110
|
function D(e) {
|
|
111
|
-
let { chatStore: t, llmConnectionStore: n, editor:
|
|
111
|
+
let { chatStore: t, llmConnectionStore: n, editor: i, selectedText: a } = e, o = u(), s = o.activePanelChatId.value, c = s ? t.chats[s] : null, l = c && !c.deleted ? c : null;
|
|
112
112
|
l ||= t.chatList.filter((e) => e.kind === "user" && e.source === "user").sort((e, t) => new Date(t.updatedAt).getTime() - new Date(e.updatedAt).getTime())[0] || null, l ||= t.newChat(n.activeConnection || "", "", void 0, "", { activate: !1 });
|
|
113
|
-
let d =
|
|
114
|
-
return l.pendingContextNote = `[editor] The user asked for AI help from editor "${
|
|
113
|
+
let d = a?.trim() ? r(a) : "", f = d ? `\nTheir current selection in that editor:\n${d.slice(0, E)}${d.length > E ? "\n...(selection truncated)" : ""}` : "";
|
|
114
|
+
return l.pendingContextNote = `[editor] The user asked for AI help from editor "${r(i.name)}" (id ${i.id}). Read it with read_editor before proposing or making changes; apply edits with update_editor_contents.${f}`, g(l.id), o.openPanel(l.id), l.id;
|
|
115
115
|
}
|
|
116
|
-
async function O(
|
|
117
|
-
let { chatId:
|
|
116
|
+
async function O(n) {
|
|
117
|
+
let { chatId: s, message: u, chatStore: d, deps: f } = n, p = d.chats[s];
|
|
118
118
|
if (!p) return;
|
|
119
|
-
(p.llmConnectionName || f.llmConnectionStore.activeConnection) && p.pendingContextNote && (d.addMessageToChat(
|
|
119
|
+
(p.llmConnectionName || f.llmConnectionStore.activeConnection) && p.pendingContextNote && (d.addMessageToChat(s, {
|
|
120
120
|
role: "user",
|
|
121
|
-
content: `${
|
|
121
|
+
content: `${e}${r(p.pendingContextNote)}${t}`,
|
|
122
122
|
hidden: !0
|
|
123
123
|
}), p.pendingContextNote = null);
|
|
124
|
-
let m =
|
|
124
|
+
let m = o(), h = {
|
|
125
125
|
connectionStore: f.connectionStore,
|
|
126
126
|
editorStore: f.editorStore,
|
|
127
127
|
chatStore: d,
|
|
@@ -129,25 +129,25 @@ async function O(i) {
|
|
|
129
129
|
...f.dashboardStore ? { dashboardStore: f.dashboardStore } : {},
|
|
130
130
|
...f.modelStore ? { modelStore: f.modelStore } : {},
|
|
131
131
|
llmConnectionStore: f.llmConnectionStore,
|
|
132
|
-
jobsStore:
|
|
132
|
+
jobsStore: l(),
|
|
133
133
|
...f.saveEditors ? { saveEditors: f.saveEditors } : {},
|
|
134
134
|
...f.saveModels ? { saveModels: f.saveModels } : {},
|
|
135
|
-
navigation:
|
|
136
|
-
screenBridge:
|
|
135
|
+
navigation: c(),
|
|
136
|
+
screenBridge: a()
|
|
137
137
|
}, g = m.createExecutor("global", h, {
|
|
138
|
-
chatId:
|
|
138
|
+
chatId: s,
|
|
139
139
|
cache: /* @__PURE__ */ new Map(),
|
|
140
140
|
requestCompaction: async (e) => {
|
|
141
|
-
let
|
|
142
|
-
if (!
|
|
141
|
+
let t = f.llmConnectionStore.connections[p.llmConnectionName || f.llmConnectionStore.activeConnection];
|
|
142
|
+
if (!t) return {
|
|
143
143
|
success: !1,
|
|
144
144
|
error: "No LLM provider available for compaction."
|
|
145
145
|
};
|
|
146
146
|
try {
|
|
147
|
-
let
|
|
148
|
-
return
|
|
147
|
+
let n = await i(t, p, { focus: e });
|
|
148
|
+
return n ? {
|
|
149
149
|
success: !0,
|
|
150
|
-
message: `Compacted ${
|
|
150
|
+
message: `Compacted ${n.archivedCount} earlier messages into a summary. The reduced history applies from the next turn.`
|
|
151
151
|
} : {
|
|
152
152
|
success: !0,
|
|
153
153
|
message: "The conversation is still small — nothing worth compacting yet."
|
|
@@ -160,11 +160,11 @@ async function O(i) {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
});
|
|
163
|
-
await d.executeMessage(
|
|
163
|
+
await d.executeMessage(s, u, f, { overrides: {
|
|
164
164
|
tools: m.getToolsetForContext("global"),
|
|
165
165
|
executeToolCall: (e, t) => g.executeToolCall(e, t),
|
|
166
|
-
buildSystemPrompt: S(
|
|
167
|
-
} }), await T(
|
|
166
|
+
buildSystemPrompt: S(s, f)
|
|
167
|
+
} }), await T(s, d, f);
|
|
168
168
|
}
|
|
169
169
|
//#endregion
|
|
170
170
|
export { y as a, _ as i, D as n, O as r, C as t };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import "./
|
|
4
|
-
import
|
|
5
|
-
import { n as s } from "./reconcile-
|
|
1
|
+
import { Rt as e } from "./llm-Bc1CfjOE.js";
|
|
2
|
+
import { s as t } from "./base-DuKnVD-A.js";
|
|
3
|
+
import { M as n, Y as r, _t as i, at as a, tt as o } from "./editorStore-Czhpct1j.js";
|
|
4
|
+
import "./stores-DgdADCiH.js";
|
|
5
|
+
import { n as s } from "./reconcile-DtPcgEjQ.js";
|
|
6
6
|
//#region models/helpers.ts
|
|
7
7
|
var c = class {
|
|
8
8
|
editorStore;
|
|
@@ -17,13 +17,13 @@ var c = class {
|
|
|
17
17
|
async fetchModelImportBase(e, t) {
|
|
18
18
|
let n = await fetch(e, this.buildRequestInit(t));
|
|
19
19
|
if (!n.ok) throw Error(`Failed to fetch model import from ${e}: ${n.statusText}`);
|
|
20
|
-
let
|
|
20
|
+
let i = await n.text(), a;
|
|
21
21
|
try {
|
|
22
|
-
a = JSON.parse(
|
|
22
|
+
a = JSON.parse(i);
|
|
23
23
|
} catch (t) {
|
|
24
24
|
throw Error(`Invalid JSON in model import from ${e}: ${t}`);
|
|
25
25
|
}
|
|
26
|
-
return
|
|
26
|
+
return r(a, e);
|
|
27
27
|
}
|
|
28
28
|
purposeToTag(e) {
|
|
29
29
|
switch (e) {
|
|
@@ -81,7 +81,7 @@ var c = class {
|
|
|
81
81
|
if (e.name?.trim()) return this.getRemoteEditorPath(e);
|
|
82
82
|
if (!t) return null;
|
|
83
83
|
try {
|
|
84
|
-
let
|
|
84
|
+
let r = `${n(t)}/`, i = new URL(r), a = new URL(e.url, i);
|
|
85
85
|
if (a.origin !== i.origin || !a.pathname.startsWith(i.pathname)) return null;
|
|
86
86
|
let o = a.pathname.slice(i.pathname.length);
|
|
87
87
|
return decodeURIComponent(o);
|
|
@@ -115,8 +115,8 @@ var c = class {
|
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
try {
|
|
118
|
-
let o =
|
|
119
|
-
o.storage = "local", o.connection = r, o.connectionId =
|
|
118
|
+
let o = e.fromSerialized(JSON.parse(n.content));
|
|
119
|
+
o.storage = "local", o.connection = r, o.connectionId = t({
|
|
120
120
|
name: r,
|
|
121
121
|
storage: a.remote ? "remote" : "local",
|
|
122
122
|
remoteStoreId: a.remoteStoreId
|
|
@@ -132,18 +132,18 @@ var c = class {
|
|
|
132
132
|
console.error(`Error importing dashboard ${n.name}:`, e);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
async importModel(e, t,
|
|
135
|
+
async importModel(e, t, n, r = {}) {
|
|
136
136
|
if (!t) return null;
|
|
137
137
|
let a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
|
|
138
138
|
try {
|
|
139
|
-
let l = await this.fetchModelImportBase(t,
|
|
139
|
+
let l = await this.fetchModelImportBase(t, r.token), u = await this.fetchModelImports(l, r.token), d = u.filter((e) => e.type === "sql" || e.type === "trilogy" || e.type === "python"), f = u.filter((e) => e.type === "dashboard"), p = [];
|
|
140
140
|
for (let e of d) {
|
|
141
141
|
console.log(`Processing editor: ${e.name}`);
|
|
142
|
-
let t = this.createOrUpdateEditor(e,
|
|
143
|
-
e.type === "sql" ? o.set(e.name, t.id) : e.type === "trilogy" ? (s.set(e.name, t.id), p.push(new
|
|
142
|
+
let t = this.createOrUpdateEditor(e, n, r);
|
|
143
|
+
e.type === "sql" ? o.set(e.name, t.id) : e.type === "trilogy" ? (s.set(e.name, t.id), p.push(new i(t.id, e.alias || e.name, [], []))) : e.type === "python" && c.set(e.name, t.id);
|
|
144
144
|
}
|
|
145
|
-
for (let e of f) console.log(`Processing dashboard: ${e.name}`), this.createOrUpdateDashboard(e,
|
|
146
|
-
return this.modelStore.models[e].sources = p, this.modelStore.models[e].storage =
|
|
145
|
+
for (let e of f) console.log(`Processing dashboard: ${e.name}`), this.createOrUpdateDashboard(e, n, a, r);
|
|
146
|
+
return this.modelStore.models[e].sources = p, this.modelStore.models[e].storage = r.remote ? "remote" : "local", this.modelStore.models[e].changed = !0, {
|
|
147
147
|
dashboards: a,
|
|
148
148
|
sql: o,
|
|
149
149
|
trilogy: s,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as e, t } from "./workers-
|
|
2
|
-
import { _ as n, a as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as d, n as f, o as p, p as m, r as h, s as g, t as _, u as v, v as y } from "./lspLanguageFeatures-
|
|
1
|
+
import { p as e, t } from "./workers-CHvkad0r.js";
|
|
2
|
+
import { _ as n, a as r, c as i, d as a, f as o, g as s, h as c, i as l, l as u, m as d, n as f, o as p, p as m, r as h, s as g, t as _, u as v, v as y } from "./lspLanguageFeatures-GDtuGOTD.js";
|
|
3
3
|
//#region node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor/esm/vs/language/html/workerManager.js
|
|
4
4
|
var b = 12e4, x = class {
|
|
5
5
|
constructor(e) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { conf as e, language as t } from "./typescript-
|
|
1
|
+
import { conf as e, language as t } from "./typescript-CzBSjjfY.js";
|
|
2
2
|
//#region node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor/esm/vs/basic-languages/javascript/javascript.js
|
|
3
3
|
var n = e, r = {
|
|
4
4
|
defaultToken: "invalid",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as e, p as t, t as n } from "./workers-
|
|
2
|
-
import { _ as r, a as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b } from "./lspLanguageFeatures-
|
|
1
|
+
import { d as e, p as t, t as n } from "./workers-CHvkad0r.js";
|
|
2
|
+
import { _ as r, a as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b } from "./lspLanguageFeatures-GDtuGOTD.js";
|
|
3
3
|
//#region node_modules/.pnpm/monaco-editor@0.55.1/node_modules/monaco-editor/esm/vs/language/json/workerManager.js
|
|
4
4
|
var x = 12e4, S = class {
|
|
5
5
|
constructor(e) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ModelConceptInput } from './data/models';
|
|
2
2
|
import { ChatImport } from '../chats/chat';
|
|
3
3
|
import { LLMToolDefinition } from './base';
|
|
4
|
+
import { RETURN_TO_USER_TOOL } from './returnToUserTool';
|
|
4
5
|
import { ToolCallResult } from './sharedToolHelpers';
|
|
5
6
|
export interface TrilogyPromptContext {
|
|
6
7
|
/** Complete syntax reference generated from pytrilogy's AI prompt. */
|
|
@@ -35,7 +36,8 @@ export interface TrilogyPromptContext {
|
|
|
35
36
|
* ```
|
|
36
37
|
*/
|
|
37
38
|
export declare function buildCustomTrilogyPrompt(templateFn: (ctx: TrilogyPromptContext) => string): string;
|
|
38
|
-
export
|
|
39
|
+
export { RETURN_TO_USER_TOOL };
|
|
40
|
+
export declare const CHAT_TOOLS: ({
|
|
39
41
|
readonly name: "return_to_user";
|
|
40
42
|
readonly description: "Signal that you are done and return control to the user. You MUST call this tool when you have completed all requested tasks and are ready for the user's next input. Provide a brief summary of what was accomplished. Never end a turn with plain text — always call this tool when finished.";
|
|
41
43
|
readonly input_schema: {
|
|
@@ -48,8 +50,7 @@ export declare const RETURN_TO_USER_TOOL: {
|
|
|
48
50
|
};
|
|
49
51
|
readonly required: readonly ["message"];
|
|
50
52
|
};
|
|
51
|
-
}
|
|
52
|
-
export declare const CHAT_TOOLS: ({
|
|
53
|
+
} | {
|
|
53
54
|
readonly name: "connect_data_connection";
|
|
54
55
|
readonly description: "Connect or reconnect a data connection that is not currently active. Use this when a query fails because the connection is not active, or when you need to establish a connection before running queries.";
|
|
55
56
|
readonly input_schema: {
|
|
@@ -62,19 +63,6 @@ export declare const CHAT_TOOLS: ({
|
|
|
62
63
|
};
|
|
63
64
|
readonly required: readonly ["connection"];
|
|
64
65
|
};
|
|
65
|
-
} | {
|
|
66
|
-
readonly name: "return_to_user";
|
|
67
|
-
readonly description: "Signal that you are done and return control to the user. You MUST call this tool when you have completed all requested tasks and are ready for the user's next input. Provide a brief summary of what was accomplished. Never end a turn with plain text — always call this tool when finished.";
|
|
68
|
-
readonly input_schema: {
|
|
69
|
-
readonly type: "object";
|
|
70
|
-
readonly properties: {
|
|
71
|
-
readonly message: {
|
|
72
|
-
readonly type: "string";
|
|
73
|
-
readonly description: "A brief summary of what was accomplished or a response to the user.";
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
readonly required: readonly ["message"];
|
|
77
|
-
};
|
|
78
66
|
} | {
|
|
79
67
|
name: string;
|
|
80
68
|
description: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatAgentPrompt.d.ts","sourceRoot":"","sources":["../../llm/chatAgentPrompt.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAQzD,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,sBAAsB,EAAE,MAAM,CAAA;IAC9B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,MAAM,GAChD,MAAM,CAQR;AAGD,
|
|
1
|
+
{"version":3,"file":"chatAgentPrompt.d.ts","sourceRoot":"","sources":["../../llm/chatAgentPrompt.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAQzD,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,sBAAsB,EAAE,MAAM,CAAA;IAC9B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,MAAM,GAChD,MAAM,CAQR;AAGD,OAAO,EAAE,mBAAmB,EAAE,CAAA;AAG9B,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyOtB,CAAA;AAED,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,MAAM,EAAE,CAAA;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAA;IACvC,aAAa,CAAC,EAAE,UAAU,EAAE,CAAA;IAC5B,6BAA6B,CAAC,EAAE,UAAU,EAAE,CAAA;IAC5C,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5D,KAAK,EAAE,CAAC,EAAE,EACV,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,CAAC,EAAE,CAIL;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,iBAAiB,CAAA;IAC7B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAAA;CAClF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACxD,KAAK,EAAE,CAAC,EAAE,EACV,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,GAC9C,CAAC,EAAE,CAkBL;AA8ED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CA0FlF"}
|
|
@@ -32,30 +32,30 @@ export declare function ensureDashboardChat(dashboard: DashboardModel, chatStore
|
|
|
32
32
|
/** Tools the agent receives. Reports get the report-mode tools layered onto
|
|
33
33
|
* the standard dashboard tool surface. */
|
|
34
34
|
export declare function dashboardAgentToolset(dashboard: DashboardModel): ({
|
|
35
|
-
readonly name: "
|
|
36
|
-
readonly description: "
|
|
35
|
+
readonly name: "return_to_user";
|
|
36
|
+
readonly description: "Signal that you are done and return control to the user. You MUST call this tool when you have completed all requested tasks and are ready for the user's next input. Provide a brief summary of what was accomplished. Never end a turn with plain text — always call this tool when finished.";
|
|
37
37
|
readonly input_schema: {
|
|
38
38
|
readonly type: "object";
|
|
39
39
|
readonly properties: {
|
|
40
|
-
readonly
|
|
40
|
+
readonly message: {
|
|
41
41
|
readonly type: "string";
|
|
42
|
-
readonly description: "
|
|
42
|
+
readonly description: "A brief summary of what was accomplished or a response to the user.";
|
|
43
43
|
};
|
|
44
44
|
};
|
|
45
|
-
readonly required: readonly ["
|
|
45
|
+
readonly required: readonly ["message"];
|
|
46
46
|
};
|
|
47
47
|
} | {
|
|
48
|
-
readonly name: "
|
|
49
|
-
readonly description: "
|
|
48
|
+
readonly name: "connect_data_connection";
|
|
49
|
+
readonly description: "Connect or reconnect a data connection that is not currently active. Use this when a query fails because the connection is not active, or when you need to establish a connection before running queries.";
|
|
50
50
|
readonly input_schema: {
|
|
51
51
|
readonly type: "object";
|
|
52
52
|
readonly properties: {
|
|
53
|
-
readonly
|
|
53
|
+
readonly connection: {
|
|
54
54
|
readonly type: "string";
|
|
55
|
-
readonly description: "
|
|
55
|
+
readonly description: "The name of the data connection to connect";
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
|
-
readonly required: readonly ["
|
|
58
|
+
readonly required: readonly ["connection"];
|
|
59
59
|
};
|
|
60
60
|
} | {
|
|
61
61
|
name: string;
|
|
@@ -3,30 +3,30 @@
|
|
|
3
3
|
* These tools let the LLM read and modify a live dashboard.
|
|
4
4
|
*/
|
|
5
5
|
export declare const DASHBOARD_TOOLS: ({
|
|
6
|
-
readonly name: "
|
|
7
|
-
readonly description: "
|
|
6
|
+
readonly name: "return_to_user";
|
|
7
|
+
readonly description: "Signal that you are done and return control to the user. You MUST call this tool when you have completed all requested tasks and are ready for the user's next input. Provide a brief summary of what was accomplished. Never end a turn with plain text — always call this tool when finished.";
|
|
8
8
|
readonly input_schema: {
|
|
9
9
|
readonly type: "object";
|
|
10
10
|
readonly properties: {
|
|
11
|
-
readonly
|
|
11
|
+
readonly message: {
|
|
12
12
|
readonly type: "string";
|
|
13
|
-
readonly description: "
|
|
13
|
+
readonly description: "A brief summary of what was accomplished or a response to the user.";
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
-
readonly required: readonly ["
|
|
16
|
+
readonly required: readonly ["message"];
|
|
17
17
|
};
|
|
18
18
|
} | {
|
|
19
|
-
readonly name: "
|
|
20
|
-
readonly description: "
|
|
19
|
+
readonly name: "connect_data_connection";
|
|
20
|
+
readonly description: "Connect or reconnect a data connection that is not currently active. Use this when a query fails because the connection is not active, or when you need to establish a connection before running queries.";
|
|
21
21
|
readonly input_schema: {
|
|
22
22
|
readonly type: "object";
|
|
23
23
|
readonly properties: {
|
|
24
|
-
readonly
|
|
24
|
+
readonly connection: {
|
|
25
25
|
readonly type: "string";
|
|
26
|
-
readonly description: "
|
|
26
|
+
readonly description: "The name of the data connection to connect";
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
|
-
readonly required: readonly ["
|
|
29
|
+
readonly required: readonly ["connection"];
|
|
30
30
|
};
|
|
31
31
|
} | {
|
|
32
32
|
name: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ModelConceptInput } from './models';
|
|
2
2
|
export declare function filterDatePartConcepts(concepts: ModelConceptInput[]): ModelConceptInput[];
|
|
3
|
-
export declare const leadIn = "You are a world-class assistant for generating queries in Trilogy, a SQL inspired language with similar syntax, Use the the syntax description below and field information to answer the user request. Return your answer with a short reasoning and a valid Trilogy query in triple double quotes.\n\n# Trilogy Syntax\n\nTrilogy statements define a semantic model or a query; collections of statements\nare written as `.preql` files. A statement returns data (SELECT) or defines\nconcepts (key | property | auto | metric), datasources, or parameters.\n\nimport <model> as <alias>; makes a model's fields available. <model> is a DOT-SEPARATED MODULE PATH relative to the project root (where trilogy.toml lives), never a file path: the file `raw/store_sales.preql` is imported as `import raw.store_sales as ss;` \u2014 replace each `/` with `.`, drop the `.preql`, keep the folder segment. When an imported model imports others (a fact with imported dimensions), those are dot paths: `enroll.student.name`. Typical usage imports ONE fact and reaches dimensions through it; nested dimensions carry ALL values (order.customers includes customers without orders).\n\nkey | property | auto | metric; define new concepts. `auto x <- ...` is a DEFINITION, not a precomputed value: each reference expands and re-evaluates in the consuming query's scope.\n\nparameter NAME TYPE [default <literal>]; \u2014 a runtime value supplied via `--param NAME=VALUE` (repeatable); append `?` to the type to allow null.\n\n## Combining models\n\n| Goal | Use |\n|---|---|\n| Typical query | no merge, no join: access all fields through dot-paths |\n| Blend two models on shared keys inside one query | scoped `subset\\|union\\|equal join` |\n| Make a connection universal to a whole file | `merge` |\n| Stack subsets/channels as rows | `union(...)` |\n| Rows in A but never in B (set difference) | `except(...)` |\n| Rows present in every source (set intersection) | `intersect(...)` |\n\n### Query-scoped join\n\nA typical fact already has its dimensions merged in, so no join is needed. Blending fact models or rowset outputs takes a scoped join, placed right after the select list, which DECLARES how the key domains relate: `subset join a = b` (a's values are contained in b's, a \u2286 b; b authoritative for the key), `union join a = b` (neither contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept) or `equal join a = b` (ONE domain: a is an alias of b, every value on either side is on the other; the join renders inner).\n\nTwo rules decide whether the numbers are right, so apply them before reaching for the example:\n\n- Joins NEVER drop a row and NULL keys match null-safely; there is NO inner join. An intersection is an explicit `where <optional-side attr> is not null`.\n- JOIN ON THE FULL GRAIN: `explore` prints each fact's grain as @<k1, k2>; write one clause PER key. Matching only one key of a multi-key grain causes duplication.\n\nChaining, expression keys, union/subset mixing, multi-key and self-pair shapes: trilogy agent-info syntax example scoped-join.\n\nmerge <a> into ~<b>; is the persistent (whole-file) equivalent of `subset join a = b`; plain `merge a into b;` is the persistent equivalent of `equal join a = b`. Standalone statements; prefer a scoped join unless the connection is universal.\n\n### union / except / intersect (row set operations)\n\n`union(...)` row-stacks self-contained select arms positionally (SQL UNION ALL) into one named rowset (`with combined as union((armA), (armB), ...) -> (out1, out2, ...)`); `except(...)` / `intersect(...)` share that arm shape but are SQL SET operators (DISTINCT rows, null-safe whole-row compare, and except subtracts later arms from the FIRST, so arm order matters). Prefer except over a multi-column `not in` for \"in A but never in B\". Each arm dedups to its own output grain BEFORE stacking, so aggregate INSIDE each arm or the total silently undersums. Examples: trilogy agent-info syntax example union-stack-channels / except-intersect-setops.\n\n## Query structure\n\nTop-level statements first (each `;`-terminated), then a query with clauses in this EXACT order \u2014 all optional except select:\n\n```\n<top-level statements>; # import / key / auto / rowset / merge / def / parameter\nwith <name> as # optional: name the select as a reusable rowset (CTE)\nwhere <row condition> # 1. filters INPUT rows, BEFORE aggregation\nselect <col>, <agg> as name, # 2. projection \u2014 grouping is AUTOMATIC by the\n # non-aggregated columns; never write GROUP BY\n subset|union|equal join a = b (= c)? # 3. blend models; one clause per key, right after the select list\nby rollup|cube|grouping sets (...) # 4. optional multi-level grouping for the whole select\nhaving <result condition> # 5. filters aggregated/joined RESULTS\norder by <col> asc|desc # 6. sort\nlimit <n>; # 7. cap rows\n```\n\nA rowset (`with <name> as where ... select ...;`) is a standalone statement, evaluated in isolation \u2014 it does NOT respond to the consuming query's context. All its outputs are namespaced: output `abc.def` of rowset `foo` is referenced as `foo.abc.def`. Pairing an output with a concept outside the rowset REQUIRES a declared join on the rowset's key (`subset join foo.key = key`); without one the query is disconnected. Alternatively project the concept inside the rowset and filter or select it through the handle (`where foo.cat = 'a'`). Alias every reused expression with `as`.\n\nFull annotated example: trilogy agent-info syntax example query-structure.\n\n### Not SQL \u2014 what to never write\n\n- **No FROM, GROUP BY, DISTINCT, SELECT \\*, or SQL-style set operators between selects.** Stack rows with `union(...)`; set difference/intersection with `except(...)`/`intersect(...)`; blend fact models with a scoped join.\n- **Grouping is automatic** by the non-aggregated fields in the SELECT \u2014 never write GROUP BY. Aggregates inherit the select's grain wherever they appear (where/select/having). Override per-aggregate with `agg(x) by <dims>`; `by *` aggregates across all data (single row). To weight a related dimension property once per fact row, project it to the fact grain first: `auto row_birth_year <- group(enroll.student.birth_year) by enroll.student_id, enroll.course_id;` then aggregate that.\n- **Output rows are deduplicated to the select grain.** To preserve legitimate duplicates (one row per matching fact), include the fact's grain keys in the select \u2014 hidden with the PREFIX `--` if they shouldn't appear in the output.\n- **Never write `distinct`.** `count(<key>)` is already distinct because keys are unique; `count_distinct(<property>)` counts distinct values of a non-key property.\n- **Count a COMPOSITE grain with `grain(...)`.** `count(grain(order_id, item.id))` counts order+item combinations; `grain(...)` is NEVER NULL. Never count one column of a multi-key grain \u2014 a coarser key counts its own distinct values and undercounts. `count_distinct(a, b)` is accepted as sugar for `count(grain(a, b))` (distinct combinations, NULL members included).\n- **An aggregate over a group with no qualifying rows is NULL, never 0.** `sum(x ? cond) by k` yields NULL for groups where nothing matches, so `= 0` matches nothing. Test emptiness with `count(key ? cond) by k = 0` or wrap: `coalesce(sum(x ? cond), 0)`.\n- **`count(1)` is invalid** \u2014 a constant does not identify rows. Use the row key, `count(grain(...))`, or `sum(1) by <grain>`.\n- **One-column expression subqueries only.** `(select ...)` is allowed where a scalar or membership set is expected (exactly one projected column; a scalar must also be one row: an aggregate with no `by`, or `limit 1`) \u2014 never as a SQL-style FROM-subquery. For related-entity filters prefer the dot-path: `where enrollments.student.state = 'TN'`, not a subselect.\n- **`--` is a HIDDEN-field prefix, not a comment** (it still changes query structure). Comments use `#` only.\n- **Aliases**: always use the full dot-path (`enroll.student.id`); alias every new expression with `as`; a select alias is usable in `having`/`order by` but NOT inside other select expressions or `where`, and must not rename a field back to an existing concept name.\n\n## Filtering\n\n`where` filters input rows before aggregation; `having` filters results after aggregation/windows. The inline filter `x ? cond` filters the immediate prior expression: `sum(credits ? enrolled = true)`.\n\nAggregates/windows in WHERE do not filter each other's inputs. Use inline filters, or a staged `then where` chain: each `then where` stage's aggregates compute over only the rows passing earlier stages (`where x = 5 then where sum(y) > 10` \u2261 `where x = 5 and sum(y ? x = 5) > 10`). One rule: the SAME cross-row expression cannot gate two different stages \u2014 give one an inline filter.\n\nWindows need all rows in their range: filter AFTER the window (in `having`) rather than in `where` when the window must see the full set.\n\n## Membership (semijoins)\n\n`in` / `not in` cross models without any declared relationship \u2014 the semijoin IS a scoped intersection. The right side is a concept or expression (never a subselect); build computed sets with an inline filter: `auto big_zip <- student.zip ? (count(student.id ? student.honors = true) by student.zip) > 10; ... where school.zip in big_zip`.\n\nMembership is IDENTITY matching, not SQL three-valued logic: NULL matches NULL; the result is always TRUE or FALSE (safe as a projected flag); `not in` is the exact complement (a NULL in the set never empties the result). For strict SQL behavior, add `x is not null`.\n\nA fact model contains ALL dimensional members, so `where students.id not in enroll.student_id` is typically a tautology \u2014 use `where enroll.id is null` instead. Tuple membership `(a, b) in (m.a, m.b)` requires both right-side concepts to resolve to ONE source (model or rowset); to test against a cross-model pair, stage it through a rowset first. Examples: existence-anti-join, staged-membership.\n\n## Aggregation\n\nAn aggregate without an explicit `by` is RESPONSIVE \u2014 its grain is set where it is consumed, not where it is declared (`auto avg_credits <- avg(enroll.credits);` becomes per-department when selected with `enroll.department`). Pin a grain inline: `sum(metric) by dim1, dim2 as name`; `by` accepts bare identifiers or parenthesized expressions: `avg(price) by (substring(phone, 1, 2))`.\n\nMulti-level grouping (`by rollup|cube|grouping sets (...)`) is a clause of the WHOLE select, placed before `having`: it computes every no-explicit-grain aggregate at every level in one pass (`by rollup (d1, d2)` \u2192 leaf, per-d1 subtotal, grand total). `grouping(<field>)` = 1 on rolled-up rows \u2014 use it to label levels rather than testing for NULL. Full detail: trilogy agent-info syntax example rollup.\n\n## Window functions\n\nDefault to windows for self-referential queries (period-over-period, running totals, rank, share of group). SQL-style syntax: `rank(<key>) over (partition by <g> order by <expr> desc)` (`dense_rank`/`row_number` same shape; multi-key `rank(a, b)`); `sum(x) over (partition by g order by t)` for running totals; `lag(<field>, <offset>) over (...)` / `lead(...)` for offsets (default 1). `partition by` is optional and accepts expressions.\n\n## Data types\n\nScalars: `string`, `bytes`, `bool`, `int`, `bigint`, `float`, `double`, `number`, `numeric(p,s)` (alias `decimal`; use for exact money), `date`, `datetime`, `timestamp`, `geography`, `any`. Composites: `array<T>`, `map<K, V>`, `struct<name: T, ...>`, `enum<T>[v1, v2, ...]`. Cast with `::type` or `cast(x as type)`: `\"2020-01-01\"::date`.\n\n`?` after a type marks it nullable (`property user.middle_name string?;`). `~` prefixing a concept marks the reference as a PARTIAL subset of the concept's domain \u2014 on a select item (`~customer.id`) or in `merge a into ~b` (a \u2286 b); it tells the planner this side is not authoritative.\n\n## Expression gotchas\n\n- `x ? cond` binds to a primary \u2014 wrap arithmetic: `(a - b) ? cond`, NOT `a - b ? cond`.\n- `a || b` is NULL if either side is NULL; `concat(...)` skips NULL arguments; `concat_ws(sep, ...)` joins with sep, skipping NULLs.\n- Date parts are unquoted: `date_part(d, year)`, never `'year'`; prefer `year(d)`. `date_diff(start, end, unit)` = end \u2212 start (a shipping lag is `date_diff(sold_date, ship_date, day)`).\n- Zero-argument functions still take parentheses: `current_date()`.\n- Factor repeated calculations into a `def` macro (invoked `@name(...)`) or reusable `auto` concepts.\n\n\nFunctions (the `aggregate` family doubles as the Aggregate Functions list):\naggregate: count|count_distinct|sum|max|min|avg|stddev|variance|array_agg|bool_or|bool_and|any|grouping(<arg1>) ; grouping_id(<arg1>, <arg2>, ..., <argN>)\nstring: concat|concat_strict|concat_ws(<arg1>, <arg2>, ..., <argN>) ; split|strpos|contains|trim|regexp_contains|format_time|parse_time(<arg1>, <arg2>) ; len|lower|upper|ltrim|rtrim|hex(<arg1>) ; substring|replace|regexp_extract|regexp_replace(<arg1>, <arg2>, <arg3>)\ndate/time: date|datetime|timestamp|second|minute|hour|day|day_of_week|week|month|quarter|year|month_name|day_name|unix_to_timestamp(<arg1>) ; date_spine(<arg1>, <arg2>) ; current_date|current_datetime()\n date_part(<arg1>, <arg2>) e.g. date_part('2020-01-01'::date, year)\n date_truncate(<arg1>, <arg2>) e.g. date_trunc('2020-01-01'::date, month)\n date_add(<arg1>, <arg2>, <arg3>) e.g. date_add('2020-01-01'::date, month, 1)\n date_sub(<arg1>, <arg2>, <arg3>) e.g. date_sub('2020-01-01'::date, day, 1)\n date_diff(<arg1>, <arg2>, <arg3>) e.g. date_diff('2020-01-01'::date, '2020-01-02'::date, day)\n current_timestamp() e.g. now()\narray/map/struct: unnest|array_distinct|array_sum|map_keys|map_values(<arg1>) ; struct|array(<arg1>, <arg2>, ..., <argN>) ; array_sort|array_to_string(<arg1>, <arg2>) ; array_transform|array_filter|generate_array(<arg1>, <arg2>, <arg3>)\nmath: mod|round|log|power|hash(<arg1>, <arg2>) ; abs|sqrt|random|floor|ceil(<arg1>)\nconditional/cast: case|simple_case|coalesce|greatest|least(<arg1>, <arg2>, ..., <argN>) ; cast|nullif(<arg1>, <arg2>) ; isnull(<arg1>)\ngeo: geo_from_text|geo_x|geo_y|geo_centroid(<arg1>) ; geo_point|geo_distance(<arg1>, <arg2>) ; geo_transform(<arg1>, <arg2>, <arg3>)\nother: is_not_distinct(<arg1>, <arg2>) ; prior(<arg1>) ; grain_pin(<arg1>, <arg2>, ..., <argN>)\n\nSome types carry trait metadata that adds meaning: 'latitude', 'longitude' and 'currency' are all 'float' with extra semantics.\n\nAdditional syntax examples:\nThese less-common patterns have complete, copy-pasteable examples. Do NOT guess\nthe syntax \u2014 print the full example on demand with\n`trilogy agent-info syntax example <name>`:\n- `python-datasource` - run a local Python script as a datasource: wrap a function in `trilogy.io.run`, which writes the Arrow IPC stream to stdout for you from a table, dataframe, or list of dicts; declare concepts, map script columns in `datasource (...)`, use `grain (...) file `path.py`;`, then reference locally declared concepts WITHOUT the datasource name as a prefix\n- `query-structure` - the exact clause order of a query, and how to define a rowset\n- `chart` - drawing a result rather than tabulating it: `chart layer <type> ( <role> <- <expr> as <name>, ... )` is a STATEMENT that wraps its own query - the bindings ARE the select; layers, roles, scales, reference lines and `from <select>`\n- `filtered-aggregate` - aggregating only the rows matching a condition, and counting rows correctly\n- `row-level-where-vs-having` - choosing between WHERE and HAVING for a threshold condition\n- `nested-aggregate-group-average` - the \"above 1.2x the group norm\" ask: inner `sum(x) by entity, group`, outer `avg(inner) by group`; use WHERE for the comparison when a separate output-only filter must not narrow the benchmark\n- `pivot-columns` - turn distinct values of a dimension into columns with a reusable `def` macro + filtered aggregate\n- `case-when` - `case when <cond> then <val> ... else <val> end` to relabel codes or bucket a measure into a derived value, then group by it\n- `window-period-over-period` - `lead`/`lag` over (order by ...) to compare a row to an offset period; build a scoped set with `<col> ? <cond>` and filter with `in`\n- `union-stack-channels` - stacking several sources/channels together as rows\n- `except-intersect-setops` - set difference or co-occurrence across sources\n- `scoped-join` - blending a second fact model or rowset into one query\n- `existence-anti-join` - keeping or excluding rows by whether a key matches another model\n- `set-intersect-difference` - count tuples present in / absent from other groups via per-group presence flags - the multi-column INTERSECT/EXCEPT idiom\n- `dedup-before-aggregate` - a `rowset <- select <cols>` collapses identical tuples to one row (SELECT-grain group by) before a downstream sum - the `distinct`/UNION substitute\n- `rollup` - subtotals and a grand total in one pass, and labeling the levels\n- `rank-over-rollup` - rank rollup subtotals/leaves with a SINGLE `rank(a,b) over (partition by level, parent ...)` - not separate ranks per level\n- `staged-membership` - filtering a fine-grain query by a set computed at a coarser grain\n- `correlated-exists-via-grouped-counts` - translate `EXISTS other` / `NOT EXISTS other matching` over the same model into two `count(...) by <grain>` compared in `where` (`> 1` = another exists, `= 1` = no other matches) - pin the correlation grain with `by`\n\nFor any response to the user, use this format -> put your actual response within triple double quotes with thinking and justification before it, in this format (replace placeholders with relevant content): Reasoning: {{reasoning}} \"\"\"{{ response }}\"\"\"\n";
|
|
3
|
+
export declare const leadIn = "You are a world-class assistant for generating queries in Trilogy, a SQL inspired language with similar syntax, Use the the syntax description below and field information to answer the user request. Return your answer with a short reasoning and a valid Trilogy query in triple double quotes.\n\n# Trilogy Syntax\n\nTrilogy statements define a semantic model or a query; collections of statements\nare written as `.preql` files. A statement returns data (SELECT) or defines\nconcepts (key | property | auto | metric), datasources, or parameters.\n\nimport <model> as <alias>; makes a model's fields available. <model> is a DOT-SEPARATED MODULE PATH relative to the project root (where trilogy.toml lives), never a file path: the file `raw/store_sales.preql` is imported as `import raw.store_sales as ss;` \u2014 replace each `/` with `.`, drop the `.preql`, keep the folder segment. When an imported model imports others (a fact with imported dimensions), those are dot paths: `enroll.student.name`. Typical usage imports ONE fact and reaches dimensions through it; nested dimensions carry ALL values (order.customers includes customers without orders).\n\nkey | property | auto | metric; define new concepts. `auto x <- ...` is a DEFINITION, not a precomputed value: each reference expands and re-evaluates in the consuming query's scope.\n\nparameter NAME TYPE [default <literal>]; \u2014 a runtime value supplied via `--param NAME=VALUE` (repeatable); append `?` to the type to allow null.\n\n## Combining models\n\n| Goal | Use |\n|---|---|\n| Typical query | no merge, no join: access all fields through dot-paths |\n| Blend two models on shared keys inside one query | scoped `subset\\|union\\|equal join` |\n| Make a connection universal to a whole file | `merge` |\n| Stack subsets/channels as rows | `union(...)` |\n| Rows in A but never in B (set difference) | `except(...)` |\n| Rows present in every source (set intersection) | `intersect(...)` |\n\n### Query-scoped join\n\nA typical fact already has its dimensions merged in, so no join is needed. Blending fact models or rowset outputs takes a scoped join, placed right after the select list, which DECLARES how the key domains relate: `subset join a = b` (a's values are contained in b's, a \u2286 b; b authoritative for the key), `union join a = b` (neither contains the other; the key is the coalesce of both sides and unmatched rows from BOTH sides are kept) or `equal join a = b` (ONE domain: a is an alias of b, every value on either side is on the other; the join renders inner).\n\nTwo rules decide whether the numbers are right, so apply them before reaching for the example:\n\n- Joins NEVER drop a row and NULL keys match null-safely; there is NO inner join. An intersection is an explicit `where <optional-side attr> is not null`.\n- JOIN ON THE FULL GRAIN: `explore` prints each fact's grain as @<k1, k2>; write one clause PER key. Matching only one key of a multi-key grain causes duplication.\n\nChaining, expression keys, union/subset mixing, multi-key and self-pair shapes: trilogy agent-info syntax example scoped-join.\n\n`merge subset a = b;`, `merge union a = b;` and `merge equal a = b;` are the persistent (whole-file) equivalents of the three scoped joins; `merge a into ~b;` and `merge a into b;` are older spellings of `merge subset` and `merge equal`. Standalone statements; prefer a scoped join unless the connection is universal. Use `merge union` when each side has keys the other lacks (orphaned parents, dimension rows with no facts): `merge a into b` declares one domain and drops the unmatched rows.\n\n### union / except / intersect (row set operations)\n\n`union(...)` row-stacks self-contained select arms positionally (SQL UNION ALL) into one named rowset (`with combined as union((armA), (armB), ...) -> (out1, out2, ...)`); `except(...)` / `intersect(...)` share that arm shape but are SQL SET operators (DISTINCT rows, null-safe whole-row compare, and except subtracts later arms from the FIRST, so arm order matters). Prefer except over a multi-column `not in` for \"in A but never in B\". Each arm dedups to its own output grain BEFORE stacking, so aggregate INSIDE each arm or the total silently undersums. Examples: trilogy agent-info syntax example union-stack-channels / except-intersect-setops.\n\n## Query structure\n\nTop-level statements first (each `;`-terminated), then a query with clauses in this EXACT order \u2014 all optional except select:\n\n```\n<top-level statements>; # import / key / auto / rowset / merge / def / parameter\nwith <name> as # optional: name the select as a reusable rowset (CTE)\nwhere <row condition> # 1. filters INPUT rows, BEFORE aggregation\nselect <col>, <agg> as name, # 2. projection \u2014 grouping is AUTOMATIC by the\n # non-aggregated columns; never write GROUP BY\n subset|union|equal join a = b (= c)? # 3. blend models; one clause per key, right after the select list\nby rollup|cube|grouping sets (...) # 4. optional multi-level grouping for the whole select\nhaving <result condition> # 5. filters aggregated/joined RESULTS\norder by <col> asc|desc # 6. sort\nlimit <n>; # 7. cap rows\n```\n\nA rowset (`with <name> as where ... select ...;`) is a standalone statement, evaluated in isolation \u2014 it does NOT respond to the consuming query's context. All its outputs are namespaced: output `abc.def` of rowset `foo` is referenced as `foo.abc.def`. Pairing an output with a concept outside the rowset REQUIRES a declared join on the rowset's key (`subset join foo.key = key`); without one the query is disconnected. Alternatively project the concept inside the rowset and filter or select it through the handle (`where foo.cat = 'a'`). Alias every reused expression with `as`.\n\nFull annotated example: trilogy agent-info syntax example query-structure.\n\n### Not SQL \u2014 what to never write\n\n- **No FROM, GROUP BY, DISTINCT, SELECT \\*, or SQL-style set operators between selects.** Stack rows with `union(...)`; set difference/intersection with `except(...)`/`intersect(...)`; blend fact models with a scoped join.\n- **Grouping is automatic** by the non-aggregated fields in the SELECT \u2014 never write GROUP BY. Aggregates inherit the select's grain wherever they appear (where/select/having). Override per-aggregate with `agg(x) by <dims>`; `by *` aggregates across all data (single row). To weight a related dimension property once per fact row, project it to the fact grain first: `auto row_birth_year <- group(enroll.student.birth_year) by enroll.student_id, enroll.course_id;` then aggregate that.\n- **Output rows are deduplicated to the select grain.** To preserve legitimate duplicates (one row per matching fact), include the fact's grain keys in the select \u2014 hidden with the PREFIX `--` if they shouldn't appear in the output.\n- **No `select distinct`.** `count(<key>)` is already distinct because keys are unique; `count(distinct(<property>))` counts distinct values of a non-key property. `distinct(x)` is `group(x) by x`: the distinct values of x, usable anywhere.\n- **Count a COMPOSITE grain with `grain(...)`.** `count(grain(order_id, item.id))` counts order+item combinations; `grain(...)` is NEVER NULL. Never count one column of a multi-key grain \u2014 a coarser key counts its own distinct values and undercounts.\n- **An aggregate over a group with no qualifying rows is NULL, never 0.** `sum(x ? cond) by k` yields NULL for groups where nothing matches, so `= 0` matches nothing. Test emptiness with `count(key ? cond) by k = 0` or wrap: `coalesce(sum(x ? cond), 0)`.\n- **A WHERE that leaves no rows returns no rows** - a grand total included: `where x > 100 select sum(x)` with nothing over 100 returns zero rows, not one NULL (or 0) row. The `?` filter is different: it narrows one aggregate's input, so the row still exists (`select count(k ? x > 100)` -> 0).\n- **Constants never count rows.** Aggregates resolve at the select grain, and a constant is one value per output row: `sum(1)` is 1 per group (`select state, sum(1)` -> 1 per state; `where ... select sum(1)` -> 1), and `count(1)` is rejected. To count rows, count a key (`count(ss.ticket_number)`), a composite row identity (`count(grain(a, b))`), or a filtered key (`count(k ? cond)`).\n- **One-column expression subqueries only.** `(select ...)` is allowed where a scalar or membership set is expected (exactly one projected column; a scalar must also be one row: an aggregate with no `by`, or `limit 1`) \u2014 never as a SQL-style FROM-subquery. For related-entity filters prefer the dot-path: `where enrollments.student.state = 'TN'`, not a subselect.\n- **`--` is a HIDDEN-field prefix, not a comment** (it still changes query structure). Comments use `#` only.\n- **Aliases**: always use the full dot-path (`enroll.student.id`); alias every new expression with `as`; a select alias is usable in `having`/`order by` but NOT inside other select expressions or `where`, and must not rename a field back to an existing concept name.\n\n## Filtering\n\n`where` filters input rows before aggregation; `having` filters results after aggregation/windows. The inline filter `x ? cond` filters the immediate prior expression: `sum(credits ? enrolled = true)`.\n\nAggregates/windows in WHERE do not filter each other's inputs. Use inline filters, or a staged `then where` chain: each `then where` stage's aggregates compute over only the rows passing earlier stages (`where x = 5 then where sum(y) > 10` \u2261 `where x = 5 and sum(y ? x = 5) > 10`). One rule: the SAME cross-row expression cannot gate two different stages \u2014 give one an inline filter.\n\nWindows need all rows in their range: filter AFTER the window (in `having`) rather than in `where` when the window must see the full set.\n\n## Membership (semijoins)\n\n`in` / `not in` cross models without any declared relationship \u2014 the semijoin IS a scoped intersection. The right side is a concept or expression (never a subselect); build computed sets with an inline filter: `auto big_zip <- student.zip ? (count(student.id ? student.honors = true) by student.zip) > 10; ... where school.zip in big_zip`.\n\nMembership is IDENTITY matching, not SQL three-valued logic: NULL matches NULL; the result is always TRUE or FALSE (safe as a projected flag); `not in` is the exact complement (a NULL in the set never empties the result). For strict SQL behavior, add `x is not null`.\n\nA fact model contains ALL dimensional members, so `where students.id not in enroll.student_id` is typically a tautology \u2014 use `where enroll.id is null` instead. Tuple membership `(a, b) in (m.a, m.b)` requires both right-side concepts to resolve to ONE source (model or rowset); to test against a cross-model pair, stage it through a rowset first. Examples: existence-anti-join, staged-membership.\n\n## Aggregation\n\nAn aggregate without an explicit `by` is RESPONSIVE \u2014 its grain is set where it is consumed, not where it is declared (`auto avg_credits <- avg(enroll.credits);` becomes per-department when selected with `enroll.department`). Pin a grain inline: `sum(metric) by dim1, dim2 as name`; `by` accepts bare identifiers or parenthesized expressions: `avg(price) by (substring(phone, 1, 2))`.\n\nMulti-level grouping (`by rollup|cube|grouping sets (...)`) is a clause of the WHOLE select, placed before `having`: it computes every no-explicit-grain aggregate at every level in one pass (`by rollup (d1, d2)` \u2192 leaf, per-d1 subtotal, grand total). `grouping(<field>)` = 1 on rolled-up rows \u2014 use it to label levels rather than testing for NULL. Full detail: trilogy agent-info syntax example rollup.\n\n## Window functions\n\nDefault to windows for self-referential queries (period-over-period, running totals, rank, share of group). SQL-style syntax: `rank(<key>) over (partition by <g> order by <expr> desc)` (`dense_rank`/`row_number` same shape; multi-key `rank(a, b)`); `sum(x) over (partition by g order by t)` for running totals; `lag(<field>, <offset>) over (...)` / `lead(...)` for offsets (default 1); these walk one row per key of the field (a property walks its key's rows), while `lag(distinct(<field>)) over (...)` walks the field's distinct values (`distinct(x)` = `group(x) by x`, usable anywhere). `partition by` is optional and accepts expressions.\n\n## Data types\n\nScalars: `string`, `bytes`, `bool`, `int`, `bigint`, `float`, `double`, `number`, `numeric(p,s)` (alias `decimal`; use for exact money), `date`, `datetime`, `timestamp`, `geography`, `any`. Composites: `array<T>`, `map<K, V>`, `struct<name: T, ...>`, `enum<T>[v1, v2, ...]`. Cast with `::type` or `cast(x as type)`: `\"2020-01-01\"::date`.\n\n`?` after a type marks it nullable (`property user.middle_name string?;`). `~` prefixing a concept marks the reference as a PARTIAL subset of the concept's domain \u2014 on a select item (`~customer.id`) or in `merge a into ~b` (a \u2286 b); it tells the planner this side is not authoritative.\n\n## Expression gotchas\n\n- `x ? cond` binds to a primary \u2014 wrap arithmetic: `(a - b) ? cond`, NOT `a - b ? cond`.\n- `a || b` is NULL if either side is NULL; `concat(...)` skips NULL arguments; `concat_ws(sep, ...)` joins with sep, skipping NULLs.\n- Date parts are unquoted: `date_part(d, year)`, never `'year'`; prefer `year(d)`. `date_diff(start, end, unit)` = end \u2212 start (a shipping lag is `date_diff(sold_date, ship_date, day)`).\n- Zero-argument functions still take parentheses: `current_date()`.\n- Factor repeated calculations into a `def` macro (invoked `@name(...)`) or reusable `auto` concepts.\n\n\nFunctions (the `aggregate` family doubles as the Aggregate Functions list):\naggregate: count|count_distinct|sum|max|min|avg|stddev|variance|array_agg|bool_or|bool_and|any|grouping(<arg1>) ; grouping_id(<arg1>, <arg2>, ..., <argN>)\nstring: concat|concat_strict|concat_ws(<arg1>, <arg2>, ..., <argN>) ; split|strpos|contains|trim|regexp_contains|format_time|parse_time(<arg1>, <arg2>) ; len|lower|upper|ltrim|rtrim|hex(<arg1>) ; substring|replace|regexp_extract|regexp_replace(<arg1>, <arg2>, <arg3>)\ndate/time: date|datetime|timestamp|second|minute|hour|day|day_of_week|week|month|quarter|year|month_name|day_name|unix_to_timestamp(<arg1>) ; date_spine(<arg1>, <arg2>) ; current_date|current_datetime()\n date_part(<arg1>, <arg2>) e.g. date_part('2020-01-01'::date, year)\n date_truncate(<arg1>, <arg2>) e.g. date_trunc('2020-01-01'::date, month)\n date_add(<arg1>, <arg2>, <arg3>) e.g. date_add('2020-01-01'::date, month, 1)\n date_sub(<arg1>, <arg2>, <arg3>) e.g. date_sub('2020-01-01'::date, day, 1)\n date_diff(<arg1>, <arg2>, <arg3>) e.g. date_diff('2020-01-01'::date, '2020-01-02'::date, day)\n current_timestamp() e.g. now()\narray/map/struct: unnest|array_distinct|array_sum|map_keys|map_values(<arg1>) ; struct|array(<arg1>, <arg2>, ..., <argN>) ; array_sort|array_to_string(<arg1>, <arg2>) ; array_transform|array_filter|generate_array(<arg1>, <arg2>, <arg3>)\nmath: mod|round|log|power|hash(<arg1>, <arg2>) ; abs|sqrt|random|floor|ceil(<arg1>)\nconditional/cast: case|simple_case|coalesce|greatest|least(<arg1>, <arg2>, ..., <argN>) ; cast|nullif(<arg1>, <arg2>) ; isnull(<arg1>)\ngeo: geo_from_text|geo_x|geo_y|geo_centroid(<arg1>) ; geo_point|geo_distance(<arg1>, <arg2>) ; geo_transform(<arg1>, <arg2>, <arg3>)\nother: is_not_distinct(<arg1>, <arg2>) ; prior(<arg1>) ; grain_pin(<arg1>, <arg2>, ..., <argN>)\n\nSome types carry trait metadata that adds meaning: 'latitude', 'longitude' and 'currency' are all 'float' with extra semantics.\n\nAdditional syntax examples:\nThese less-common patterns have complete, copy-pasteable examples. Do NOT guess\nthe syntax \u2014 print the full example on demand with\n`trilogy agent-info syntax example <name>`:\n- `python-datasource` - run a local Python script as a datasource: wrap a function in `trilogy.io.run`, which writes the Arrow IPC stream to stdout for you from a table, dataframe, or list of dicts; declare concepts, map script columns in `datasource (...)`, use `grain (...) file `path.py`;`, then reference locally declared concepts WITHOUT the datasource name as a prefix\n- `query-structure` - the exact clause order of a query, and how to define a rowset\n- `chart` - drawing a result rather than tabulating it: `chart layer <type> ( <role> <- <expr> as <name>, ... )` is a STATEMENT that wraps its own query - the bindings ARE the select; layers, roles, scales, reference lines and `from <select>`\n- `filtered-aggregate` - aggregating only the rows matching a condition, and counting rows correctly\n- `row-level-where-vs-having` - choosing between WHERE and HAVING for a threshold condition\n- `nested-aggregate-group-average` - the \"above 1.2x the group norm\" ask: inner `sum(x) by entity, group`, outer `avg(inner) by group`; use WHERE for the comparison when a separate output-only filter must not narrow the benchmark\n- `pivot-columns` - turn distinct values of a dimension into columns with a reusable `def` macro + filtered aggregate\n- `case-when` - `case when <cond> then <val> ... else <val> end` to relabel codes or bucket a measure into a derived value, then group by it\n- `window-period-over-period` - `lead`/`lag` over (order by ...) to compare a row to an offset period; build a scoped set with `<col> ? <cond>` and filter with `in`\n- `union-stack-channels` - stacking several sources/channels together as rows\n- `except-intersect-setops` - set difference or co-occurrence across sources\n- `scoped-join` - blending a second fact model or rowset into one query\n- `existence-anti-join` - keeping or excluding rows by whether a key matches another model\n- `set-intersect-difference` - count tuples present in / absent from other groups via per-group presence flags - the multi-column INTERSECT/EXCEPT idiom\n- `dedup-before-aggregate` - a `rowset <- select <cols>` collapses identical tuples to one row (SELECT-grain group by) before a downstream sum - the `distinct`/UNION substitute\n- `rollup` - subtotals and a grand total in one pass, and labeling the levels\n- `rank-over-rollup` - rank rollup subtotals/leaves with a SINGLE `rank(a,b) over (partition by level, parent ...)` - not separate ranks per level\n- `staged-membership` - filtering a fine-grain query by a set computed at a coarser grain\n- `correlated-exists-via-grouped-counts` - translate `EXISTS other` / `NOT EXISTS other matching` over the same model into two `count(...) by <grain>` compared in `where` (`> 1` = another exists, `= 1` = no other matches) - pin the correlation grain with `by`\n- `recursive-rollup` - walk a parent pointer (folder tree, org chart, process tree) to the top of each chain with `recurse_edge(key, parent)`, then aggregate per root\n\nFor any response to the user, use this format -> put your actual response within triple double quotes with thinking and justification before it, in this format (replace placeholders with relevant content): Reasoning: {{reasoning}} \"\"\"{{ response }}\"\"\"\n";
|
|
4
4
|
export declare function conceptsToFieldPrompt(conceptInputs: ModelConceptInput[]): string;
|
|
5
5
|
export declare function createPrompt(query: string, conceptInputs: ModelConceptInput[]): string;
|
|
6
6
|
export declare function createFilterPrompt(query: string, conceptInputs: ModelConceptInput[]): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../llm/data/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAIjD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,CAEzF;AAED,eAAO,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../llm/data/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAIjD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,CAEzF;AAED,eAAO,MAAM,MAAM,8rlBAKlB,CAAA;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,iBAAiB,EAAE,UAOvE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAG7E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAGnF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAGtF"}
|