@datalayer/agent-runtimes 1.3.59 → 1.3.60
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/lib/chat/ChatFloating.d.ts +11 -1
- package/lib/chat/ChatFloating.js +6 -2
- package/lib/chat/assistant/AssistantStage.d.ts +7 -1
- package/lib/chat/assistant/AssistantStage.js +5 -3
- package/lib/chat/assistant/DecisionAsk.d.ts +31 -0
- package/lib/chat/assistant/DecisionAsk.js +96 -0
- package/lib/chat/assistant/SpeechBalloon.d.ts +11 -2
- package/lib/chat/assistant/SpeechBalloon.js +5 -4
- package/lib/chat/assistant/decisions.d.ts +104 -0
- package/lib/chat/assistant/decisions.js +161 -0
- package/lib/chat/marks/toolMarks.js +2 -2
- package/lib/config/AgentConfiguration.d.ts +2 -1
- package/lib/config/AgentConfiguration.js +2 -2
- package/lib/examples/AgentDecideExample.d.ts +24 -0
- package/lib/examples/AgentDecideExample.js +73 -0
- package/lib/examples/AgentNotificationsExample.js +1 -1
- package/lib/examples/AgentSkillsExample.js +1 -1
- package/lib/examples/AgentspecsExample.js +3 -3
- package/lib/examples/example-selector.js +1 -0
- package/lib/examples/index.d.ts +1 -0
- package/lib/examples/index.js +1 -0
- package/lib/examples/main.js +3 -0
- package/lib/loop/apps/appspec.js +4 -4
- package/lib/loop/apps/checks.js +6 -6
- package/lib/loop/apps/rules.js +2 -2
- package/lib/loop/plugins/assistant/index.d.ts +14 -2
- package/lib/loop/plugins/assistant/index.js +13 -4
- package/lib/specs/actions.d.ts +1 -1
- package/lib/specs/actions.js +1 -1
- package/lib/specs/agents/agents.js +197 -192
- package/lib/specs/apps.js +13 -13
- package/lib/specs/appspecSchema.js +3 -3
- package/lib/specs/backendTools.d.ts +31 -0
- package/lib/specs/{tools.js → backendTools.js} +48 -48
- package/lib/specs/cogs.js +8 -7
- package/lib/specs/frames.js +5 -5
- package/lib/specs/index.d.ts +1 -1
- package/lib/specs/index.js +1 -1
- package/lib/stores/agentRuntimeStore.js +2 -2
- package/lib/types/agentspecs.d.ts +7 -5
- package/lib/types/config.d.ts +2 -2
- package/lib/types/tools.d.ts +3 -3
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +23 -12
- package/scripts/codegen/generate_apps.py +3 -2
- package/scripts/codegen/{generate_tools.py → generate_backend_tools.py} +29 -29
- package/scripts/codegen/generate_cogs.py +2 -2
- package/scripts/codegen/generate_frames.py +2 -2
- package/lib/specs/tools.d.ts +0 -31
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Decide: typed decisions asked of Jev (`cloudflare:wrk/typesafe/jev`), the
|
|
8
|
+
* typed-decision model, from the chat and from the floating assistant.
|
|
9
|
+
*
|
|
10
|
+
* The *Decide* application of the catalogue (agentspecs `apps/decide.yaml`)
|
|
11
|
+
* in the LOOP workspace, on the Local target: its agent — `example-simple`
|
|
12
|
+
* with the `decide` tool — runs on the local agent-runtimes server, and
|
|
13
|
+
* answers a question about a text by asking a typed decision. The floating
|
|
14
|
+
* assistant beside it offers *Ask a decision* in its balloon: the situation,
|
|
15
|
+
* the question and its type, asked through the same server's
|
|
16
|
+
* `/api/v1/configure/inference/decisions`, the route that asks as `decide`
|
|
17
|
+
* does, with the same token.
|
|
18
|
+
*
|
|
19
|
+
* The server needs ai-inference: start it with
|
|
20
|
+
* `AGENT_RUNTIMES_INFERENCE_PROVIDER_OVERRIDE=datalayer`,
|
|
21
|
+
* `DATALAYER_AI_INFERENCE_URL=https://r1.datalayer.run` and
|
|
22
|
+
* `DATALAYER_AI_INFERENCE_API_KEY` set from `DATALAYER_API_KEY`. Another
|
|
23
|
+
* server than `http://localhost:8765` is named with `?agentRuntimesUrl=`.
|
|
24
|
+
*
|
|
25
|
+
* @module examples/AgentDecideExample
|
|
26
|
+
*/
|
|
27
|
+
import { useMemo } from 'react';
|
|
28
|
+
import { configurePlugin } from '@datalayer/reactor';
|
|
29
|
+
import { Heading, Text } from '@primer/react';
|
|
30
|
+
import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
|
|
31
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
32
|
+
import { resolveExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
|
|
33
|
+
import { AppRenderer, appDatalayerCreatePayload, } from '../loop/apps/AppRenderer';
|
|
34
|
+
import { AssistantCharactersPlugin } from '../loop/plugins/assistant-characters';
|
|
35
|
+
import { LoopAssistantPlugin } from '../loop/plugins/assistant';
|
|
36
|
+
import { APP_CATALOGUE } from '../specs/apps';
|
|
37
|
+
setupPrimerPortals();
|
|
38
|
+
/** The local server: `?agentRuntimesUrl=` when given, else the examples' own. */
|
|
39
|
+
function serverUrlOf() {
|
|
40
|
+
const named = typeof window === 'undefined'
|
|
41
|
+
? null
|
|
42
|
+
: new URLSearchParams(window.location.search).get('agentRuntimesUrl');
|
|
43
|
+
return resolveExampleAgentRuntimesUrl('local', named ?? undefined);
|
|
44
|
+
}
|
|
45
|
+
const AgentDecideExample = () => {
|
|
46
|
+
const app = APP_CATALOGUE['decide'];
|
|
47
|
+
const serverUrl = useMemo(serverUrlOf, []);
|
|
48
|
+
// Made once: a new plugin on a render restarts the workspace.
|
|
49
|
+
const plugins = useMemo(() => [
|
|
50
|
+
AssistantCharactersPlugin,
|
|
51
|
+
configurePlugin(LoopAssistantPlugin, {
|
|
52
|
+
app: app.interface.assistant ?? undefined,
|
|
53
|
+
decisions: { serverUrl },
|
|
54
|
+
}),
|
|
55
|
+
], [app, serverUrl]);
|
|
56
|
+
// The Local agent is the application's: created under its id with its
|
|
57
|
+
// spec, so that the server runs its instructions, its tool and its rule.
|
|
58
|
+
const localAgent = useMemo(() => ({ createPayload: appDatalayerCreatePayload(app) }), [app]);
|
|
59
|
+
return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
|
|
60
|
+
height: '100vh',
|
|
61
|
+
minHeight: 0,
|
|
62
|
+
display: 'flex',
|
|
63
|
+
bg: 'canvas.default',
|
|
64
|
+
}, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0, minHeight: 0 }, children: _jsx(AppRenderer, { app: app, serverUrl: serverUrl, target: "local", localAgent: localAgent, plugins: plugins }) }), _jsxs(Box, { as: "aside", sx: {
|
|
65
|
+
width: 320,
|
|
66
|
+
flexShrink: 0,
|
|
67
|
+
p: 3,
|
|
68
|
+
borderLeft: '1px solid',
|
|
69
|
+
borderColor: 'border.default',
|
|
70
|
+
overflowY: 'auto',
|
|
71
|
+
}, children: [_jsxs(Heading, { as: "h2", sx: { fontSize: 2, mb: 2 }, children: [app.emoji, " Decide"] }), _jsx(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: "Typed decisions asked of Jev, the typed-decision model: yes or no with its probability, one of named options, or a score, each with its confidence." }), _jsxs(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: [_jsx("strong", { children: "In the chat" }), ": ask \u201CIs this ticket urgent? \u2018Help! My payouts have been failing for 3 days.\u2019\u201D Its agent calls the ", _jsx("code", { children: "decide" }), " tool, a read it does without asking."] }), _jsxs(Text, { as: "p", sx: { fontSize: 1, mb: 2 }, children: [_jsx("strong", { children: "From the assistant" }), ": hover the character below and choose ", _jsx("em", { children: "Ask a decision" }), " \u2014 the situation, the question, and its type. The answer comes back in its balloon."] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted' }, children: ["Runs on the local agent-runtimes server at ", serverUrl, ", which asks Jev through ai-inference."] })] })] }) }));
|
|
72
|
+
};
|
|
73
|
+
export default AgentDecideExample;
|
|
@@ -602,7 +602,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
602
602
|
setGoal(spec.goal || '');
|
|
603
603
|
setSystemPrompt(spec.systemPrompt || spec.goal || DEFAULT_SYSTEM_PROMPT);
|
|
604
604
|
setSystemPromptCodemodeAddons(spec.systemPromptCodemodeAddons || '');
|
|
605
|
-
setTools(spec.
|
|
605
|
+
setTools(spec.backendTools || []);
|
|
606
606
|
setSandboxVariant(spec.sandboxVariant || '');
|
|
607
607
|
if (spec.model) {
|
|
608
608
|
setModel(spec.model);
|
|
@@ -650,7 +650,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
650
650
|
protocol: normalizedProtocol,
|
|
651
651
|
systemPrompt: systemPrompt || undefined,
|
|
652
652
|
systemPromptCodemodeAddons: systemPromptCodemodeAddons || undefined,
|
|
653
|
-
tools,
|
|
653
|
+
backendTools: tools,
|
|
654
654
|
sandboxVariant: sandboxVariant || undefined,
|
|
655
655
|
skills: selectedSkills,
|
|
656
656
|
mcpServers: selectedMcpServers.map(server => ({
|
|
@@ -786,7 +786,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
786
786
|
model: model,
|
|
787
787
|
system_prompt: systemPrompt || DEFAULT_SYSTEM_PROMPT,
|
|
788
788
|
system_prompt_codemode_addons: systemPromptCodemodeAddons || undefined,
|
|
789
|
-
|
|
789
|
+
backend_tools: tools,
|
|
790
790
|
sandbox_variant: sandboxVariant || undefined,
|
|
791
791
|
enable_skills: enableSkills,
|
|
792
792
|
enable_codemode: enableCodemode,
|
|
@@ -98,6 +98,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
98
98
|
makeEntry('AgentCompactionExample', () => import('./AgentCompactionExample'), 'Set a context token budget and watch history compaction summarize older messages, with live from/to token and timing details.', ['example', 'agent', 'compaction', 'context', 'tokens']),
|
|
99
99
|
makeEntry('AgentCodemodeExample', () => import('./AgentCodemodeExample'), 'Code mode execution and tool orchestration example.'),
|
|
100
100
|
makeEntry('AgentCodeSandboxesExample', () => import('./AgentCodeSandboxesExample'), 'Launch sandbox-variant agent specs and compare code execution across backends.', ['example', 'agent', 'sandbox', 'codemode']),
|
|
101
|
+
makeEntry('AgentDecideExample', () => import('./AgentDecideExample'), 'Decide: typed decisions asked of Jev — yes or no, a choice, a score — from the chat, where the agent calls decide, and from the floating assistant’s Ask a decision.', ['example', 'agent', 'loop', 'app', 'decisions', 'jev', 'assistant']),
|
|
101
102
|
makeEntry('AgentEvalsExample', () => import('./AgentEvalsExample'), 'Evaluation workflows for agent outputs.'),
|
|
102
103
|
makeEntry('AgentGuardrailsExample', () => import('./AgentGuardrailsExample'), 'Guardrails and safety checks for agent runs.'),
|
|
103
104
|
makeEntry('AgentHooksExample', () => import('./AgentHooksExample'), 'Pre-hooks and post-hooks lifecycle execution example.'),
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export { default as AgentCheckpointsExample } from './AgentCheckpointsExample';
|
|
|
25
25
|
export { default as AgentCompactionExample } from './AgentCompactionExample';
|
|
26
26
|
export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
27
27
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
28
|
+
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
28
29
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
29
30
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
30
31
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -31,6 +31,7 @@ export { default as AgentCheckpointsExample } from './AgentCheckpointsExample';
|
|
|
31
31
|
export { default as AgentCompactionExample } from './AgentCompactionExample';
|
|
32
32
|
export { default as AgentCodemodeExample } from './AgentCodemodeExample';
|
|
33
33
|
export { default as AgentCodeSandboxesExample } from './AgentCodeSandboxesExample';
|
|
34
|
+
export { default as AgentDecideExample } from './AgentDecideExample';
|
|
34
35
|
export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
35
36
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
36
37
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
package/lib/examples/main.js
CHANGED
|
@@ -70,6 +70,9 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
70
70
|
// An application beside its computer, on the local agent-runtimes server:
|
|
71
71
|
// nothing allocated on Datalayer, and the machine itself needs no token.
|
|
72
72
|
'LoopAppComputerExample',
|
|
73
|
+
// Decide, on the local agent-runtimes server as above: Jev is asked
|
|
74
|
+
// through the server's ai-inference, with the server's own key.
|
|
75
|
+
'AgentDecideExample',
|
|
73
76
|
// Runs on the browser sandbox: nothing to allocate, nothing to sign into.
|
|
74
77
|
'LoopShellExample',
|
|
75
78
|
// Temporarily anonymous so the Jupyter output surface can be driven and
|
package/lib/loop/apps/appspec.js
CHANGED
|
@@ -89,7 +89,7 @@ export function emptyAppspec(kind = 'chat') {
|
|
|
89
89
|
instructions: '',
|
|
90
90
|
model: '',
|
|
91
91
|
skills: [],
|
|
92
|
-
|
|
92
|
+
backendTools: [],
|
|
93
93
|
context: [],
|
|
94
94
|
contents: [],
|
|
95
95
|
connections: [],
|
|
@@ -147,7 +147,7 @@ const KNOWN_KEYS = [
|
|
|
147
147
|
'instructions',
|
|
148
148
|
'model',
|
|
149
149
|
'skills',
|
|
150
|
-
'
|
|
150
|
+
'backend_tools',
|
|
151
151
|
'context',
|
|
152
152
|
'contents',
|
|
153
153
|
'connections',
|
|
@@ -341,7 +341,7 @@ export function parseAppspec(document) {
|
|
|
341
341
|
instructions: text(data.instructions),
|
|
342
342
|
model: text(data.model),
|
|
343
343
|
skills: texts(data.skills),
|
|
344
|
-
|
|
344
|
+
backendTools: texts(data.backend_tools),
|
|
345
345
|
context: texts(data.context),
|
|
346
346
|
contents: texts(data.contents),
|
|
347
347
|
connections: records(data.connections).map(parseConnection),
|
|
@@ -541,7 +541,7 @@ export function dumpAppspec(app) {
|
|
|
541
541
|
.text('instructions', app.instructions)
|
|
542
542
|
.text('model', app.model)
|
|
543
543
|
.list('skills', app.skills)
|
|
544
|
-
.list('
|
|
544
|
+
.list('backend_tools', app.backendTools)
|
|
545
545
|
.list('context', app.context)
|
|
546
546
|
.list('contents', app.contents)
|
|
547
547
|
.list('connections', app.connections.map(connection => new Writer()
|
package/lib/loop/apps/checks.js
CHANGED
|
@@ -36,7 +36,7 @@ import { getModel } from '../../specs/models';
|
|
|
36
36
|
import { getNotificationSpec } from '../../specs/notifications';
|
|
37
37
|
import { getSkillSpec } from '../../specs/skills';
|
|
38
38
|
import { getTeamSpec } from '../../specs/teams';
|
|
39
|
-
import {
|
|
39
|
+
import { getBackendToolSpec } from '../../specs/backendTools';
|
|
40
40
|
import { getTrack } from '../../specs/tracks';
|
|
41
41
|
import { pluginsOffSetupNotes } from '../plugins/canvas-blocks';
|
|
42
42
|
import { isAssistantCharacterId, parseAppspec } from './appspec';
|
|
@@ -173,8 +173,8 @@ function referenceProblems(app, organizationFrames) {
|
|
|
173
173
|
if (!getSkillSpec(idOf(ref)))
|
|
174
174
|
missing('skill', ref);
|
|
175
175
|
}
|
|
176
|
-
for (const ref of app.
|
|
177
|
-
if (!
|
|
176
|
+
for (const ref of app.backendTools) {
|
|
177
|
+
if (!getBackendToolSpec(idOf(ref)))
|
|
178
178
|
missing('tool', ref);
|
|
179
179
|
}
|
|
180
180
|
for (const ref of app.checks.guards) {
|
|
@@ -241,7 +241,7 @@ function referenceProblems(app, organizationFrames) {
|
|
|
241
241
|
continue;
|
|
242
242
|
const [server, name] = splitRef(target);
|
|
243
243
|
if (server === undefined) {
|
|
244
|
-
if (!
|
|
244
|
+
if (!getBackendToolSpec(name)) {
|
|
245
245
|
problems.push(`The rule “${rule.action}” names the tool “${target}”, which the catalogue does not have.`);
|
|
246
246
|
}
|
|
247
247
|
continue;
|
|
@@ -339,8 +339,8 @@ function setupNotes(app) {
|
|
|
339
339
|
}
|
|
340
340
|
for (const ref of app.skills)
|
|
341
341
|
note('skill', ref, getSkillSpec(idOf(ref)));
|
|
342
|
-
for (const ref of app.
|
|
343
|
-
note('tool', ref,
|
|
342
|
+
for (const ref of app.backendTools)
|
|
343
|
+
note('tool', ref, getBackendToolSpec(idOf(ref)));
|
|
344
344
|
for (const ref of app.checks.guards)
|
|
345
345
|
note('Guard', ref, own(GUARD_CATALOGUE, idOf(ref)));
|
|
346
346
|
for (const ref of app.checks.gates)
|
package/lib/loop/apps/rules.js
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* @module loop/apps/rules
|
|
36
36
|
*/
|
|
37
|
-
import { SERVER_ACTIONS,
|
|
37
|
+
import { SERVER_ACTIONS, BACKEND_TOOL_ACTIONS } from '../../specs/actions';
|
|
38
38
|
/** The four behaviours, from the freest to the most restricted. */
|
|
39
39
|
export const BEHAVIOURS = [
|
|
40
40
|
'do_it',
|
|
@@ -138,7 +138,7 @@ function entryOf(server, name) {
|
|
|
138
138
|
export function classesOf(ref, args) {
|
|
139
139
|
const [server, name] = splitRef(ref);
|
|
140
140
|
if (server === undefined) {
|
|
141
|
-
return [...(own(
|
|
141
|
+
return [...(own(BACKEND_TOOL_ACTIONS, name) ?? [])];
|
|
142
142
|
}
|
|
143
143
|
const [classes, conditions] = entryOf(server, name);
|
|
144
144
|
for (const condition of conditions) {
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* while the conversation is out of sight, holds there the approval it waits
|
|
10
10
|
* on, answered with *Approve* or *Deny* on the path every approval of it is
|
|
11
11
|
* answered on (T-23, U-19), opens the conversation when clicked, and is
|
|
12
|
-
* dragged about and sent away as the chat's own assistant is (T-27).
|
|
12
|
+
* dragged about and sent away as the chat's own assistant is (T-27). Given
|
|
13
|
+
* the runtime to ask (`decisions`), its balloon offers *Ask a decision*: a
|
|
14
|
+
* typed decision asked of Jev through the runtime, answered there.
|
|
13
15
|
*
|
|
14
16
|
* The workspace's chat is the conversation: on a page layout, its side panel
|
|
15
17
|
* is opened and closed; where the conversation is always on screen, a click
|
|
@@ -33,6 +35,16 @@ export type LoopAssistantConfig = {
|
|
|
33
35
|
* the balloon says an approval waits and the conversation answers it.
|
|
34
36
|
*/
|
|
35
37
|
appId?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The runtime decisions are asked at — its
|
|
40
|
+
* `/api/v1/configure/inference/decisions`, as the `decide` tool asks — and
|
|
41
|
+
* the token to ask with, if it needs one: the balloon offers *Ask a
|
|
42
|
+
* decision*. Without it, it does not.
|
|
43
|
+
*/
|
|
44
|
+
decisions?: {
|
|
45
|
+
serverUrl: string;
|
|
46
|
+
token?: string;
|
|
47
|
+
};
|
|
36
48
|
};
|
|
37
49
|
/**
|
|
38
50
|
* What the character acts out (T-22), from what the application is doing as
|
|
@@ -43,6 +55,6 @@ export declare function assistantStateOfTurn(turn: ChatTurnSnapshot, presence: P
|
|
|
43
55
|
arriving?: boolean;
|
|
44
56
|
leaving?: boolean;
|
|
45
57
|
}): AssistantState;
|
|
46
|
-
export declare function LoopAssistant({ app, person, appId, }: LoopAssistantConfig): JSX.Element | null;
|
|
58
|
+
export declare function LoopAssistant({ app, person, appId, decisions, }: LoopAssistantConfig): JSX.Element | null;
|
|
47
59
|
export declare const LoopAssistantPlugin: import("@datalayer/reactor").ReactorPlugin<LoopAssistantConfig, unknown, unknown>;
|
|
48
60
|
export default LoopAssistantPlugin;
|
|
@@ -7,6 +7,7 @@ import { Box } from '@datalayer/primer-addons';
|
|
|
7
7
|
import { useIAMStore } from '@datalayer/core/lib/state/substates/IAMState';
|
|
8
8
|
import { pageLayoutPanelOpen, togglePagePanel, } from '@datalayer/primer-addons/lib/reactor';
|
|
9
9
|
import { AssistantStage } from '../../../chat/assistant/AssistantStage';
|
|
10
|
+
import { decisionsAskerAt } from '../../../chat/assistant/decisions';
|
|
10
11
|
import { ASSISTANT_WORDS, assistantStateOf, keepAway, keptAway, latestSaying, } from '../../../chat/assistant/state';
|
|
11
12
|
import { useApproveToolRequest, useRejectToolRequest, useToolApprovalsQuery, } from '../../../hooks/useToolApprovals';
|
|
12
13
|
import { approvalsOfApp, ruleOfApproval } from '../app-rules/AppRulesCard';
|
|
@@ -67,7 +68,7 @@ function focusComposer() {
|
|
|
67
68
|
const composer = document.querySelector('[data-chat-composer] textarea, [data-chat-composer] [contenteditable="true"]');
|
|
68
69
|
composer?.focus();
|
|
69
70
|
}
|
|
70
|
-
export function LoopAssistant({ app, person, appId, }) {
|
|
71
|
+
export function LoopAssistant({ app, person, appId, decisions, }) {
|
|
71
72
|
const contributed = useContributions(LoopAssistantCharacter).map(entry => entry.value);
|
|
72
73
|
const chosen = assistantCharacterFor(contributed, { app, person });
|
|
73
74
|
const turnEntries = useContributions(LoopChatTurn);
|
|
@@ -110,6 +111,9 @@ export function LoopAssistant({ app, person, appId, }) {
|
|
|
110
111
|
}, [open, saying?.id]);
|
|
111
112
|
const stageRef = useRef(null);
|
|
112
113
|
const drag = useViewportDrag(stageRef, { whole: true });
|
|
114
|
+
const decide = useMemo(() => decisions?.serverUrl
|
|
115
|
+
? decisionsAskerAt(decisions.serverUrl, decisions.token)
|
|
116
|
+
: undefined, [decisions?.serverUrl, decisions?.token]);
|
|
113
117
|
if (away !== 'none') {
|
|
114
118
|
return null;
|
|
115
119
|
}
|
|
@@ -162,16 +166,21 @@ export function LoopAssistant({ app, person, appId, }) {
|
|
|
162
166
|
};
|
|
163
167
|
return (_jsxs(_Fragment, { children: [appId && signedIn ? (_jsx(WaitingApprovals, { appId: appId, onWaiting: setApproval })) : null, _jsx(AssistantStage, { character: chosen.character, state: state, size: SIZE, place: drag.position
|
|
164
168
|
? { left: `${drag.position.left}px`, top: `${drag.position.top}px` }
|
|
165
|
-
: { right: '24px', bottom: '24px' }, stageRef: stageRef, onDragStart: drag.onHandlePointerDown, open: open, onToggle: onToggle, balloon: balloon, insist: insist, onDismiss: onDismiss })] }));
|
|
169
|
+
: { right: '24px', bottom: '24px' }, stageRef: stageRef, onDragStart: drag.onHandlePointerDown, open: open, onToggle: onToggle, balloon: balloon, insist: insist, onDismiss: onDismiss, decide: decide })] }));
|
|
166
170
|
}
|
|
167
171
|
export const LoopAssistantPlugin = definePlugin({
|
|
168
172
|
name: LOOP_ASSISTANT_PLUGIN_NAME,
|
|
169
|
-
config: {
|
|
173
|
+
config: {
|
|
174
|
+
app: undefined,
|
|
175
|
+
person: undefined,
|
|
176
|
+
appId: undefined,
|
|
177
|
+
decisions: undefined,
|
|
178
|
+
},
|
|
170
179
|
displayName: 'Floating assistant',
|
|
171
180
|
description: 'The chat as a character on the page: the application’s own, or the one the person chose, from the characters the enabled plugins contribute.',
|
|
172
181
|
octicon: 'paperclip',
|
|
173
182
|
build: ({ config }) => {
|
|
174
|
-
const Configured = () => (_jsx(LoopAssistant, { app: config.app, person: config.person, appId: config.appId }));
|
|
183
|
+
const Configured = () => (_jsx(LoopAssistant, { app: config.app, person: config.person, appId: config.appId, decisions: config.decisions }));
|
|
175
184
|
return {
|
|
176
185
|
components: [
|
|
177
186
|
{ id: 'loop-assistant', slot: LoopSlots.root, Component: Configured },
|
package/lib/specs/actions.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type { ActionClass, AppBehaviour, AppEscalation, ServerActionsSpec } from
|
|
|
11
11
|
/** The classes of action, from the one that changes nothing. */
|
|
12
12
|
export declare const ACTION_CLASSES: ActionClass[];
|
|
13
13
|
/** What each tool of the tools catalogue does, by id. */
|
|
14
|
-
export declare const
|
|
14
|
+
export declare const BACKEND_TOOL_ACTIONS: Record<string, ActionClass[]>;
|
|
15
15
|
/**
|
|
16
16
|
* What each MCP server's tools do, by server id. `checked` is the day the
|
|
17
17
|
* names were read off the running server; absent when nobody looked.
|
package/lib/specs/actions.js
CHANGED
|
@@ -12,7 +12,7 @@ export const ACTION_CLASSES = [
|
|
|
12
12
|
'publish',
|
|
13
13
|
];
|
|
14
14
|
/** What each tool of the tools catalogue does, by id. */
|
|
15
|
-
export const
|
|
15
|
+
export const BACKEND_TOOL_ACTIONS = {
|
|
16
16
|
'create-plan': ['read'],
|
|
17
17
|
'current-time': ['read'],
|
|
18
18
|
decide: ['read'],
|