@antelopejs/dms-ai 0.8.0 → 0.9.0
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 -1
- package/dist/pages/settings/sections.js +10 -0
- package/dist/pages/settings/sections.js.map +1 -1
- package/dist/routes/builder.d.ts +1 -1
- package/dist/routes/builder.js +3 -0
- package/dist/routes/builder.js.map +1 -1
- package/dist/vocabulary/tools.js +3 -0
- package/dist/vocabulary/tools.js.map +1 -1
- package/frontend-vue/app/chat/components/ChatView.vue +38 -37
- package/frontend-vue/app/chat/components/NoticeCard.vue +16 -0
- package/frontend-vue/app/chat/components/PanelHeader.vue +2 -6
- package/frontend-vue/app/chat/composables/conversation-events.ts +4 -0
- package/frontend-vue/app/chat/composables/useConversation.ts +6 -0
- package/frontend-vue/app/chat/types/protocol.ts +9 -1
- package/frontend-vue/app/chat/utils/status-label.ts +50 -0
- package/frontend-vue/app/chat/utils/tool-lexicon.ts +16 -0
- package/frontend-vue/app/plugins/ai.client.ts +2 -2
- package/frontend-vue/app/runtime/assistant-actions.ts +4 -2
- package/frontend-vue/app/runtime/assistant-session.ts +5 -1
- package/frontend-vue/app/runtime/block-health.ts +135 -0
- package/frontend-vue/app/runtime/constants.ts +1 -0
- package/frontend-vue/app/runtime/navigation-complete.ts +47 -6
- package/frontend-vue/app/runtime/panel-intents.ts +6 -2
- package/frontend-vue/i18n/locales/dms-ai-pages-en-GB.json +7 -0
- package/frontend-vue/i18n/locales/dms-ai-pages-fr-FR.json +7 -0
- package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +6 -1
- package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +6 -1
- package/frontend-vue/tests/assistant-actions.test.ts +37 -0
- package/frontend-vue/tests/block-health.test.ts +142 -0
- package/frontend-vue/tests/chat/conversation-events.test.ts +34 -0
- package/frontend-vue/tests/chat/tool-lexicon.test.ts +1 -0
- package/frontend-vue/tests/navigation.test.ts +67 -2
- package/frontend-vue/tests/support/panel-harness.ts +2 -2
- package/package.json +4 -4
- package/sidecar/dist/agent/provider.d.ts +5 -0
- package/sidecar/dist/agent/runner.d.ts +5 -0
- package/sidecar/dist/agent/runner.js +2 -0
- package/sidecar/dist/agent/runner.js.map +1 -1
- package/sidecar/dist/builder/builder-client.js +2 -2
- package/sidecar/dist/builder/builder-client.js.map +1 -1
- package/sidecar/dist/constants/builder.d.ts +2 -1
- package/sidecar/dist/constants/builder.js +12 -0
- package/sidecar/dist/constants/builder.js.map +1 -1
- package/sidecar/dist/constants/claude.d.ts +2 -0
- package/sidecar/dist/constants/claude.js +2 -0
- package/sidecar/dist/constants/claude.js.map +1 -1
- package/sidecar/dist/constants/mcp.d.ts +1 -1
- package/sidecar/dist/constants/mcp.js +1 -1
- package/sidecar/dist/constants/mcp.js.map +1 -1
- package/sidecar/dist/constants/native-binary.d.ts +5 -2
- package/sidecar/dist/constants/native-binary.js +5 -2
- package/sidecar/dist/constants/native-binary.js.map +1 -1
- package/sidecar/dist/constants/settings.d.ts +1 -0
- package/sidecar/dist/constants/settings.js +2 -0
- package/sidecar/dist/constants/settings.js.map +1 -1
- package/sidecar/dist/constants/timing.d.ts +1 -0
- package/sidecar/dist/constants/timing.js +1 -0
- package/sidecar/dist/constants/timing.js.map +1 -1
- package/sidecar/dist/constants/tool-kinds.js +1 -0
- package/sidecar/dist/constants/tool-kinds.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-compose.d.ts +51 -0
- package/sidecar/dist/mcp/tools/builder-compose.js +96 -0
- package/sidecar/dist/mcp/tools/builder-compose.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-project.js +54 -1
- package/sidecar/dist/mcp/tools/builder-project.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-queries.d.ts +31 -0
- package/sidecar/dist/mcp/tools/builder-queries.js +30 -13
- package/sidecar/dist/mcp/tools/builder-queries.js.map +1 -1
- package/sidecar/dist/mcp/tools/builder-table-view-schema.d.ts +99 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js +118 -0
- package/sidecar/dist/mcp/tools/builder-table-view-schema.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder-table-view.d.ts +102 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js +24 -0
- package/sidecar/dist/mcp/tools/builder-table-view.js.map +1 -0
- package/sidecar/dist/mcp/tools/builder.d.ts +135 -1
- package/sidecar/dist/mcp/tools/builder.js +17 -4
- package/sidecar/dist/mcp/tools/builder.js.map +1 -1
- package/sidecar/dist/mcp/tools/navigate-to-page.js +12 -4
- package/sidecar/dist/mcp/tools/navigate-to-page.js.map +1 -1
- package/sidecar/dist/pages/block-health.d.ts +14 -0
- package/sidecar/dist/pages/block-health.js +60 -0
- package/sidecar/dist/pages/block-health.js.map +1 -0
- package/sidecar/dist/prompts/agent.d.ts +1 -1
- package/sidecar/dist/prompts/agent.js +4 -3
- package/sidecar/dist/prompts/agent.js.map +1 -1
- package/sidecar/dist/protocol/events.d.ts +43 -0
- package/sidecar/dist/protocol/events.js +10 -0
- package/sidecar/dist/protocol/events.js.map +1 -1
- package/sidecar/dist/protocol/messages.d.ts +57 -0
- package/sidecar/dist/protocol/messages.js +22 -0
- package/sidecar/dist/protocol/messages.js.map +1 -1
- package/sidecar/dist/providers/claude/config.d.ts +16 -2
- package/sidecar/dist/providers/claude/config.js +17 -5
- package/sidecar/dist/providers/claude/config.js.map +1 -1
- package/sidecar/dist/providers/claude/model-fallback.d.ts +9 -0
- package/sidecar/dist/providers/claude/model-fallback.js +37 -0
- package/sidecar/dist/providers/claude/model-fallback.js.map +1 -0
- package/sidecar/dist/providers/claude/provider.js +23 -22
- package/sidecar/dist/providers/claude/provider.js.map +1 -1
- package/sidecar/dist/providers/claude/resolve-binary.js +18 -13
- package/sidecar/dist/providers/claude/resolve-binary.js.map +1 -1
- package/sidecar/dist/providers/claude/session-stream.d.ts +23 -0
- package/sidecar/dist/providers/claude/session-stream.js +58 -0
- package/sidecar/dist/providers/claude/session-stream.js.map +1 -0
- package/sidecar/dist/server/chat-events.js +1 -0
- package/sidecar/dist/server/chat-events.js.map +1 -1
- package/sidecar/dist/server/navigation-completer.d.ts +15 -2
- package/sidecar/dist/server/navigation-completer.js +42 -41
- package/sidecar/dist/server/navigation-completer.js.map +1 -1
- package/sidecar/dist/server/routing.js +11 -1
- package/sidecar/dist/server/routing.js.map +1 -1
- package/sidecar/dist/server/turns.js +8 -0
- package/sidecar/dist/server/turns.js.map +1 -1
- package/sidecar/dist/state/conversations.d.ts +1 -0
- package/sidecar/dist/state/conversations.js +8 -0
- package/sidecar/dist/state/conversations.js.map +1 -1
- package/sidecar/dist/state/settings-store.d.ts +1 -0
- package/sidecar/dist/state/settings-store.js +1 -0
- package/sidecar/dist/state/settings-store.js.map +1 -1
- package/sidecar/dist/state/settings-types.d.ts +1 -0
- package/sidecar/dist/state/types.d.ts +8 -1
- package/sidecar/dist/state/types.js.map +1 -1
- package/sidecar/package.json +2 -2
- package/skills/dms-builder-safe/REFERENCE.md +5 -6
- package/skills/dms-builder-safe/SKILL.md +12 -10
- package/skills/dms-external-database/REFERENCE.md +20 -8
- package/skills/dms-external-database/SKILL.md +64 -18
- package/skills/dms-page-design/SKILL.md +192 -0
- package/skills/dms-page-design/cases.json +57 -0
|
@@ -40,6 +40,7 @@ export const HELLO_MESSAGE_TYPE = "hello";
|
|
|
40
40
|
export const LOG_PREFIX = "[dms-ai]";
|
|
41
41
|
export const HOST_STATE_UPDATE_TYPE = "host_state_update";
|
|
42
42
|
export const HOST_NAVIGATION_COMPLETE_TYPE = "host_navigation_complete";
|
|
43
|
+
export const HOST_PAGE_BLOCKS_TYPE = "host_page_blocks";
|
|
43
44
|
export const HOST_COMMAND_NAVIGATE_TYPE = "host_command_navigate";
|
|
44
45
|
/** Frames of the tab's stream meant for the dashboard; every other one is the chat's. */
|
|
45
46
|
export const HOST_COMMAND_TYPES: ReadonlySet<string> = new Set([
|
|
@@ -1,22 +1,63 @@
|
|
|
1
1
|
import { router } from "@inertiajs/vue3";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
awaitSettledBlocks,
|
|
4
|
+
BLOCK_SETTLE_BUDGET_MS,
|
|
5
|
+
type PageBlocks,
|
|
6
|
+
} from "./block-health";
|
|
7
|
+
import {
|
|
8
|
+
HOST_NAVIGATION_COMPLETE_TYPE,
|
|
9
|
+
HOST_PAGE_BLOCKS_TYPE,
|
|
10
|
+
} from "./constants";
|
|
3
11
|
|
|
4
12
|
interface HostNavigationCompleteMessage {
|
|
5
13
|
type: typeof HOST_NAVIGATION_COMPLETE_TYPE;
|
|
6
14
|
path: string;
|
|
15
|
+
/** A `host_page_blocks` message for this path follows within this long. */
|
|
16
|
+
blocksWithinMs: number;
|
|
7
17
|
}
|
|
8
18
|
|
|
19
|
+
interface HostPageBlocksMessage extends PageBlocks {
|
|
20
|
+
type: typeof HOST_PAGE_BLOCKS_TYPE;
|
|
21
|
+
path: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type NavigationMessage = HostNavigationCompleteMessage | HostPageBlocksMessage;
|
|
25
|
+
|
|
9
26
|
interface InstallNavigationCompleteEmitterOptions {
|
|
10
|
-
send: (msg:
|
|
27
|
+
send: (msg: NavigationMessage) => void;
|
|
11
28
|
}
|
|
12
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Reports each completed visit at once, then what the page's data blocks
|
|
32
|
+
* showed once they settled, so the assistant learns of empty charts without
|
|
33
|
+
* a screenshot.
|
|
34
|
+
*/
|
|
13
35
|
export function installNavigationCompleteEmitter(
|
|
14
36
|
options: InstallNavigationCompleteEmitterOptions,
|
|
15
37
|
): () => void {
|
|
16
|
-
|
|
38
|
+
let settling = new AbortController();
|
|
39
|
+
let stopped = false;
|
|
40
|
+
const stopNavigation = router.on("navigate", (event) => {
|
|
41
|
+
const path = new URL(event.detail.page.url, window.location.origin)
|
|
42
|
+
.pathname;
|
|
43
|
+
settling.abort();
|
|
44
|
+
settling = new AbortController();
|
|
17
45
|
options.send({
|
|
18
46
|
type: HOST_NAVIGATION_COMPLETE_TYPE,
|
|
19
|
-
path
|
|
20
|
-
|
|
21
|
-
|
|
47
|
+
path,
|
|
48
|
+
blocksWithinMs: BLOCK_SETTLE_BUDGET_MS,
|
|
49
|
+
});
|
|
50
|
+
void awaitSettledBlocks({
|
|
51
|
+
root: document,
|
|
52
|
+
signal: settling.signal,
|
|
53
|
+
}).then((blocks) => {
|
|
54
|
+
if (!stopped)
|
|
55
|
+
options.send({ type: HOST_PAGE_BLOCKS_TYPE, path, ...blocks });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
stopped = true;
|
|
60
|
+
settling.abort();
|
|
61
|
+
stopNavigation();
|
|
62
|
+
};
|
|
22
63
|
}
|
|
@@ -7,11 +7,15 @@ interface OpenConversationIntent {
|
|
|
7
7
|
conversationId: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Opens the panel on a new conversation, in `mode` when given. The prompt is put in the composer,
|
|
12
|
+
* or sent as the first message when `send` is set.
|
|
13
|
+
*/
|
|
14
|
+
export interface StartConversationIntent {
|
|
12
15
|
kind: "start";
|
|
13
16
|
prompt?: string;
|
|
14
17
|
mode?: ConversationStartMode;
|
|
18
|
+
send?: boolean;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
/** Puts the caret in the composer of the current conversation. */
|
|
@@ -314,6 +314,8 @@
|
|
|
314
314
|
"BuilderPageStructure": "Read page",
|
|
315
315
|
"BuilderCreatePage": "Create page",
|
|
316
316
|
"BuilderConfigurePage": "Configure page",
|
|
317
|
+
"BuilderComposePage": "Compose page",
|
|
318
|
+
"BuilderConfigureTableView": "Configure table view",
|
|
317
319
|
"BuilderDeletePage": "Delete page",
|
|
318
320
|
"BuilderAddBlock": "Add block",
|
|
319
321
|
"BuilderConfigureBlock": "Configure block",
|
|
@@ -332,6 +334,7 @@
|
|
|
332
334
|
"BuilderRemoveField": "Remove field",
|
|
333
335
|
"BuilderQueryTemplates": "Read query templates",
|
|
334
336
|
"BuilderAddQuery": "Add query",
|
|
337
|
+
"BuilderPreviewQuery": "Preview query",
|
|
335
338
|
"BuilderConfigureQuery": "Configure query",
|
|
336
339
|
"BuilderRemoveQuery": "Remove query",
|
|
337
340
|
"UndoChangeSet": "Undo change set",
|
|
@@ -462,6 +465,10 @@
|
|
|
462
465
|
"high": "High"
|
|
463
466
|
}
|
|
464
467
|
},
|
|
468
|
+
"claude_model": {
|
|
469
|
+
"label": "Claude model",
|
|
470
|
+
"description": "The model Claude Code runs on. Thinking sets its reasoning effort."
|
|
471
|
+
},
|
|
465
472
|
"mode": {
|
|
466
473
|
"label": "Approval mode",
|
|
467
474
|
"description": "What the assistant may do without asking you first.",
|
|
@@ -314,6 +314,8 @@
|
|
|
314
314
|
"BuilderPageStructure": "Lire une page",
|
|
315
315
|
"BuilderCreatePage": "Créer une page",
|
|
316
316
|
"BuilderConfigurePage": "Configurer une page",
|
|
317
|
+
"BuilderComposePage": "Composer une page",
|
|
318
|
+
"BuilderConfigureTableView": "Configurer une vue tableau",
|
|
317
319
|
"BuilderDeletePage": "Supprimer une page",
|
|
318
320
|
"BuilderAddBlock": "Ajouter un bloc",
|
|
319
321
|
"BuilderConfigureBlock": "Configurer un bloc",
|
|
@@ -332,6 +334,7 @@
|
|
|
332
334
|
"BuilderRemoveField": "Retirer un champ",
|
|
333
335
|
"BuilderQueryTemplates": "Lire les modèles de requêtes",
|
|
334
336
|
"BuilderAddQuery": "Ajouter une requête",
|
|
337
|
+
"BuilderPreviewQuery": "Aperçu de la requête",
|
|
335
338
|
"BuilderConfigureQuery": "Configurer une requête",
|
|
336
339
|
"BuilderRemoveQuery": "Retirer une requête",
|
|
337
340
|
"UndoChangeSet": "Annuler un lot de modifications",
|
|
@@ -462,6 +465,10 @@
|
|
|
462
465
|
"high": "Élevée"
|
|
463
466
|
}
|
|
464
467
|
},
|
|
468
|
+
"claude_model": {
|
|
469
|
+
"label": "Modèle Claude",
|
|
470
|
+
"description": "Le modèle sur lequel tourne Claude Code. La réflexion règle son niveau d'effort."
|
|
471
|
+
},
|
|
465
472
|
"mode": {
|
|
466
473
|
"label": "Mode de validation",
|
|
467
474
|
"description": "Ce que l'assistant peut faire sans vous demander d'abord.",
|
|
@@ -142,7 +142,9 @@
|
|
|
142
142
|
"expired_title": "{tool} request expired.",
|
|
143
143
|
"expired_text": "“{summary}” was not answered in time, so it was denied at {time} and the assistant was told why.",
|
|
144
144
|
"question_skipped": "You let the assistant decide “{header}”.",
|
|
145
|
-
"full_auto_ended": "Full auto ended at {time}. The assistant asks first again."
|
|
145
|
+
"full_auto_ended": "Full auto ended at {time}. The assistant asks first again.",
|
|
146
|
+
"model_fallback_title": "Switched to {model}.",
|
|
147
|
+
"model_fallback_text": "The requested model, {requested}, was refused (unknown, or no access on this plan). This answer comes from {model}, the default model."
|
|
146
148
|
},
|
|
147
149
|
"errors": {
|
|
148
150
|
"turn_title": "The turn stopped.",
|
|
@@ -430,6 +432,8 @@
|
|
|
430
432
|
"configure_page": "Configure page",
|
|
431
433
|
"delete_page": "Delete page",
|
|
432
434
|
"add_block": "Add block",
|
|
435
|
+
"compose_page": "Compose page",
|
|
436
|
+
"configure_table_view": "Configure table view",
|
|
433
437
|
"configure_block": "Configure block",
|
|
434
438
|
"move_block": "Move block",
|
|
435
439
|
"remove_block": "Remove block",
|
|
@@ -446,6 +450,7 @@
|
|
|
446
450
|
"remove_field": "Remove field",
|
|
447
451
|
"browse_queries": "Browse query templates",
|
|
448
452
|
"add_query": "Add query",
|
|
453
|
+
"preview_query": "Preview query",
|
|
449
454
|
"configure_query": "Configure query",
|
|
450
455
|
"remove_query": "Remove query",
|
|
451
456
|
"search_tools": "Load tools",
|
|
@@ -142,7 +142,9 @@
|
|
|
142
142
|
"expired_title": "Demande « {tool} » expirée.",
|
|
143
143
|
"expired_text": "« {summary} » est restée sans réponse : elle a été refusée à {time} et l'assistant en a été informé.",
|
|
144
144
|
"question_skipped": "Vous avez laissé l'assistant décider pour « {header} ».",
|
|
145
|
-
"full_auto_ended": "Le mode automatique complet a pris fin à {time}. L'assistant redemande avant d'agir."
|
|
145
|
+
"full_auto_ended": "Le mode automatique complet a pris fin à {time}. L'assistant redemande avant d'agir.",
|
|
146
|
+
"model_fallback_title": "Passage à {model}.",
|
|
147
|
+
"model_fallback_text": "Le modèle demandé, {requested}, a été refusé (inconnu, ou sans accès avec cet abonnement). Cette réponse vient de {model}, le modèle par défaut."
|
|
146
148
|
},
|
|
147
149
|
"errors": {
|
|
148
150
|
"turn_title": "Le tour s'est arrêté.",
|
|
@@ -430,6 +432,8 @@
|
|
|
430
432
|
"configure_page": "Configurer la page",
|
|
431
433
|
"delete_page": "Supprimer la page",
|
|
432
434
|
"add_block": "Ajouter un bloc",
|
|
435
|
+
"compose_page": "Composer une page",
|
|
436
|
+
"configure_table_view": "Configurer la vue de tableau",
|
|
433
437
|
"configure_block": "Configurer le bloc",
|
|
434
438
|
"move_block": "Déplacer le bloc",
|
|
435
439
|
"remove_block": "Retirer le bloc",
|
|
@@ -446,6 +450,7 @@
|
|
|
446
450
|
"remove_field": "Retirer le champ",
|
|
447
451
|
"browse_queries": "Parcourir les modèles de requête",
|
|
448
452
|
"add_query": "Ajouter une requête",
|
|
453
|
+
"preview_query": "Aperçu de la requête",
|
|
449
454
|
"configure_query": "Configurer la requête",
|
|
450
455
|
"remove_query": "Retirer la requête",
|
|
451
456
|
"search_tools": "Charger des outils",
|
|
@@ -64,6 +64,43 @@ describe("the assistant actions another module's layer injects", () => {
|
|
|
64
64
|
]);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
it("send the prompt as the first message, in plan mode, when asked to", async () => {
|
|
68
|
+
const harness = createHarness();
|
|
69
|
+
const panel = await openPanel(harness);
|
|
70
|
+
publicAssistantActions(shallowRef(harness.session)).startConversation(
|
|
71
|
+
PROMPT,
|
|
72
|
+
{ mode: "plan", send: true },
|
|
73
|
+
);
|
|
74
|
+
await flushPromises();
|
|
75
|
+
const started = sentOfType(harness, "hello").at(-1)?.conversationId;
|
|
76
|
+
expect(sentOfType(harness, "set_conversation_mode")).toEqual([
|
|
77
|
+
expect.objectContaining({ conversationId: started, mode: "plan" }),
|
|
78
|
+
]);
|
|
79
|
+
expect(sentOfType(harness, "user_message")).toEqual([
|
|
80
|
+
expect.objectContaining({ content: PROMPT }),
|
|
81
|
+
]);
|
|
82
|
+
expect((panel.find("textarea").element as HTMLTextAreaElement).value).toBe(
|
|
83
|
+
"",
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("send the prompt once the stream is up, when the panel opens before it", async () => {
|
|
88
|
+
const harness = createHarness();
|
|
89
|
+
await openPanel(harness);
|
|
90
|
+
harness.setChannelStatus("disconnected");
|
|
91
|
+
publicAssistantActions(shallowRef(harness.session)).startConversation(
|
|
92
|
+
PROMPT,
|
|
93
|
+
{ send: true },
|
|
94
|
+
);
|
|
95
|
+
await flushPromises();
|
|
96
|
+
expect(sentOfType(harness, "user_message")).toEqual([]);
|
|
97
|
+
harness.setChannelStatus("connected");
|
|
98
|
+
await flushPromises();
|
|
99
|
+
expect(sentOfType(harness, "user_message")).toEqual([
|
|
100
|
+
expect.objectContaining({ content: PROMPT }),
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
67
104
|
it("are unavailable without a session, and starting then does nothing", () => {
|
|
68
105
|
const actions = publicAssistantActions(shallowRef(null));
|
|
69
106
|
expect(actions.isAvailable).toBe(false);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
BLOCK_SETTLE_BUDGET_MS,
|
|
5
|
+
awaitSettledBlocks,
|
|
6
|
+
readBlocks,
|
|
7
|
+
} from "../app/runtime/block-health";
|
|
8
|
+
|
|
9
|
+
function addBlock(
|
|
10
|
+
state: string,
|
|
11
|
+
type: string,
|
|
12
|
+
path?: string,
|
|
13
|
+
parent: Element = document.body,
|
|
14
|
+
): HTMLElement {
|
|
15
|
+
const element = document.createElement("div");
|
|
16
|
+
element.setAttribute("data-dms-block-state", state);
|
|
17
|
+
element.setAttribute("data-dms-block-type", type);
|
|
18
|
+
if (path !== undefined) element.setAttribute("data-dms-block", path);
|
|
19
|
+
parent.append(element);
|
|
20
|
+
return element;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const never = new AbortController().signal;
|
|
24
|
+
|
|
25
|
+
describe("readBlocks", () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
document.body.replaceChildren();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("reads the state, kind and layout path each block states on its root", () => {
|
|
31
|
+
addBlock("empty", "ChartCard", "revenue");
|
|
32
|
+
addBlock("ok", "KpiCard");
|
|
33
|
+
document.body.append(document.createElement("section"));
|
|
34
|
+
expect(readBlocks(document)).toEqual([
|
|
35
|
+
{ path: "revenue", type: "ChartCard", state: "empty" },
|
|
36
|
+
{ type: "KpiCard", state: "ok" },
|
|
37
|
+
]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("finds none on a host that states nothing", () => {
|
|
41
|
+
document.body.append(document.createElement("section"));
|
|
42
|
+
expect(readBlocks(document)).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("awaitSettledBlocks", () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
document.body.replaceChildren();
|
|
49
|
+
vi.useFakeTimers();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
vi.useRealTimers();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("reports the blocks showing no data once the page stopped changing", async () => {
|
|
57
|
+
addBlock("ok", "KpiCard", "orders");
|
|
58
|
+
addBlock("empty", "ChartCard", "revenue");
|
|
59
|
+
addBlock("error", "TopListCard", "top");
|
|
60
|
+
const settled = awaitSettledBlocks({ root: document, signal: never });
|
|
61
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS);
|
|
62
|
+
await expect(settled).resolves.toEqual({
|
|
63
|
+
status: "settled",
|
|
64
|
+
checked: 3,
|
|
65
|
+
blocks: [
|
|
66
|
+
{ path: "revenue", type: "ChartCard", state: "empty" },
|
|
67
|
+
{ path: "top", type: "TopListCard", state: "error" },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("waits for a loading block and reports what it turned into", async () => {
|
|
73
|
+
const chart = addBlock("loading", "ChartCard", "revenue");
|
|
74
|
+
let result: Awaited<ReturnType<typeof awaitSettledBlocks>> | undefined;
|
|
75
|
+
void awaitSettledBlocks({ root: document, signal: never }).then((value) => {
|
|
76
|
+
result = value;
|
|
77
|
+
});
|
|
78
|
+
await vi.advanceTimersByTimeAsync(4_000);
|
|
79
|
+
expect(result).toBeUndefined();
|
|
80
|
+
chart.setAttribute("data-dms-block-state", "empty");
|
|
81
|
+
await vi.advanceTimersByTimeAsync(4_000);
|
|
82
|
+
expect(result).toEqual({
|
|
83
|
+
status: "settled",
|
|
84
|
+
checked: 1,
|
|
85
|
+
blocks: [{ path: "revenue", type: "ChartCard", state: "empty" }],
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("waits for a block that mounts after the others settled", async () => {
|
|
90
|
+
addBlock("ok", "KpiCard", "orders");
|
|
91
|
+
const settled = awaitSettledBlocks({ root: document, signal: never });
|
|
92
|
+
await vi.advanceTimersByTimeAsync(300);
|
|
93
|
+
addBlock("loading", "ChartCard", "late");
|
|
94
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS);
|
|
95
|
+
await expect(settled).resolves.toMatchObject({
|
|
96
|
+
status: "timeout",
|
|
97
|
+
checked: 2,
|
|
98
|
+
blocks: [{ path: "late", type: "ChartCard", state: "loading" }],
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("gives up at the budget and names the blocks still loading", async () => {
|
|
103
|
+
addBlock("loading", "Chart", "slow");
|
|
104
|
+
let finishedAt = -1;
|
|
105
|
+
const started = Date.now();
|
|
106
|
+
const settled = awaitSettledBlocks({ root: document, signal: never });
|
|
107
|
+
void settled.then(() => {
|
|
108
|
+
finishedAt = Date.now() - started;
|
|
109
|
+
});
|
|
110
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS - 1);
|
|
111
|
+
expect(finishedAt).toBe(-1);
|
|
112
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
113
|
+
await expect(settled).resolves.toEqual({
|
|
114
|
+
status: "timeout",
|
|
115
|
+
checked: 1,
|
|
116
|
+
blocks: [{ path: "slow", type: "Chart", state: "loading" }],
|
|
117
|
+
});
|
|
118
|
+
expect(finishedAt).toBe(BLOCK_SETTLE_BUDGET_MS);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("reports a page without data blocks as having none", async () => {
|
|
122
|
+
const settled = awaitSettledBlocks({ root: document, signal: never });
|
|
123
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS);
|
|
124
|
+
await expect(settled).resolves.toEqual({
|
|
125
|
+
status: "settled",
|
|
126
|
+
checked: 0,
|
|
127
|
+
blocks: [],
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("answers at once as superseded when another navigation starts", async () => {
|
|
132
|
+
addBlock("loading", "Chart", "slow");
|
|
133
|
+
const controller = new AbortController();
|
|
134
|
+
const settled = awaitSettledBlocks({
|
|
135
|
+
root: document,
|
|
136
|
+
signal: controller.signal,
|
|
137
|
+
});
|
|
138
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
139
|
+
controller.abort();
|
|
140
|
+
await expect(settled).resolves.toMatchObject({ status: "superseded" });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -220,6 +220,40 @@ describe("the conversation folds the redesign's events", () => {
|
|
|
220
220
|
expect(conversation.totalTokens.value).toBe(1_200);
|
|
221
221
|
});
|
|
222
222
|
|
|
223
|
+
it("shows the model that answered, from a usage event or a snapshot", () => {
|
|
224
|
+
const b = bus();
|
|
225
|
+
const conversation = useConversation(b.options as never);
|
|
226
|
+
expect(conversation.model.value).toBeNull();
|
|
227
|
+
b.receive({ type: "usage", totalTokens: 10, model: "claude-opus-5-5" });
|
|
228
|
+
expect(conversation.model.value).toBe("claude-opus-5-5");
|
|
229
|
+
b.receive({
|
|
230
|
+
type: "conversation_snapshot",
|
|
231
|
+
messages: [],
|
|
232
|
+
changeSets: [],
|
|
233
|
+
totalTokens: 10,
|
|
234
|
+
model: "claude-sonnet-4-6",
|
|
235
|
+
});
|
|
236
|
+
expect(conversation.model.value).toBe("claude-sonnet-4-6");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("keeps the notice that the configured model was refused", () => {
|
|
240
|
+
const b = bus();
|
|
241
|
+
const conversation = useConversation(b.options as never);
|
|
242
|
+
b.receive({
|
|
243
|
+
type: "notice",
|
|
244
|
+
notice: {
|
|
245
|
+
kind: "model_fallback",
|
|
246
|
+
requestedModel: "claude-opus-5-5",
|
|
247
|
+
usedModel: "claude-sonnet-4-6",
|
|
248
|
+
timestampMs: 7,
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
expect(conversation.messages.value[0]).toMatchObject({
|
|
252
|
+
role: "notice",
|
|
253
|
+
notice: { kind: "model_fallback", usedModel: "claude-sonnet-4-6" },
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
223
257
|
it("ignores another conversation's events", () => {
|
|
224
258
|
const b = bus();
|
|
225
259
|
const conversation = useConversation(b.options as never);
|
|
@@ -68,6 +68,7 @@ describe("the tool lexicon names a call by what it does", () => {
|
|
|
68
68
|
"BuilderRemoveField",
|
|
69
69
|
"BuilderRemoveQuery",
|
|
70
70
|
"BuilderQueryTemplates",
|
|
71
|
+
"BuilderPreviewQuery",
|
|
71
72
|
];
|
|
72
73
|
for (const name of [...builder, "AskUser", "Typecheck", "NavigateToPage"])
|
|
73
74
|
expect(describeTool(`mcp__dms-ai__${name}`, {}).verbKey).not.toBeNull();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { installCurrentPageTracker } from "../app/runtime/current-page";
|
|
4
|
+
import { BLOCK_SETTLE_BUDGET_MS } from "../app/runtime/block-health";
|
|
4
5
|
import { installNavigationCompleteEmitter } from "../app/runtime/navigation-complete";
|
|
5
6
|
|
|
6
7
|
function navigate(url: string): void {
|
|
@@ -61,7 +62,7 @@ describe("Inertia host navigation", () => {
|
|
|
61
62
|
document.title = "";
|
|
62
63
|
});
|
|
63
64
|
|
|
64
|
-
it("emits completion
|
|
65
|
+
it("emits completion at once after navigation, announcing the block report, and removes its event listener", () => {
|
|
65
66
|
const send = vi.fn();
|
|
66
67
|
const stop = installNavigationCompleteEmitter({ send });
|
|
67
68
|
expect(send).not.toHaveBeenCalled();
|
|
@@ -69,9 +70,73 @@ describe("Inertia host navigation", () => {
|
|
|
69
70
|
expect(send).toHaveBeenCalledExactlyOnceWith({
|
|
70
71
|
type: "host_navigation_complete",
|
|
71
72
|
path: "/finished",
|
|
73
|
+
blocksWithinMs: BLOCK_SETTLE_BUDGET_MS,
|
|
72
74
|
});
|
|
73
75
|
stop();
|
|
74
76
|
navigate("/ignored");
|
|
75
77
|
expect(send).toHaveBeenCalledTimes(1);
|
|
76
78
|
});
|
|
79
|
+
|
|
80
|
+
describe("block report", () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
document.body.replaceChildren();
|
|
83
|
+
vi.useFakeTimers();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
vi.useRealTimers();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function addChart(state: string): HTMLElement {
|
|
91
|
+
const element = document.createElement("div");
|
|
92
|
+
element.setAttribute("data-dms-block-state", state);
|
|
93
|
+
element.setAttribute("data-dms-block-type", "ChartCard");
|
|
94
|
+
element.setAttribute("data-dms-block", "revenue");
|
|
95
|
+
document.body.append(element);
|
|
96
|
+
return element;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
it("follows the completion with the blocks showing no data", async () => {
|
|
100
|
+
addChart("empty");
|
|
101
|
+
const send = vi.fn();
|
|
102
|
+
const stop = installNavigationCompleteEmitter({ send });
|
|
103
|
+
navigate("/sales");
|
|
104
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS);
|
|
105
|
+
expect(send).toHaveBeenLastCalledWith({
|
|
106
|
+
type: "host_page_blocks",
|
|
107
|
+
path: "/sales",
|
|
108
|
+
status: "settled",
|
|
109
|
+
checked: 1,
|
|
110
|
+
blocks: [{ path: "revenue", type: "ChartCard", state: "empty" }],
|
|
111
|
+
});
|
|
112
|
+
stop();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("reports the first page as superseded when a second navigation starts", async () => {
|
|
116
|
+
addChart("loading");
|
|
117
|
+
const send = vi.fn();
|
|
118
|
+
const stop = installNavigationCompleteEmitter({ send });
|
|
119
|
+
navigate("/first");
|
|
120
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
121
|
+
navigate("/second");
|
|
122
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
123
|
+
expect(send).toHaveBeenCalledWith(
|
|
124
|
+
expect.objectContaining({
|
|
125
|
+
type: "host_page_blocks",
|
|
126
|
+
path: "/first",
|
|
127
|
+
status: "superseded",
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
stop();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("reports nothing once stopped", async () => {
|
|
134
|
+
const send = vi.fn();
|
|
135
|
+
const stop = installNavigationCompleteEmitter({ send });
|
|
136
|
+
navigate("/sales");
|
|
137
|
+
stop();
|
|
138
|
+
await vi.advanceTimersByTimeAsync(BLOCK_SETTLE_BUDGET_MS);
|
|
139
|
+
expect(send).toHaveBeenCalledTimes(1);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
77
142
|
});
|
|
@@ -94,8 +94,8 @@ export function createHarness(): Harness {
|
|
|
94
94
|
intents.push({ kind: "open", conversationId });
|
|
95
95
|
panel.open();
|
|
96
96
|
},
|
|
97
|
-
startConversation: (prompt, mode) => {
|
|
98
|
-
intents.push({ kind: "start", prompt, mode });
|
|
97
|
+
startConversation: (prompt, mode, send) => {
|
|
98
|
+
intents.push({ kind: "start", prompt, mode, send });
|
|
99
99
|
panel.open();
|
|
100
100
|
},
|
|
101
101
|
holdStream: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "AI development assistant for the AntelopeJS DMS: a chat panel next to every page and a coding agent that edits the project in reviewable, undoable change sets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"@antelopejs/interface-api": ">=0.0.15 <1.0.0",
|
|
80
80
|
"@antelopejs/interface-core": ">=0.2.4 <1.0.0",
|
|
81
81
|
"@antelopejs/interface-dms": ">=0.9.0 <1.0.0",
|
|
82
|
-
"@anthropic-ai/claude-agent-sdk": "^0.
|
|
83
|
-
"@anthropic-ai/claude-code": "^2.1.
|
|
82
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.316",
|
|
83
|
+
"@anthropic-ai/claude-code": "^2.1.316",
|
|
84
84
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
85
85
|
"ws": "^8.18.0",
|
|
86
86
|
"zod": "^4.0.0"
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
},
|
|
111
111
|
"optionalDependencies": {
|
|
112
112
|
"@antelopejs/interface-database-catalog": ">=0.0.1 <1.0.0",
|
|
113
|
-
"@antelopejs/interface-dms-builder": ">=0.
|
|
113
|
+
"@antelopejs/interface-dms-builder": ">=0.3.0 <1.0.0"
|
|
114
114
|
},
|
|
115
115
|
"packageManager": "pnpm@10.2.0",
|
|
116
116
|
"antelopeJs": {
|
|
@@ -30,6 +30,11 @@ export interface ProviderSessionContext extends ToolCallHooks {
|
|
|
30
30
|
permissionBus?: PermissionBus;
|
|
31
31
|
mcpServer?: AiMcpServer;
|
|
32
32
|
onTokenUsage?: (usage: TokenUsage) => void;
|
|
33
|
+
onModelUsed?: (model: string) => void;
|
|
34
|
+
onModelFallback?: (fallback: {
|
|
35
|
+
requested: string;
|
|
36
|
+
used: string;
|
|
37
|
+
}) => void;
|
|
33
38
|
onDisposed: (disposal: Promise<void>) => void;
|
|
34
39
|
}
|
|
35
40
|
export interface ProviderSession {
|
|
@@ -15,6 +15,11 @@ export interface RunnerContext extends ToolCallHooks {
|
|
|
15
15
|
permissionBus?: PermissionBus;
|
|
16
16
|
createMcpServer?: () => AiMcpServer;
|
|
17
17
|
onTokenUsage?: (usage: TokenUsage) => void;
|
|
18
|
+
onModelUsed?: (model: string) => void;
|
|
19
|
+
onModelFallback?: (fallback: {
|
|
20
|
+
requested: string;
|
|
21
|
+
used: string;
|
|
22
|
+
}) => void;
|
|
18
23
|
}
|
|
19
24
|
export interface AgentRunner {
|
|
20
25
|
start(message: string, ctx: RunnerContext): AsyncIterable<RunnerEvent>;
|
|
@@ -22,6 +22,8 @@ function createSession(manager, ctx) {
|
|
|
22
22
|
onToolAnnounced: ctx.onToolAnnounced,
|
|
23
23
|
beforeMutation: ctx.beforeMutation,
|
|
24
24
|
onTokenUsage: ctx.onTokenUsage,
|
|
25
|
+
onModelUsed: ctx.onModelUsed,
|
|
26
|
+
onModelFallback: ctx.onModelFallback,
|
|
25
27
|
onDisposed: (disposal) => {
|
|
26
28
|
manager.sessions.delete(ctx.conversationId);
|
|
27
29
|
manager.disposals.track(disposal);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAM5D,OAAO,EAAE,qBAAqB,EAAwB,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAavD,MAAM,YAAY,GAAgB,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAM5D,OAAO,EAAE,qBAAqB,EAAwB,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAavD,MAAM,YAAY,GAAgB,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC;AA6EvE,SAAS,UAAU,CAAC,OAAuB,EAAE,cAAsB;IACjE,OAAO,OAAO,CAAC,eAAe,CAAC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,kBAAkB,CACzB,eAAuB,EACvB,QAAqB;IAErB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CACpB,OAAuB,EACvB,GAAkB;IAElB,OAAO,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;QACpC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC;QACjD,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,SAAS,EAAE,GAAG,CAAC,eAAe,EAAE,EAAE;QAClC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE;YACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5C,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,KAAU,CAAC;AAEjC,KAAK,UAAU,WAAW,CACxB,OAAuB,EACvB,GAAkB;IAElB,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CACzB,OAAuB,EACvB,GAAkB;IAElB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC1D,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7D,IAAI,OAAO,CAAC,QAAQ;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IACpE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,SAAS,CAAC,CAAC,SAAS,CACvB,OAAuB,EACvB,OAAe,EACf,GAAkB;IAElB,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,kBAAkB,CACjC,OAAO,EACP,GAAG,CAAC,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,EAAE,EACtE,uBAAuB,CAAC,QAAQ,CAAC,cAAc,CAAC,CACjD,CAAC;IACF,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CACpB,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,EAAE,EACtD,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAuB,EACvB,cAAsB;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO;IAClC,OAAO,CAAC,SAAS,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,cAAc,CACrB,OAAuB,EACvB,cAAsB;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IACnC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,OAAuB,EACvB,MAAoB;IAEpB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IACxB,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;AACnC,CAAC;AAED,SAAS,aAAa,CAAC,OAAuB,EAAE,QAAqB;IACnE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC5B,KAAK,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzD,OAAO,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAuB,EAAE,cAAsB;IACrE,OAAO,CAAC,QAAQ;SACb,GAAG,CAAC,cAAc,CAAC;QACpB,EAAE,aAAa,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAAuB,EACvB,OAA4B;IAE5B,MAAM,OAAO,GAAmB;QAC9B,QAAQ;QACR,QAAQ,EAAE,IAAI,GAAG,EAAE;QACnB,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,gBAAgB;QAC/C,eAAe,EAAE,OAAO,EAAE,eAAe,IAAI,kBAAkB;QAC/D,SAAS,EAAE,qBAAqB,EAAE;QAClC,QAAQ,EAAE,KAAK;KAChB,CAAC;IACF,OAAO;QACL,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC;QACzD,gBAAgB,EAAE,CAAC,cAAc,EAAE,EAAE,CACnC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC;QAC3C,cAAc,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC;QAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC;QAC7D,cAAc,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC;QAC3E,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;KACjD,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BUILDER_FETCH_TIMEOUT_MS, BUILDER_LOG_PREFIX, BUILDER_OP_PATH, } from "../constants/builder.js";
|
|
1
|
+
import { BUILDER_FETCH_TIMEOUT_MS, BUILDER_SLOW_OP_TIMEOUTS_MS, BUILDER_LOG_PREFIX, BUILDER_OP_PATH, } from "../constants/builder.js";
|
|
2
2
|
import { SIDECAR_AUTH_HEADER } from "../constants/daemon.js";
|
|
3
3
|
import { JsonValueSchema } from "../protocol/json.js";
|
|
4
4
|
const JSON_HEADERS = { "content-type": "application/json" };
|
|
@@ -15,7 +15,7 @@ export function createBuilderClient(opts) {
|
|
|
15
15
|
return {
|
|
16
16
|
call: async (op, args) => {
|
|
17
17
|
const controller = new AbortController();
|
|
18
|
-
const timer = setTimeout(() => controller.abort(), BUILDER_FETCH_TIMEOUT_MS);
|
|
18
|
+
const timer = setTimeout(() => controller.abort(), BUILDER_SLOW_OP_TIMEOUTS_MS.get(op) ?? BUILDER_FETCH_TIMEOUT_MS);
|
|
19
19
|
try {
|
|
20
20
|
const response = await fetchImpl(url, {
|
|
21
21
|
method: "POST",
|