@datalayer/agent-runtimes 1.3.54 → 1.3.55
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/examples/AgentStrategyExample.d.ts +12 -0
- package/lib/examples/{AgentLoopExample.js → AgentStrategyExample.js} +62 -62
- package/lib/examples/example-selector.js +1 -1
- package/lib/examples/index.d.ts +1 -1
- package/lib/examples/index.js +1 -1
- package/lib/examples/main.js +3 -3
- package/lib/specs/index.d.ts +1 -1
- package/lib/specs/index.js +1 -1
- package/lib/specs/strategies.d.ts +34 -0
- package/lib/specs/{loops.js → strategies.js} +30 -30
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +1 -1
- package/lib/types/{loops.d.ts → strategies.d.ts} +17 -17
- package/package.json +1 -1
- package/scripts/codegen/generate_agents.py +1 -1
- package/scripts/codegen/{generate_loops.py → generate_strategies.py} +81 -81
- package/lib/examples/AgentLoopExample.d.ts +0 -12
- package/lib/specs/loops.d.ts +0 -34
- /package/lib/types/{loops.js → strategies.js} +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ServiceManager } from '@jupyterlab/services';
|
|
2
|
+
interface AgentStrategyExampleInnerProps {
|
|
3
|
+
serviceManager?: ServiceManager.IManager;
|
|
4
|
+
}
|
|
5
|
+
export declare function AgentStrategyExampleInner({ serviceManager, }: AgentStrategyExampleInnerProps): import("react").JSX.Element;
|
|
6
|
+
/**
|
|
7
|
+
* Main example component with Jupyter provider wrapper.
|
|
8
|
+
*/
|
|
9
|
+
export declare function AgentStrategyExample({ serviceManager, }: {
|
|
10
|
+
serviceManager?: ServiceManager.IManager;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export default AgentStrategyExample;
|
|
@@ -4,27 +4,27 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* AgentStrategyExample - Define and launch an agent reasoning *strategy*.
|
|
8
8
|
*
|
|
9
|
-
* This example demonstrates the
|
|
9
|
+
* This example demonstrates the control-loop paradigm (observe → think → act →
|
|
10
10
|
* evaluate) instead of one-shot prompting. It is fully driven by the generic
|
|
11
|
-
*
|
|
11
|
+
* strategy specifications defined in agentspecs (`src/specs/strategies.ts`):
|
|
12
12
|
*
|
|
13
|
-
* - Pick any
|
|
14
|
-
* Human-in-the-Loop). The list is read from the
|
|
15
|
-
* new YAML
|
|
16
|
-
* - The agent's system prompt is composed generically from the selected
|
|
13
|
+
* - Pick any strategy spec (Data Analysis, Plan/Execute/Critic, OODA,
|
|
14
|
+
* Human-in-the-Loop). The list is read from the strategy catalogue, so adding a
|
|
15
|
+
* new YAML strategy spec automatically makes it available here.
|
|
16
|
+
* - The agent's system prompt is composed generically from the selected strategy's
|
|
17
17
|
* objective, phases, constraints, termination policy and human settings — no
|
|
18
|
-
*
|
|
19
|
-
* - The agent then runs the
|
|
20
|
-
*
|
|
18
|
+
* strategy-specific code.
|
|
19
|
+
* - The agent then runs the strategy against a live Jupyter notebook, where the
|
|
20
|
+
* strategy state (dataframes, charts, intermediate results) lives outside the
|
|
21
21
|
* model so each iteration stays small and focused.
|
|
22
22
|
*
|
|
23
23
|
* To run this example:
|
|
24
24
|
* 1. Start the agent-runtimes server.
|
|
25
25
|
* 2. Select this example from the header dropdown (Agent group).
|
|
26
26
|
*
|
|
27
|
-
* @module examples/
|
|
27
|
+
* @module examples/AgentStrategyExample
|
|
28
28
|
*/
|
|
29
29
|
import { useMemo, useState } from 'react';
|
|
30
30
|
import { Box } from '@datalayer/primer-addons';
|
|
@@ -32,40 +32,40 @@ import { Notebook } from '@datalayer/jupyter-react';
|
|
|
32
32
|
import { useNotebookTools } from '../tools/adapters/agent-runtimes/notebookHooks';
|
|
33
33
|
import { ThemedJupyterProvider, ThemedProvider } from './utils/themedProvider';
|
|
34
34
|
import { ChatSidebar } from '../chat';
|
|
35
|
-
import {
|
|
35
|
+
import { listStrategies, getStrategy, DEFAULT_STRATEGY } from '../specs';
|
|
36
36
|
import { useExampleJupyterAgent } from './hooks/useExampleJupyterAgent';
|
|
37
37
|
import MatplotlibNotebook from './utils/notebooks/Matplotlib.ipynb.json';
|
|
38
38
|
import { ExampleNotebookToolbar } from './utils/notebookToolbarItems';
|
|
39
39
|
// Fixed notebook ID
|
|
40
|
-
const NOTEBOOK_ID = 'agent-
|
|
41
|
-
// Use the imported Matplotlib notebook as the working surface for the
|
|
40
|
+
const NOTEBOOK_ID = 'agent-strategy-example';
|
|
41
|
+
// Use the imported Matplotlib notebook as the working surface for the strategy.
|
|
42
42
|
const NOTEBOOK_CONTENT = MatplotlibNotebook;
|
|
43
43
|
// Default configuration
|
|
44
|
-
const DEFAULT_AGENT_ID = import.meta.env.VITE_AGENT_ID || '
|
|
44
|
+
const DEFAULT_AGENT_ID = import.meta.env.VITE_AGENT_ID || 'strategy-agent-runtime-example';
|
|
45
45
|
/**
|
|
46
|
-
* Compose an agent system prompt generically from a
|
|
46
|
+
* Compose an agent system prompt generically from a strategy specification.
|
|
47
47
|
*
|
|
48
|
-
* This is intentionally spec-driven: every field comes from the
|
|
49
|
-
* the same code drives any
|
|
48
|
+
* This is intentionally spec-driven: every field comes from the strategy YAML, so
|
|
49
|
+
* the same code drives any strategy (data analysis, plan/execute/critic, OODA, ...).
|
|
50
50
|
*/
|
|
51
|
-
function
|
|
51
|
+
function buildStrategySystemPrompt(strategy) {
|
|
52
52
|
const lines = [];
|
|
53
|
-
lines.push(`You are an agent that operates as a control
|
|
54
|
-
lines.push(`
|
|
55
|
-
if (
|
|
56
|
-
lines.push(`Objective: ${
|
|
53
|
+
lines.push(`You are an agent that operates as a control loop rather than answering in a single prompt.`);
|
|
54
|
+
lines.push(`Strategy: ${strategy.name} (${strategy.strategy}).`);
|
|
55
|
+
if (strategy.objective) {
|
|
56
|
+
lines.push(`Objective: ${strategy.objective}`);
|
|
57
57
|
}
|
|
58
|
-
if (
|
|
59
|
-
lines.push(`Each iteration, execute these phases in order: ${
|
|
58
|
+
if (strategy.phases?.length) {
|
|
59
|
+
lines.push(`Each iteration, execute these phases in order: ${strategy.phases.join(' → ')}. ` +
|
|
60
60
|
`Decide the single best next action each iteration; do not try to solve everything at once.`);
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
63
|
-
lines.push(`Constraints you must respect:\n${
|
|
62
|
+
if (strategy.constraints?.length) {
|
|
63
|
+
lines.push(`Constraints you must respect:\n${strategy.constraints
|
|
64
64
|
.map(c => `- ${c}`)
|
|
65
65
|
.join('\n')}`);
|
|
66
66
|
}
|
|
67
|
-
if (
|
|
68
|
-
const t =
|
|
67
|
+
if (strategy.termination) {
|
|
68
|
+
const t = strategy.termination;
|
|
69
69
|
lines.push(`Termination: stop after at most ${t.maxIterations} iterations, or when the goal is reached.`);
|
|
70
70
|
if (t.successCriteria?.length) {
|
|
71
71
|
lines.push(`Success criteria:\n${t.successCriteria.map(s => `- ${s}`).join('\n')}`);
|
|
@@ -74,13 +74,13 @@ function buildLoopSystemPrompt(loop) {
|
|
|
74
74
|
lines.push(`If blocked: ${t.onBlocked}.`);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
if (
|
|
78
|
-
lines.push(`Human-in-the-loop: mode "${
|
|
79
|
-
(
|
|
80
|
-
? `; request explicit approval before: ${
|
|
77
|
+
if (strategy.human && strategy.human.mode !== 'none') {
|
|
78
|
+
lines.push(`Human-in-the-loop: mode "${strategy.human.mode}"` +
|
|
79
|
+
(strategy.human.approvalRequired
|
|
80
|
+
? `; request explicit approval before: ${strategy.human.approvalFor.join(', ') || 'sensitive actions'}.`
|
|
81
81
|
: '.'));
|
|
82
82
|
}
|
|
83
|
-
lines.push(`Keep
|
|
83
|
+
lines.push(`Keep strategy state (dataframes, charts, intermediate results) in the notebook/runtime, not in the prompt. ` +
|
|
84
84
|
`For notebook operations, always use the notebook frontend tools (runCell, readAllCells, readCell, insertCell, updateCell, deleteCells) so actions happen in the live notebook UI. ` +
|
|
85
85
|
`Use executeCodeInNotebook only for temporary inspection code that should not modify notebook cells.`);
|
|
86
86
|
return lines.join('\n\n');
|
|
@@ -108,9 +108,9 @@ function NotebookUI({ serviceManager }) {
|
|
|
108
108
|
return (_jsx(ThemedJupyterProvider, { children: _jsx(Notebook, { nbformat: NOTEBOOK_CONTENT, id: NOTEBOOK_ID, Toolbar: ExampleNotebookToolbar, serviceManager: serviceManager, height: "100%", cellSidebarMargin: 120, startDefaultKernel: true }) }));
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* A compact, read-only summary of the selected
|
|
111
|
+
* A compact, read-only summary of the selected strategy specification.
|
|
112
112
|
*/
|
|
113
|
-
function
|
|
113
|
+
function StrategySummary({ strategy }) {
|
|
114
114
|
return (_jsxs(Box, { sx: {
|
|
115
115
|
mt: 2,
|
|
116
116
|
p: 2,
|
|
@@ -119,7 +119,7 @@ function LoopSummary({ loop }) {
|
|
|
119
119
|
borderRadius: 2,
|
|
120
120
|
bg: 'canvas.default',
|
|
121
121
|
fontSize: 0,
|
|
122
|
-
}, children: [_jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 2, mb: 1 }, children:
|
|
122
|
+
}, children: [_jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 2, mb: 1 }, children: strategy.phases.map((phase, index) => (_jsxs(Box, { sx: {
|
|
123
123
|
display: 'flex',
|
|
124
124
|
alignItems: 'center',
|
|
125
125
|
gap: 1,
|
|
@@ -129,21 +129,21 @@ function LoopSummary({ loop }) {
|
|
|
129
129
|
bg: 'neutral.muted',
|
|
130
130
|
color: 'fg.default',
|
|
131
131
|
fontWeight: 'bold',
|
|
132
|
-
}, children: [index + 1, ". ", phase] }, phase))) }),
|
|
132
|
+
}, children: [index + 1, ". ", phase] }, phase))) }), strategy.objective && (_jsxs(Box, { sx: { color: 'fg.muted' }, children: [_jsx("strong", { children: "Objective:" }), " ", strategy.objective] })), strategy.termination && (_jsxs(Box, { sx: { color: 'fg.muted', mt: 1 }, children: [_jsx("strong", { children: "Max iterations:" }), " ", strategy.termination.maxIterations, ' ', "\u00B7 ", _jsx("strong", { children: "On blocked:" }), " ", strategy.termination.onBlocked] }))] }));
|
|
133
133
|
}
|
|
134
|
-
export function
|
|
135
|
-
// All available
|
|
136
|
-
const
|
|
137
|
-
const [
|
|
138
|
-
const
|
|
139
|
-
const systemPrompt = useMemo(() =>
|
|
134
|
+
export function AgentStrategyExampleInner({ serviceManager, }) {
|
|
135
|
+
// All available strategies come from the generated strategy catalogue.
|
|
136
|
+
const strategies = useMemo(() => listStrategies(), []);
|
|
137
|
+
const [selectedStrategyId, setSelectedStrategyId] = useState(DEFAULT_STRATEGY);
|
|
138
|
+
const selectedStrategy = useMemo(() => getStrategy(selectedStrategyId) ?? strategies[0], [selectedStrategyId, strategies]);
|
|
139
|
+
const systemPrompt = useMemo(() => buildStrategySystemPrompt(selectedStrategy), [selectedStrategy]);
|
|
140
140
|
// The tools. Which of the chat and the harness runs them depends on
|
|
141
|
-
// where the
|
|
141
|
+
// where the strategy turns, and the hook decides that.
|
|
142
142
|
const tools = useNotebookTools(NOTEBOOK_ID);
|
|
143
143
|
const { agentReady, protocol: protocolConfig, chatFrontendTools, error, unavailableReason, createAttempted, } = useExampleJupyterAgent({
|
|
144
|
-
exampleId: '
|
|
144
|
+
exampleId: 'AgentStrategyExample',
|
|
145
145
|
agentName: DEFAULT_AGENT_ID,
|
|
146
|
-
description: `
|
|
146
|
+
description: `Strategy agent (${selectedStrategy.name}) for AgentStrategyExample`,
|
|
147
147
|
systemPrompt,
|
|
148
148
|
serviceManager,
|
|
149
149
|
frontendTools: tools,
|
|
@@ -153,16 +153,16 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
153
153
|
// The example's own agent, not merely the runtime: on the cloud target the
|
|
154
154
|
// runtime is ready before this agent has been registered on it.
|
|
155
155
|
const effectiveReady = agentReady;
|
|
156
|
-
const
|
|
156
|
+
const isStrategySelectorDisabled = createAttempted;
|
|
157
157
|
// Get notebook tools for ChatSidebar
|
|
158
158
|
// Build Vercel AI protocol config
|
|
159
|
-
// Chat suggestions derived from the selected
|
|
159
|
+
// Chat suggestions derived from the selected strategy.
|
|
160
160
|
const suggestions = useMemo(() => [
|
|
161
161
|
{
|
|
162
|
-
title: `${
|
|
163
|
-
message:
|
|
164
|
-
? `Run the ${
|
|
165
|
-
: `Run the ${
|
|
162
|
+
title: `${selectedStrategy.emoji} Run the strategy`,
|
|
163
|
+
message: selectedStrategy.objective
|
|
164
|
+
? `Run the ${selectedStrategy.name}. ${selectedStrategy.objective}`
|
|
165
|
+
: `Run the ${selectedStrategy.name} against the data in this notebook.`,
|
|
166
166
|
},
|
|
167
167
|
{
|
|
168
168
|
title: '🔁 Next iteration',
|
|
@@ -176,7 +176,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
176
176
|
title: '📊 Summarize findings',
|
|
177
177
|
message: 'Summarize the key findings and produce a final, decision-oriented report.',
|
|
178
178
|
},
|
|
179
|
-
], [
|
|
179
|
+
], [selectedStrategy]);
|
|
180
180
|
return (_jsx(_Fragment, { children: _jsxs(Box, { sx: {
|
|
181
181
|
// The wrapper is the viewport, not the window: it sits below the
|
|
182
182
|
// header and beside the sidebar, so viewport units size this box to
|
|
@@ -204,9 +204,9 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
204
204
|
justifyContent: 'space-between',
|
|
205
205
|
gap: 3,
|
|
206
206
|
flexWrap: 'wrap',
|
|
207
|
-
}, children: [_jsxs(Box, { children: [_jsxs("h1", { style: { margin: 0, fontSize: '1.5rem' }, children: [
|
|
208
|
-
? '
|
|
209
|
-
: 'Choose a
|
|
207
|
+
}, children: [_jsxs(Box, { children: [_jsxs("h1", { style: { margin: 0, fontSize: '1.5rem' }, children: [selectedStrategy.emoji, " Agent Strategy Example"] }), _jsx("p", { style: { margin: '8px 0 0', color: 'var(--fgColor-muted)' }, children: "Define and launch an agent reasoning strategy \u2014 observe, think, act, evaluate \u2014 over a live notebook." })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, title: isStrategySelectorDisabled
|
|
208
|
+
? 'Strategy selector is temporarily disabled while launching the agent'
|
|
209
|
+
: 'Choose a strategy', children: [_jsx(Box, { as: "label", sx: { fontSize: 1, fontWeight: 'bold' }, children: "Strategy" }), _jsx(Box, { as: "select", value: selectedStrategyId, onChange: (e) => setSelectedStrategyId(e.target.value), disabled: isStrategySelectorDisabled, "aria-label": "Strategy specification", sx: {
|
|
210
210
|
px: 2,
|
|
211
211
|
py: '6px',
|
|
212
212
|
fontSize: 1,
|
|
@@ -215,7 +215,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
215
215
|
borderColor: 'border.default',
|
|
216
216
|
bg: 'canvas.default',
|
|
217
217
|
color: 'fg.default',
|
|
218
|
-
}, children:
|
|
218
|
+
}, children: strategies.map(strategy => (_jsxs("option", { value: strategy.id, children: [strategy.emoji, " ", strategy.name] }, strategy.id))) })] })] }), _jsx(StrategySummary, { strategy: selectedStrategy })] }), _jsx(Box, { sx: {
|
|
219
219
|
flex: 1,
|
|
220
220
|
display: 'flex',
|
|
221
221
|
overflow: 'hidden',
|
|
@@ -227,7 +227,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
227
227
|
borderColor: 'border.default',
|
|
228
228
|
borderRadius: 2,
|
|
229
229
|
overflow: 'hidden',
|
|
230
|
-
}, children: _jsx(NotebookUI, { serviceManager: serviceManager }) }) })] }), effectiveReady && (_jsx(ChatSidebar, { title: `${
|
|
230
|
+
}, children: _jsx(NotebookUI, { serviceManager: serviceManager }) }) })] }), effectiveReady && (_jsx(ChatSidebar, { title: `${selectedStrategy.emoji} ${selectedStrategy.name}`, protocol: protocolConfig, position: "right", width: 400, clickOutsideToClose: false, showNewChatButton: true, showClearButton: true, showSettingsButton: true, defaultOpen: true, panelProps: {
|
|
231
231
|
protocol: protocolConfig,
|
|
232
232
|
frontendTools: chatFrontendTools,
|
|
233
233
|
useStore: false,
|
|
@@ -250,7 +250,7 @@ export function AgentLoopExampleInner({ serviceManager, }) {
|
|
|
250
250
|
/**
|
|
251
251
|
* Main example component with Jupyter provider wrapper.
|
|
252
252
|
*/
|
|
253
|
-
export function
|
|
254
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
253
|
+
export function AgentStrategyExample({ serviceManager, }) {
|
|
254
|
+
return (_jsx(ThemedProvider, { children: _jsx(AgentStrategyExampleInner, { serviceManager: serviceManager }) }));
|
|
255
255
|
}
|
|
256
|
-
export default
|
|
256
|
+
export default AgentStrategyExample;
|
|
@@ -111,7 +111,7 @@ export const EXAMPLE_ENTRIES = [
|
|
|
111
111
|
// `owns-sandbox-control`: the shell is pinned to the browser sandbox, so
|
|
112
112
|
// the page's selector would offer three targets it cannot move to.
|
|
113
113
|
['example', 'loop', 'shell', 'prompt', 'editors', 'owns-sandbox-control']),
|
|
114
|
-
makeEntry('
|
|
114
|
+
makeEntry('AgentStrategyExample', () => import('./AgentStrategyExample'), 'Define and launch an agent reasoning strategy (a control loop: observe/think/act/evaluate) over a live notebook, driven by generic strategy specs.', ['example', 'agent', 'strategy', 'notebook', 'agentspecs']),
|
|
115
115
|
makeEntry('AgentToolApprovalsExample', () => import('./AgentToolApprovalsExample'), 'Tool approval workflows and manual decisions.'),
|
|
116
116
|
makeEntry('AgentMemoryExample', () => import('./AgentMemoryExample'), 'Memory-aware conversation and retrieval example.'),
|
|
117
117
|
makeEntry('AgentSkillsExample', () => import('./AgentSkillsExample'), 'Skills discovery, execution, and monitoring example.'),
|
package/lib/examples/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
|
28
28
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
29
29
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
|
30
30
|
export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
|
|
31
|
-
export { default as
|
|
31
|
+
export { default as AgentStrategyExample } from './AgentStrategyExample';
|
|
32
32
|
export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
|
|
33
33
|
export { default as AgentMemoryExample } from './AgentMemoryExample';
|
|
34
34
|
export { default as AgentOtelExample } from './AgentOtelExample';
|
package/lib/examples/index.js
CHANGED
|
@@ -34,7 +34,7 @@ export { default as AgentEvalsExample } from './AgentEvalsExample';
|
|
|
34
34
|
export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
|
|
35
35
|
export { default as AgentHooksExample } from './AgentHooksExample';
|
|
36
36
|
export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
|
|
37
|
-
export { default as
|
|
37
|
+
export { default as AgentStrategyExample } from './AgentStrategyExample';
|
|
38
38
|
export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
|
|
39
39
|
export { default as AgentMemoryExample } from './AgentMemoryExample';
|
|
40
40
|
export { default as AgentOtelExample } from './AgentOtelExample';
|
package/lib/examples/main.js
CHANGED
|
@@ -86,7 +86,7 @@ const ANONYMOUS_EXAMPLES = new Set([
|
|
|
86
86
|
]);
|
|
87
87
|
const getExampleGroup = (id) => {
|
|
88
88
|
if (id === 'AgentspecsExample' ||
|
|
89
|
-
id === '
|
|
89
|
+
id === 'AgentStrategyExample' ||
|
|
90
90
|
id === 'LoopWorkspaceExample' ||
|
|
91
91
|
id === 'LoopShellExample' ||
|
|
92
92
|
id === 'DecksAgent') {
|
|
@@ -1068,12 +1068,12 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
|
|
|
1068
1068
|
for (const [groupName, examples] of groups) {
|
|
1069
1069
|
examples.sort((left, right) => {
|
|
1070
1070
|
if (groupName === 'Loop') {
|
|
1071
|
-
// The shells first, most naked first; then the
|
|
1071
|
+
// The shells first, most naked first; then the strategy that drives a
|
|
1072
1072
|
// notebook; then the library of specs behind them all.
|
|
1073
1073
|
const LOOP_ORDER = [
|
|
1074
1074
|
'LoopShellExample',
|
|
1075
1075
|
'LoopWorkspaceExample',
|
|
1076
|
-
'
|
|
1076
|
+
'AgentStrategyExample',
|
|
1077
1077
|
'AgentspecsExample',
|
|
1078
1078
|
];
|
|
1079
1079
|
const loopOrder = (id) => {
|
package/lib/specs/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export * from './teams';
|
|
|
8
8
|
export * from './envvars';
|
|
9
9
|
export * from './evals';
|
|
10
10
|
export * from './guardrails';
|
|
11
|
-
export * from './
|
|
11
|
+
export * from './strategies';
|
|
12
12
|
export * from './mcpServers';
|
|
13
13
|
export * from './memory';
|
|
14
14
|
export * from './models';
|
package/lib/specs/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export * from './teams';
|
|
|
12
12
|
export * from './envvars';
|
|
13
13
|
export * from './evals';
|
|
14
14
|
export * from './guardrails';
|
|
15
|
-
export * from './
|
|
15
|
+
export * from './strategies';
|
|
16
16
|
export * from './mcpServers';
|
|
17
17
|
export * from './memory';
|
|
18
18
|
export * from './models';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strategy Catalog
|
|
3
|
+
*
|
|
4
|
+
* Predefined agent reasoning strategies (control loops).
|
|
5
|
+
*
|
|
6
|
+
* This file is AUTO-GENERATED from YAML specifications.
|
|
7
|
+
* DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
|
|
8
|
+
*/
|
|
9
|
+
import type { StrategySpec } from '../types';
|
|
10
|
+
export declare const Strategies: {
|
|
11
|
+
readonly DATA_ANALYSIS: "data-analysis";
|
|
12
|
+
readonly HUMAN_IN_THE_LOOP: "human-in-the-loop";
|
|
13
|
+
readonly OODA: "ooda";
|
|
14
|
+
readonly PLAN_EXECUTE_CRITIC: "plan-execute-critic";
|
|
15
|
+
};
|
|
16
|
+
export type StrategyId = (typeof Strategies)[keyof typeof Strategies];
|
|
17
|
+
export declare const DATA_ANALYSIS_STRATEGY_0_0_1: StrategySpec;
|
|
18
|
+
export declare const HUMAN_IN_THE_LOOP_STRATEGY_0_0_1: StrategySpec;
|
|
19
|
+
export declare const OODA_STRATEGY_0_0_1: StrategySpec;
|
|
20
|
+
export declare const PLAN_EXECUTE_CRITIC_STRATEGY_0_0_1: StrategySpec;
|
|
21
|
+
export declare const STRATEGY_CATALOGUE: Record<string, StrategySpec>;
|
|
22
|
+
export declare const DEFAULT_STRATEGY: StrategyId;
|
|
23
|
+
/**
|
|
24
|
+
* Get a strategy specification by ID.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getStrategy(strategyId: string): StrategySpec | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Get the default strategy.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getDefaultStrategy(): StrategySpec | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* List all available strategies.
|
|
33
|
+
*/
|
|
34
|
+
export declare function listStrategies(): StrategySpec[];
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
// ============================================================================
|
|
6
|
-
//
|
|
6
|
+
// Strategies Enum
|
|
7
7
|
// ============================================================================
|
|
8
|
-
export const
|
|
8
|
+
export const Strategies = {
|
|
9
9
|
DATA_ANALYSIS: 'data-analysis',
|
|
10
10
|
HUMAN_IN_THE_LOOP: 'human-in-the-loop',
|
|
11
11
|
OODA: 'ooda',
|
|
12
12
|
PLAN_EXECUTE_CRITIC: 'plan-execute-critic',
|
|
13
13
|
};
|
|
14
14
|
// ============================================================================
|
|
15
|
-
//
|
|
15
|
+
// Strategy Definitions
|
|
16
16
|
// ============================================================================
|
|
17
|
-
export const
|
|
17
|
+
export const DATA_ANALYSIS_STRATEGY_0_0_1 = {
|
|
18
18
|
id: 'data-analysis',
|
|
19
19
|
version: '0.0.1',
|
|
20
20
|
name: 'Data Analysis Loop',
|
|
@@ -47,7 +47,7 @@ export const DATA_ANALYSIS_LOOP_0_0_1 = {
|
|
|
47
47
|
icon: 'graph',
|
|
48
48
|
emoji: '📊',
|
|
49
49
|
};
|
|
50
|
-
export const
|
|
50
|
+
export const HUMAN_IN_THE_LOOP_STRATEGY_0_0_1 = {
|
|
51
51
|
id: 'human-in-the-loop',
|
|
52
52
|
version: '0.0.1',
|
|
53
53
|
name: 'Human-in-the-Loop',
|
|
@@ -83,7 +83,7 @@ export const HUMAN_IN_THE_LOOP_LOOP_0_0_1 = {
|
|
|
83
83
|
icon: 'person',
|
|
84
84
|
emoji: '🙋',
|
|
85
85
|
};
|
|
86
|
-
export const
|
|
86
|
+
export const OODA_STRATEGY_0_0_1 = {
|
|
87
87
|
id: 'ooda',
|
|
88
88
|
version: '0.0.1',
|
|
89
89
|
name: 'OODA Loop',
|
|
@@ -112,7 +112,7 @@ export const OODA_LOOP_0_0_1 = {
|
|
|
112
112
|
icon: 'sync',
|
|
113
113
|
emoji: '🔄',
|
|
114
114
|
};
|
|
115
|
-
export const
|
|
115
|
+
export const PLAN_EXECUTE_CRITIC_STRATEGY_0_0_1 = {
|
|
116
116
|
id: 'plan-execute-critic',
|
|
117
117
|
version: '0.0.1',
|
|
118
118
|
name: 'Plan / Execute / Critic Loop',
|
|
@@ -148,41 +148,41 @@ export const PLAN_EXECUTE_CRITIC_LOOP_0_0_1 = {
|
|
|
148
148
|
emoji: '✅',
|
|
149
149
|
};
|
|
150
150
|
// ============================================================================
|
|
151
|
-
//
|
|
151
|
+
// Strategy Catalog
|
|
152
152
|
// ============================================================================
|
|
153
|
-
export const
|
|
154
|
-
'data-analysis':
|
|
155
|
-
'human-in-the-loop':
|
|
156
|
-
ooda:
|
|
157
|
-
'plan-execute-critic':
|
|
153
|
+
export const STRATEGY_CATALOGUE = {
|
|
154
|
+
'data-analysis': DATA_ANALYSIS_STRATEGY_0_0_1,
|
|
155
|
+
'human-in-the-loop': HUMAN_IN_THE_LOOP_STRATEGY_0_0_1,
|
|
156
|
+
ooda: OODA_STRATEGY_0_0_1,
|
|
157
|
+
'plan-execute-critic': PLAN_EXECUTE_CRITIC_STRATEGY_0_0_1,
|
|
158
158
|
};
|
|
159
|
-
export const
|
|
160
|
-
function
|
|
161
|
-
if (
|
|
162
|
-
return
|
|
163
|
-
const idx =
|
|
159
|
+
export const DEFAULT_STRATEGY = Strategies.DATA_ANALYSIS;
|
|
160
|
+
function resolveStrategyId(strategyId) {
|
|
161
|
+
if (strategyId in STRATEGY_CATALOGUE)
|
|
162
|
+
return strategyId;
|
|
163
|
+
const idx = strategyId.lastIndexOf(':');
|
|
164
164
|
if (idx > 0) {
|
|
165
|
-
const base =
|
|
166
|
-
if (base in
|
|
165
|
+
const base = strategyId.slice(0, idx);
|
|
166
|
+
if (base in STRATEGY_CATALOGUE)
|
|
167
167
|
return base;
|
|
168
168
|
}
|
|
169
|
-
return
|
|
169
|
+
return strategyId;
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
* Get a
|
|
172
|
+
* Get a strategy specification by ID.
|
|
173
173
|
*/
|
|
174
|
-
export function
|
|
175
|
-
return
|
|
174
|
+
export function getStrategy(strategyId) {
|
|
175
|
+
return STRATEGY_CATALOGUE[resolveStrategyId(strategyId)];
|
|
176
176
|
}
|
|
177
177
|
/**
|
|
178
|
-
* Get the default
|
|
178
|
+
* Get the default strategy.
|
|
179
179
|
*/
|
|
180
|
-
export function
|
|
181
|
-
return
|
|
180
|
+
export function getDefaultStrategy() {
|
|
181
|
+
return STRATEGY_CATALOGUE[DEFAULT_STRATEGY];
|
|
182
182
|
}
|
|
183
183
|
/**
|
|
184
|
-
* List all available
|
|
184
|
+
* List all available strategies.
|
|
185
185
|
*/
|
|
186
|
-
export function
|
|
187
|
-
return Object.values(
|
|
186
|
+
export function listStrategies() {
|
|
187
|
+
return Object.values(STRATEGY_CATALOGUE);
|
|
188
188
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export * from './execution';
|
|
|
20
20
|
export * from './uiPlugins';
|
|
21
21
|
export * from './guardrails';
|
|
22
22
|
export * from './inference';
|
|
23
|
-
export * from './
|
|
23
|
+
export * from './strategies';
|
|
24
24
|
export * from './mcp';
|
|
25
25
|
export * from './memory';
|
|
26
26
|
export * from './messages';
|
package/lib/types/index.js
CHANGED
|
@@ -24,7 +24,7 @@ export * from './execution';
|
|
|
24
24
|
export * from './uiPlugins';
|
|
25
25
|
export * from './guardrails';
|
|
26
26
|
export * from './inference';
|
|
27
|
-
export * from './
|
|
27
|
+
export * from './strategies';
|
|
28
28
|
export * from './mcp';
|
|
29
29
|
export * from './memory';
|
|
30
30
|
export * from './messages';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* How the human participates in (or around) an agent
|
|
2
|
+
* How the human participates in (or around) an agent reasoning strategy.
|
|
3
3
|
*/
|
|
4
|
-
export interface
|
|
4
|
+
export interface StrategyHuman {
|
|
5
5
|
/** Human interaction pattern: none, initiate, approve, feedback, or tool */
|
|
6
6
|
mode: string;
|
|
7
|
-
/** Whether the
|
|
7
|
+
/** Whether the strategy pauses for human approval before sensitive actions */
|
|
8
8
|
approvalRequired: boolean;
|
|
9
9
|
/** Actions that require explicit human approval */
|
|
10
10
|
approvalFor: string[];
|
|
@@ -12,48 +12,48 @@ export interface LoopHuman {
|
|
|
12
12
|
description: string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* When and how an agent
|
|
15
|
+
* When and how an agent reasoning strategy stops iterating.
|
|
16
16
|
*/
|
|
17
|
-
export interface
|
|
18
|
-
/** Maximum iterations before the
|
|
17
|
+
export interface StrategyTermination {
|
|
18
|
+
/** Maximum iterations before the strategy is stopped */
|
|
19
19
|
maxIterations: number;
|
|
20
20
|
/** Conditions that mark the goal as reached */
|
|
21
21
|
successCriteria: string[];
|
|
22
|
-
/** Conditions that mark the
|
|
22
|
+
/** Conditions that mark the strategy as failed */
|
|
23
23
|
failureCriteria: string[];
|
|
24
24
|
/** What to do when blocked: ask-human, retry, or abort */
|
|
25
25
|
onBlocked: string;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Specification for an agent
|
|
28
|
+
* Specification for an agent reasoning strategy (a control loop).
|
|
29
29
|
*
|
|
30
30
|
* A framework-agnostic description of how an agent progresses from one
|
|
31
31
|
* decision to the next: the control cycle (observe/think/act/evaluate), the
|
|
32
32
|
* objective, constraints, where state lives, human participation, and the
|
|
33
33
|
* termination policy.
|
|
34
34
|
*/
|
|
35
|
-
export interface
|
|
36
|
-
/** Unique
|
|
35
|
+
export interface StrategySpec {
|
|
36
|
+
/** Unique strategy identifier (e.g., 'data-analysis') */
|
|
37
37
|
id: string;
|
|
38
38
|
/** Version */
|
|
39
39
|
version: string;
|
|
40
|
-
/** Display name for the
|
|
40
|
+
/** Display name for the strategy */
|
|
41
41
|
name: string;
|
|
42
|
-
/**
|
|
42
|
+
/** Strategy description */
|
|
43
43
|
description: string;
|
|
44
|
-
/** Default goal/objective the
|
|
44
|
+
/** Default goal/objective the strategy works toward */
|
|
45
45
|
objective: string;
|
|
46
|
-
/**
|
|
46
|
+
/** Strategy family */
|
|
47
47
|
strategy: string;
|
|
48
48
|
/** Ordered phase names that make up one iteration */
|
|
49
49
|
phases: string[];
|
|
50
50
|
/** Boundaries the agent must respect */
|
|
51
51
|
constraints: string[];
|
|
52
52
|
/** Termination policy */
|
|
53
|
-
termination?:
|
|
53
|
+
termination?: StrategyTermination;
|
|
54
54
|
/** Human-in-the-loop participation settings */
|
|
55
|
-
human?:
|
|
56
|
-
/** Where
|
|
55
|
+
human?: StrategyHuman;
|
|
56
|
+
/** Where strategy state lives between iterations */
|
|
57
57
|
stateBackends: string[];
|
|
58
58
|
/** Categorization tags */
|
|
59
59
|
tags: string[];
|
package/package.json
CHANGED
|
@@ -1616,7 +1616,7 @@ export * from './teams';
|
|
|
1616
1616
|
export * from './envvars';
|
|
1617
1617
|
export * from './evals';
|
|
1618
1618
|
export * from './guardrails';
|
|
1619
|
-
export * from './
|
|
1619
|
+
export * from './strategies';
|
|
1620
1620
|
export * from './mcpServers';
|
|
1621
1621
|
export * from './memory';
|
|
1622
1622
|
export * from './models';
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
# Distributed under the terms of the Modified BSD License.
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
|
-
Generate Python and TypeScript code from YAML
|
|
6
|
+
Generate Python and TypeScript code from YAML strategy specifications.
|
|
7
7
|
|
|
8
|
-
A *
|
|
9
|
-
|
|
10
|
-
constraints and success criteria that bound it, where state lives
|
|
11
|
-
iterations, how the human participates, and when
|
|
8
|
+
A *strategy* is the control loop an agent reasons with: how it progresses from
|
|
9
|
+
one decision to the next (observe/think/act/evaluate), the objective it works
|
|
10
|
+
toward, the constraints and success criteria that bound it, where state lives
|
|
11
|
+
between iterations, how the human participates, and when it terminates.
|
|
12
12
|
|
|
13
13
|
Usage:
|
|
14
|
-
python
|
|
15
|
-
--specs-dir agentspecs/agentspecs/
|
|
16
|
-
--python-output agent_runtimes/specs/
|
|
17
|
-
--typescript-output src/specs/
|
|
14
|
+
python generate_strategies.py \\
|
|
15
|
+
--specs-dir agentspecs/agentspecs/strategies \\
|
|
16
|
+
--python-output agent_runtimes/specs/strategies.py \\
|
|
17
|
+
--typescript-output src/specs/strategies.ts
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
import argparse
|
|
@@ -26,14 +26,14 @@ import yaml
|
|
|
26
26
|
from versioning import ensure_spec_version, version_suffix
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def _make_const_name(
|
|
30
|
-
"""Convert a
|
|
31
|
-
return f"{
|
|
29
|
+
def _make_const_name(strategy_id: str) -> str:
|
|
30
|
+
"""Convert a strategy ID to a constant name (e.g., 'ooda' -> 'OODA_STRATEGY')."""
|
|
31
|
+
return f"{strategy_id.upper().replace('-', '_')}_STRATEGY"
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def _make_enum_name(
|
|
35
|
-
"""Convert a
|
|
36
|
-
return
|
|
34
|
+
def _make_enum_name(strategy_id: str) -> str:
|
|
35
|
+
"""Convert a strategy ID to an enum member name (e.g., 'data-analysis' -> 'DATA_ANALYSIS')."""
|
|
36
|
+
return strategy_id.upper().replace("-", "_")
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def _clean(text: str) -> str:
|
|
@@ -65,8 +65,8 @@ def _ts_list(items: list) -> str:
|
|
|
65
65
|
return "[" + ", ".join(_ts_str(item) for item in items) + "]"
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def
|
|
69
|
-
"""Load all
|
|
68
|
+
def load_strategy_specs(specs_dir: Path) -> list[dict[str, Any]]:
|
|
69
|
+
"""Load all strategy YAML specifications from a directory."""
|
|
70
70
|
specs = []
|
|
71
71
|
for yaml_file in sorted(specs_dir.glob("*.yaml")):
|
|
72
72
|
with open(yaml_file) as f:
|
|
@@ -77,14 +77,14 @@ def load_loop_specs(specs_dir: Path) -> list[dict[str, Any]]:
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
80
|
-
"""Generate Python code from
|
|
80
|
+
"""Generate Python code from strategy specifications."""
|
|
81
81
|
lines = [
|
|
82
82
|
"# Copyright (c) 2025-2026 Datalayer, Inc.",
|
|
83
83
|
"# Distributed under the terms of the Modified BSD License.",
|
|
84
84
|
'"""',
|
|
85
|
-
"
|
|
85
|
+
"Strategy Catalog.",
|
|
86
86
|
"",
|
|
87
|
-
"Predefined agent
|
|
87
|
+
"Predefined agent reasoning strategies (control loops) that agents can use.",
|
|
88
88
|
"",
|
|
89
89
|
"This file is AUTO-GENERATED from YAML specifications.",
|
|
90
90
|
"DO NOT EDIT MANUALLY - run 'make specs' to regenerate.",
|
|
@@ -93,16 +93,16 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
93
93
|
"from enum import Enum",
|
|
94
94
|
"from typing import Optional",
|
|
95
95
|
"",
|
|
96
|
-
"from agent_runtimes.types import
|
|
96
|
+
"from agent_runtimes.types import StrategyHuman, StrategySpec, StrategyTermination",
|
|
97
97
|
"",
|
|
98
98
|
"",
|
|
99
99
|
"# " + "=" * 76,
|
|
100
|
-
"#
|
|
100
|
+
"# Strategies Enum",
|
|
101
101
|
"# " + "=" * 76,
|
|
102
102
|
"",
|
|
103
103
|
"",
|
|
104
|
-
"class
|
|
105
|
-
' """Enumeration of available agent
|
|
104
|
+
"class Strategies(str, Enum):",
|
|
105
|
+
' """Enumeration of available agent reasoning strategies."""',
|
|
106
106
|
"",
|
|
107
107
|
]
|
|
108
108
|
|
|
@@ -114,7 +114,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
114
114
|
"",
|
|
115
115
|
"",
|
|
116
116
|
"# " + "=" * 76,
|
|
117
|
-
"#
|
|
117
|
+
"# Strategy Definitions",
|
|
118
118
|
"# " + "=" * 76,
|
|
119
119
|
"",
|
|
120
120
|
]
|
|
@@ -124,7 +124,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
124
124
|
version = spec["version"]
|
|
125
125
|
const_name = _make_const_name(spec["id"]) + version_suffix(version)
|
|
126
126
|
|
|
127
|
-
lines.append(f"{const_name} =
|
|
127
|
+
lines.append(f"{const_name} = StrategySpec(")
|
|
128
128
|
lines.append(f' id="{spec["id"]}",')
|
|
129
129
|
lines.append(f' version="{version}",')
|
|
130
130
|
lines.append(f' name="{spec["name"]}",')
|
|
@@ -138,7 +138,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
138
138
|
|
|
139
139
|
term = spec.get("termination")
|
|
140
140
|
if term:
|
|
141
|
-
lines.append(" termination=
|
|
141
|
+
lines.append(" termination=StrategyTermination(")
|
|
142
142
|
lines.append(
|
|
143
143
|
f" max_iterations={int(term.get('max_iterations', 10))},"
|
|
144
144
|
)
|
|
@@ -155,7 +155,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
155
155
|
|
|
156
156
|
human = spec.get("human")
|
|
157
157
|
if human:
|
|
158
|
-
lines.append(" human=
|
|
158
|
+
lines.append(" human=StrategyHuman(")
|
|
159
159
|
lines.append(f" mode={_py_str(human.get('mode', 'initiate'))},")
|
|
160
160
|
lines.append(
|
|
161
161
|
f" approval_required={bool(human.get('approval_required', False))},"
|
|
@@ -179,10 +179,10 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
179
179
|
[
|
|
180
180
|
"",
|
|
181
181
|
"# " + "=" * 76,
|
|
182
|
-
"#
|
|
182
|
+
"# Strategy Catalog",
|
|
183
183
|
"# " + "=" * 76,
|
|
184
184
|
"",
|
|
185
|
-
"
|
|
185
|
+
"STRATEGY_CATALOGUE: dict[str, StrategySpec] = {",
|
|
186
186
|
]
|
|
187
187
|
)
|
|
188
188
|
|
|
@@ -195,46 +195,46 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
195
195
|
"}",
|
|
196
196
|
"",
|
|
197
197
|
"",
|
|
198
|
-
'
|
|
198
|
+
'DEFAULT_STRATEGY: str = "data-analysis"',
|
|
199
199
|
"",
|
|
200
200
|
"",
|
|
201
|
-
"def
|
|
201
|
+
"def get_strategy(strategy_id: str) -> Optional[StrategySpec]:",
|
|
202
202
|
' """',
|
|
203
|
-
" Get a
|
|
203
|
+
" Get a strategy specification by ID (accepts both bare and versioned refs).",
|
|
204
204
|
"",
|
|
205
205
|
" Args:",
|
|
206
|
-
"
|
|
206
|
+
" strategy_id: The unique identifier of the strategy.",
|
|
207
207
|
"",
|
|
208
208
|
" Returns:",
|
|
209
|
-
" The
|
|
209
|
+
" The StrategySpec, or None if not found.",
|
|
210
210
|
' """',
|
|
211
|
-
"
|
|
212
|
-
" if
|
|
213
|
-
" return
|
|
214
|
-
" base, _, ver =
|
|
211
|
+
" strategy = STRATEGY_CATALOGUE.get(strategy_id)",
|
|
212
|
+
" if strategy is not None:",
|
|
213
|
+
" return strategy",
|
|
214
|
+
" base, _, ver = strategy_id.rpartition(':')",
|
|
215
215
|
" if base and '.' in ver:",
|
|
216
|
-
" return
|
|
216
|
+
" return STRATEGY_CATALOGUE.get(base)",
|
|
217
217
|
" return None",
|
|
218
218
|
"",
|
|
219
219
|
"",
|
|
220
|
-
"def
|
|
220
|
+
"def get_default_strategy() -> Optional[StrategySpec]:",
|
|
221
221
|
' """',
|
|
222
|
-
" Get the default
|
|
222
|
+
" Get the default strategy.",
|
|
223
223
|
"",
|
|
224
224
|
" Returns:",
|
|
225
|
-
" The default
|
|
225
|
+
" The default StrategySpec, or None if no default is set.",
|
|
226
226
|
' """',
|
|
227
|
-
" return
|
|
227
|
+
" return STRATEGY_CATALOGUE.get(DEFAULT_STRATEGY)",
|
|
228
228
|
"",
|
|
229
229
|
"",
|
|
230
|
-
"def
|
|
230
|
+
"def list_strategies() -> list[StrategySpec]:",
|
|
231
231
|
' """',
|
|
232
|
-
" List all available
|
|
232
|
+
" List all available strategies.",
|
|
233
233
|
"",
|
|
234
234
|
" Returns:",
|
|
235
|
-
" List of all
|
|
235
|
+
" List of all StrategySpec specifications.",
|
|
236
236
|
' """',
|
|
237
|
-
" return list(
|
|
237
|
+
" return list(STRATEGY_CATALOGUE.values())",
|
|
238
238
|
"",
|
|
239
239
|
]
|
|
240
240
|
)
|
|
@@ -243,7 +243,7 @@ def generate_python_code(specs: list[dict[str, Any]]) -> str:
|
|
|
243
243
|
|
|
244
244
|
|
|
245
245
|
def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
246
|
-
"""Generate TypeScript code from
|
|
246
|
+
"""Generate TypeScript code from strategy specifications."""
|
|
247
247
|
lines = [
|
|
248
248
|
"/*",
|
|
249
249
|
" * Copyright (c) 2025-2026 Datalayer, Inc.",
|
|
@@ -251,21 +251,21 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
251
251
|
" */",
|
|
252
252
|
"",
|
|
253
253
|
"/**",
|
|
254
|
-
" *
|
|
254
|
+
" * Strategy Catalog",
|
|
255
255
|
" *",
|
|
256
|
-
" * Predefined agent
|
|
256
|
+
" * Predefined agent reasoning strategies (control loops).",
|
|
257
257
|
" *",
|
|
258
258
|
" * This file is AUTO-GENERATED from YAML specifications.",
|
|
259
259
|
" * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.",
|
|
260
260
|
" */",
|
|
261
261
|
"",
|
|
262
|
-
"import type {
|
|
262
|
+
"import type { StrategySpec } from '../types';",
|
|
263
263
|
"",
|
|
264
264
|
"// " + "=" * 76,
|
|
265
|
-
"//
|
|
265
|
+
"// Strategies Enum",
|
|
266
266
|
"// " + "=" * 76,
|
|
267
267
|
"",
|
|
268
|
-
"export const
|
|
268
|
+
"export const Strategies = {",
|
|
269
269
|
]
|
|
270
270
|
|
|
271
271
|
for spec in specs:
|
|
@@ -275,10 +275,10 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
275
275
|
[
|
|
276
276
|
"} as const;",
|
|
277
277
|
"",
|
|
278
|
-
"export type
|
|
278
|
+
"export type StrategyId = (typeof Strategies)[keyof typeof Strategies];",
|
|
279
279
|
"",
|
|
280
280
|
"// " + "=" * 76,
|
|
281
|
-
"//
|
|
281
|
+
"// Strategy Definitions",
|
|
282
282
|
"// " + "=" * 76,
|
|
283
283
|
"",
|
|
284
284
|
]
|
|
@@ -288,7 +288,7 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
288
288
|
version = spec["version"]
|
|
289
289
|
const_name = _make_const_name(spec["id"]) + version_suffix(version)
|
|
290
290
|
|
|
291
|
-
lines.append(f"export const {const_name}:
|
|
291
|
+
lines.append(f"export const {const_name}: StrategySpec = {{")
|
|
292
292
|
lines.append(f" id: '{spec['id']}',")
|
|
293
293
|
lines.append(f" version: '{version}',")
|
|
294
294
|
lines.append(f" name: {_ts_str(spec['name'])},")
|
|
@@ -336,10 +336,10 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
336
336
|
lines.extend(
|
|
337
337
|
[
|
|
338
338
|
"// " + "=" * 76,
|
|
339
|
-
"//
|
|
339
|
+
"// Strategy Catalog",
|
|
340
340
|
"// " + "=" * 76,
|
|
341
341
|
"",
|
|
342
|
-
"export const
|
|
342
|
+
"export const STRATEGY_CATALOGUE: Record<string, StrategySpec> = {",
|
|
343
343
|
]
|
|
344
344
|
)
|
|
345
345
|
|
|
@@ -351,37 +351,37 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
351
351
|
[
|
|
352
352
|
"};",
|
|
353
353
|
"",
|
|
354
|
-
"export const
|
|
354
|
+
"export const DEFAULT_STRATEGY: StrategyId = Strategies.DATA_ANALYSIS;",
|
|
355
355
|
"",
|
|
356
|
-
"function
|
|
357
|
-
" if (
|
|
358
|
-
" const idx =
|
|
356
|
+
"function resolveStrategyId(strategyId: string): string {",
|
|
357
|
+
" if (strategyId in STRATEGY_CATALOGUE) return strategyId;",
|
|
358
|
+
" const idx = strategyId.lastIndexOf(':');",
|
|
359
359
|
" if (idx > 0) {",
|
|
360
|
-
" const base =
|
|
361
|
-
" if (base in
|
|
360
|
+
" const base = strategyId.slice(0, idx);",
|
|
361
|
+
" if (base in STRATEGY_CATALOGUE) return base;",
|
|
362
362
|
" }",
|
|
363
|
-
" return
|
|
363
|
+
" return strategyId;",
|
|
364
364
|
"}",
|
|
365
365
|
"",
|
|
366
366
|
"/**",
|
|
367
|
-
" * Get a
|
|
367
|
+
" * Get a strategy specification by ID.",
|
|
368
368
|
" */",
|
|
369
|
-
"export function
|
|
370
|
-
" return
|
|
369
|
+
"export function getStrategy(strategyId: string): StrategySpec | undefined {",
|
|
370
|
+
" return STRATEGY_CATALOGUE[resolveStrategyId(strategyId)];",
|
|
371
371
|
"}",
|
|
372
372
|
"",
|
|
373
373
|
"/**",
|
|
374
|
-
" * Get the default
|
|
374
|
+
" * Get the default strategy.",
|
|
375
375
|
" */",
|
|
376
|
-
"export function
|
|
377
|
-
" return
|
|
376
|
+
"export function getDefaultStrategy(): StrategySpec | undefined {",
|
|
377
|
+
" return STRATEGY_CATALOGUE[DEFAULT_STRATEGY];",
|
|
378
378
|
"}",
|
|
379
379
|
"",
|
|
380
380
|
"/**",
|
|
381
|
-
" * List all available
|
|
381
|
+
" * List all available strategies.",
|
|
382
382
|
" */",
|
|
383
|
-
"export function
|
|
384
|
-
" return Object.values(
|
|
383
|
+
"export function listStrategies(): StrategySpec[] {",
|
|
384
|
+
" return Object.values(STRATEGY_CATALOGUE);",
|
|
385
385
|
"}",
|
|
386
386
|
"",
|
|
387
387
|
]
|
|
@@ -393,13 +393,13 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
|
|
|
393
393
|
def main():
|
|
394
394
|
"""Main entry point."""
|
|
395
395
|
parser = argparse.ArgumentParser(
|
|
396
|
-
description="Generate Python and TypeScript code from YAML
|
|
396
|
+
description="Generate Python and TypeScript code from YAML strategy specifications"
|
|
397
397
|
)
|
|
398
398
|
parser.add_argument(
|
|
399
399
|
"--specs-dir",
|
|
400
400
|
type=Path,
|
|
401
401
|
required=True,
|
|
402
|
-
help="Directory containing YAML
|
|
402
|
+
help="Directory containing YAML strategy specification files",
|
|
403
403
|
)
|
|
404
404
|
parser.add_argument(
|
|
405
405
|
"--python-output",
|
|
@@ -420,9 +420,9 @@ def main():
|
|
|
420
420
|
print(f"Error: Specs directory does not exist: {args.specs_dir}")
|
|
421
421
|
sys.exit(1)
|
|
422
422
|
|
|
423
|
-
print(f"Loading
|
|
424
|
-
specs =
|
|
425
|
-
print(f"Loaded {len(specs)}
|
|
423
|
+
print(f"Loading strategy specs from {args.specs_dir}...")
|
|
424
|
+
specs = load_strategy_specs(args.specs_dir)
|
|
425
|
+
print(f"Loaded {len(specs)} strategy specifications")
|
|
426
426
|
|
|
427
427
|
print("Generating Python code...")
|
|
428
428
|
python_code = generate_python_code(specs)
|
|
@@ -436,7 +436,7 @@ def main():
|
|
|
436
436
|
args.typescript_output.write_text(typescript_code)
|
|
437
437
|
print(f"✓ Generated {args.typescript_output}")
|
|
438
438
|
|
|
439
|
-
print(f"\n✓ Successfully generated code from {len(specs)}
|
|
439
|
+
print(f"\n✓ Successfully generated code from {len(specs)} strategy specs")
|
|
440
440
|
|
|
441
441
|
|
|
442
442
|
if __name__ == "__main__":
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ServiceManager } from '@jupyterlab/services';
|
|
2
|
-
interface AgentLoopExampleInnerProps {
|
|
3
|
-
serviceManager?: ServiceManager.IManager;
|
|
4
|
-
}
|
|
5
|
-
export declare function AgentLoopExampleInner({ serviceManager, }: AgentLoopExampleInnerProps): import("react").JSX.Element;
|
|
6
|
-
/**
|
|
7
|
-
* Main example component with Jupyter provider wrapper.
|
|
8
|
-
*/
|
|
9
|
-
export declare function AgentLoopExample({ serviceManager, }: {
|
|
10
|
-
serviceManager?: ServiceManager.IManager;
|
|
11
|
-
}): import("react").JSX.Element;
|
|
12
|
-
export default AgentLoopExample;
|
package/lib/specs/loops.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Loop Catalog
|
|
3
|
-
*
|
|
4
|
-
* Predefined agent execution-loop specifications.
|
|
5
|
-
*
|
|
6
|
-
* This file is AUTO-GENERATED from YAML specifications.
|
|
7
|
-
* DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
|
|
8
|
-
*/
|
|
9
|
-
import type { LoopSpec } from '../types';
|
|
10
|
-
export declare const Loops: {
|
|
11
|
-
readonly DATA_ANALYSIS: "data-analysis";
|
|
12
|
-
readonly HUMAN_IN_THE_LOOP: "human-in-the-loop";
|
|
13
|
-
readonly OODA: "ooda";
|
|
14
|
-
readonly PLAN_EXECUTE_CRITIC: "plan-execute-critic";
|
|
15
|
-
};
|
|
16
|
-
export type LoopId = (typeof Loops)[keyof typeof Loops];
|
|
17
|
-
export declare const DATA_ANALYSIS_LOOP_0_0_1: LoopSpec;
|
|
18
|
-
export declare const HUMAN_IN_THE_LOOP_LOOP_0_0_1: LoopSpec;
|
|
19
|
-
export declare const OODA_LOOP_0_0_1: LoopSpec;
|
|
20
|
-
export declare const PLAN_EXECUTE_CRITIC_LOOP_0_0_1: LoopSpec;
|
|
21
|
-
export declare const LOOP_CATALOGUE: Record<string, LoopSpec>;
|
|
22
|
-
export declare const DEFAULT_LOOP: LoopId;
|
|
23
|
-
/**
|
|
24
|
-
* Get a loop specification by ID.
|
|
25
|
-
*/
|
|
26
|
-
export declare function getLoop(loopId: string): LoopSpec | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Get the default loop.
|
|
29
|
-
*/
|
|
30
|
-
export declare function getDefaultLoop(): LoopSpec | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* List all available loops.
|
|
33
|
-
*/
|
|
34
|
-
export declare function listLoops(): LoopSpec[];
|
|
File without changes
|