@datalayer/agent-runtimes 1.3.15 → 1.3.17
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/lib/chat/base/ChatBase.js +3 -2
- package/lib/config/AgentConfiguration.d.ts +1 -1
- package/lib/loop/apps/AppRenderer.d.ts +24 -0
- package/lib/loop/apps/AppRenderer.js +101 -0
- package/lib/loop/apps/appspec.d.ts +69 -0
- package/lib/loop/apps/appspec.js +566 -0
- package/lib/loop/apps/checks.d.ts +21 -0
- package/lib/loop/apps/checks.js +556 -0
- package/lib/loop/apps/index.d.ts +10 -0
- package/lib/loop/apps/index.js +14 -0
- package/lib/loop/apps/rules.d.ts +64 -0
- package/lib/loop/apps/rules.js +289 -0
- package/lib/loop/apps/yaml.d.ts +17 -0
- package/lib/loop/apps/yaml.js +185 -0
- package/lib/loop/embed/LoopEmbed.d.ts +6 -1
- package/lib/loop/embed/LoopEmbed.js +3 -2
- package/lib/loop/index.d.ts +1 -0
- package/lib/loop/index.js +3 -0
- package/lib/loop/plugins/chat/ChatView.js +9 -4
- package/lib/loop/plugins/chat/index.d.ts +10 -0
- package/lib/loop/plugins/chat/index.js +1 -0
- package/lib/loop/presets.d.ts +6 -0
- package/lib/loop/presets.js +2 -1
- package/lib/loop/shell/LoopWorkspace.d.ts +14 -0
- package/lib/loop/shell/LoopWorkspace.js +20 -6
- package/lib/loop/shell/index.d.ts +1 -1
- package/lib/loop/shell/index.js +1 -1
- package/lib/loop/shell/useWorkspaceFullScreen.d.ts +17 -4
- package/lib/loop/shell/useWorkspaceFullScreen.js +23 -6
- package/lib/specs/actions.d.ts +30 -0
- package/lib/specs/actions.js +616 -0
- package/lib/specs/agents/agents.d.ts +1 -0
- package/lib/specs/agents/agents.js +338 -284
- package/lib/specs/apps.d.ts +25 -0
- package/lib/specs/apps.js +1064 -0
- package/lib/specs/cogs.d.ts +19 -0
- package/lib/specs/cogs.js +736 -0
- package/lib/specs/events.d.ts +6 -1
- package/lib/specs/events.js +144 -1
- package/lib/specs/frames.d.ts +19 -0
- package/lib/specs/frames.js +444 -0
- package/lib/specs/gates.d.ts +22 -0
- package/lib/specs/gates.js +177 -0
- package/lib/specs/guards.d.ts +26 -0
- package/lib/specs/guards.js +930 -0
- package/lib/specs/index.d.ts +10 -0
- package/lib/specs/index.js +10 -0
- package/lib/specs/mcpServers.js +2 -2
- package/lib/specs/memory.js +4 -0
- package/lib/specs/modelProviders.d.ts +22 -0
- package/lib/specs/modelProviders.js +102 -0
- package/lib/specs/models.d.ts +31 -0
- package/lib/specs/models.js +215 -0
- package/lib/specs/ops.d.ts +15 -0
- package/lib/specs/ops.js +1272 -0
- package/lib/specs/outputs.js +2 -2
- package/lib/specs/skills.js +1 -1
- package/lib/specs/teams/teams.js +18 -18
- package/lib/specs/tracks.d.ts +15 -0
- package/lib/specs/tracks.js +87 -0
- package/lib/specs/uiPlugins.d.ts +16 -0
- package/lib/specs/uiPlugins.js +40 -0
- package/lib/types/agentspecs.d.ts +453 -2
- package/lib/types/memory.d.ts +2 -0
- package/lib/types/models.d.ts +52 -0
- package/package.json +2 -1
- package/scripts/check-cloudflare-models.py +122 -0
- package/scripts/codegen/agentspecs_clone.py +53 -0
- package/scripts/codegen/compose.py +65 -0
- package/scripts/codegen/generate_agents.py +14 -4
- package/scripts/codegen/generate_apps.py +454 -0
- package/scripts/codegen/generate_cogs.py +308 -0
- package/scripts/codegen/generate_frames.py +278 -0
- package/scripts/codegen/generate_memory.py +2 -0
- package/scripts/codegen/generate_model_providers.py +246 -0
- package/scripts/codegen/generate_models.py +135 -4
- package/scripts/codegen/generate_ops.py +388 -0
- package/scripts/codegen/generate_sandbox_agents.py +1 -1
- package/scripts/codegen/generate_ui_plugins.py +226 -0
- package/scripts/gen_workers.py +2 -2
|
@@ -74,6 +74,457 @@ export interface AgentCapability {
|
|
|
74
74
|
/** Free text, for humans reading a catalogue; never matched on. */
|
|
75
75
|
tags?: string[];
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* How an agent's answer becomes an interface: a protocol the host renders
|
|
79
|
+
* (`agentspecs/ui-plugins`). An agent spec's `uiPlugin` names one.
|
|
80
|
+
*/
|
|
81
|
+
export interface UIPluginSpec {
|
|
82
|
+
/** What an agent spec's `uiPlugin` names (e.g. 'a2ui'). */
|
|
83
|
+
id: string;
|
|
84
|
+
version: string;
|
|
85
|
+
name: string;
|
|
86
|
+
/** What the plugin renders, and how the user's action comes back. */
|
|
87
|
+
description: string;
|
|
88
|
+
/** The protocol's own documentation. */
|
|
89
|
+
docsUrl: string;
|
|
90
|
+
/** Whether an agent spec may name it today. */
|
|
91
|
+
enabled: boolean;
|
|
92
|
+
}
|
|
93
|
+
/** A check a Frame requires of the output of work done under it. */
|
|
94
|
+
export interface FrameGuardSpec {
|
|
95
|
+
id: string;
|
|
96
|
+
/**
|
|
97
|
+
* What kind of check it is: algorithmic, source-grounding, consensus,
|
|
98
|
+
* expert, policy-safety, regression-drift or outcome.
|
|
99
|
+
*/
|
|
100
|
+
category: string;
|
|
101
|
+
description: string;
|
|
102
|
+
/** Whether the output counts only once this Guard has passed. */
|
|
103
|
+
required: boolean;
|
|
104
|
+
}
|
|
105
|
+
/** A reusable prompt fragment a Cog loads into its context. */
|
|
106
|
+
export interface FramePromptSpec {
|
|
107
|
+
id: string;
|
|
108
|
+
text: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The context work happens in, written down (`agentspecs/frames`): owned,
|
|
112
|
+
* scoped, versioned and inherited. A Frame in the generated catalogue is
|
|
113
|
+
* resolved — what it inherits through `extends` is already in it.
|
|
114
|
+
*/
|
|
115
|
+
export interface FrameSpec {
|
|
116
|
+
id: string;
|
|
117
|
+
version: string;
|
|
118
|
+
name: string;
|
|
119
|
+
description: string;
|
|
120
|
+
/** organization, department, team, project, role or relationship. */
|
|
121
|
+
scope: string;
|
|
122
|
+
/** Who manages the Frame and answers for it. */
|
|
123
|
+
owner: string;
|
|
124
|
+
/** The parent Frame, as the spec names it. */
|
|
125
|
+
extends?: string;
|
|
126
|
+
/** The Frames it inherits from, nearest parent first. */
|
|
127
|
+
lineage: string[];
|
|
128
|
+
tags: string[];
|
|
129
|
+
/** Whether a Cog may name it today. */
|
|
130
|
+
enabled: boolean;
|
|
131
|
+
icon?: string;
|
|
132
|
+
emoji?: string;
|
|
133
|
+
rules: string[];
|
|
134
|
+
terminology: Record<string, string>;
|
|
135
|
+
goals: string[];
|
|
136
|
+
style: string[];
|
|
137
|
+
norms: string[];
|
|
138
|
+
process: string[];
|
|
139
|
+
architecture: string;
|
|
140
|
+
prompts: FramePromptSpec[];
|
|
141
|
+
skills: string[];
|
|
142
|
+
tools: string[];
|
|
143
|
+
mcpServers: string[];
|
|
144
|
+
guards: FrameGuardSpec[];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* An AI worker you can hold to account (`agentspecs/cogs`): a Cog extends an
|
|
148
|
+
* agent spec and is equipped with Frames. In the generated catalogue it is
|
|
149
|
+
* resolved — `spec` is the agent with the Cog's changes and its Frames.
|
|
150
|
+
*/
|
|
151
|
+
export interface CogSpec {
|
|
152
|
+
id: string;
|
|
153
|
+
version: string;
|
|
154
|
+
name: string;
|
|
155
|
+
description: string;
|
|
156
|
+
/** The id of the agent spec it extends. */
|
|
157
|
+
agent: string;
|
|
158
|
+
/** The Frames it works under, in order. */
|
|
159
|
+
frames: string[];
|
|
160
|
+
/** Every Frame that contributed: the named ones and those they inherit from. */
|
|
161
|
+
lineage: string[];
|
|
162
|
+
/** What the Cog packages: context, model or combined. */
|
|
163
|
+
kind: string;
|
|
164
|
+
/** Whether it is offered today. */
|
|
165
|
+
enabled: boolean;
|
|
166
|
+
/** The Guards its Frames declare: what its output answers to. */
|
|
167
|
+
guards: FrameGuardSpec[];
|
|
168
|
+
/** The Cog as an agent spec, resolved and ready to launch. */
|
|
169
|
+
spec: Agentspec;
|
|
170
|
+
}
|
|
171
|
+
/** Something a Guard reports, which a Gate's condition reads. */
|
|
172
|
+
export interface GuardSignalSpec {
|
|
173
|
+
name: string;
|
|
174
|
+
/** boolean, number or string. */
|
|
175
|
+
type: string;
|
|
176
|
+
description: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* A reusable check (`agentspecs/guards`): a Guard extends a guardrail. The
|
|
180
|
+
* guardrail is the policy; the Guard verifies that the work stayed within
|
|
181
|
+
* it. Resolved: it carries the guardrail's policy under its own identity.
|
|
182
|
+
*/
|
|
183
|
+
export interface GuardSpec extends GuardrailSpec {
|
|
184
|
+
id: string;
|
|
185
|
+
version: string;
|
|
186
|
+
name: string;
|
|
187
|
+
description: string;
|
|
188
|
+
/** The id of the guardrail it extends. */
|
|
189
|
+
guardrail: string;
|
|
190
|
+
/**
|
|
191
|
+
* algorithmic, source-grounding, consensus, expert, policy-safety,
|
|
192
|
+
* regression-drift or outcome.
|
|
193
|
+
*/
|
|
194
|
+
category: string;
|
|
195
|
+
/** preflight, in_flight, post_run, continuous: where it may run. */
|
|
196
|
+
stages: string[];
|
|
197
|
+
/** algorithmic, cog or human. */
|
|
198
|
+
method: string;
|
|
199
|
+
/** What is verified. */
|
|
200
|
+
check: string;
|
|
201
|
+
/** What it reports for a Gate to decide on. */
|
|
202
|
+
signals: GuardSignalSpec[];
|
|
203
|
+
/** Whether the work counts only once it has passed. */
|
|
204
|
+
required: boolean;
|
|
205
|
+
enabled: boolean;
|
|
206
|
+
tags: string[];
|
|
207
|
+
icon?: string;
|
|
208
|
+
emoji?: string;
|
|
209
|
+
}
|
|
210
|
+
/** A decision point of an Op (`agentspecs/gates`): Guards check, Gates decide. */
|
|
211
|
+
export interface GateSpec {
|
|
212
|
+
id: string;
|
|
213
|
+
version: string;
|
|
214
|
+
name: string;
|
|
215
|
+
description: string;
|
|
216
|
+
/** The stage it decides at. */
|
|
217
|
+
stage: string;
|
|
218
|
+
/** The Guards whose results it reads. */
|
|
219
|
+
guards: string[];
|
|
220
|
+
/** The condition on its Guards' signals, or `always`. */
|
|
221
|
+
when: string;
|
|
222
|
+
/** What happens when the condition holds. */
|
|
223
|
+
then: string;
|
|
224
|
+
/** What happens when it does not. */
|
|
225
|
+
otherwise: string;
|
|
226
|
+
/** The signals the condition reads. */
|
|
227
|
+
signals: string[];
|
|
228
|
+
/** The roles a decision is handed to. */
|
|
229
|
+
reviewers: string[];
|
|
230
|
+
maxRetries: number;
|
|
231
|
+
enabled: boolean;
|
|
232
|
+
tags: string[];
|
|
233
|
+
icon?: string;
|
|
234
|
+
emoji?: string;
|
|
235
|
+
}
|
|
236
|
+
/** What evidence a run keeps, and for how long (`agentspecs/tracks`). */
|
|
237
|
+
export interface TrackSpec {
|
|
238
|
+
id: string;
|
|
239
|
+
version: string;
|
|
240
|
+
name: string;
|
|
241
|
+
description: string;
|
|
242
|
+
/** The retention, e.g. `7_years`. */
|
|
243
|
+
retainFor: string;
|
|
244
|
+
retentionDays: number;
|
|
245
|
+
/** What a record has to include. */
|
|
246
|
+
include: string[];
|
|
247
|
+
/** The roles that may read a record. */
|
|
248
|
+
readers: string[];
|
|
249
|
+
/** Field patterns kept out of the record. */
|
|
250
|
+
redact: string[];
|
|
251
|
+
/** Whether corrections and overrides feed Organizational Memory. */
|
|
252
|
+
feedsMemory: boolean;
|
|
253
|
+
/** Whether a record may leave the Hub that produced it: it may not. */
|
|
254
|
+
exchangeable: boolean;
|
|
255
|
+
enabled: boolean;
|
|
256
|
+
tags: string[];
|
|
257
|
+
icon?: string;
|
|
258
|
+
emoji?: string;
|
|
259
|
+
}
|
|
260
|
+
/** A Cog as an Op names it. */
|
|
261
|
+
export interface OpCogSpec {
|
|
262
|
+
id: string;
|
|
263
|
+
/** The agent spec the Cog extends. */
|
|
264
|
+
agent: string;
|
|
265
|
+
frames: string[];
|
|
266
|
+
kind: string;
|
|
267
|
+
}
|
|
268
|
+
/** The Guards of an Op, by the stage they run at, each resolved. */
|
|
269
|
+
export interface OpGuardsSpec {
|
|
270
|
+
preflight: GuardSpec[];
|
|
271
|
+
inFlight: GuardSpec[];
|
|
272
|
+
postRun: GuardSpec[];
|
|
273
|
+
continuous: GuardSpec[];
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* An orchestrated, supervised workflow (`agentspecs/ops`): Cogs do the work,
|
|
277
|
+
* and a validation strategy says how it is verified — Guards by stage, the
|
|
278
|
+
* Gates that decide, the Track kept as evidence. Resolved: everything it
|
|
279
|
+
* names is in it.
|
|
280
|
+
*/
|
|
281
|
+
export interface OpSpec {
|
|
282
|
+
id: string;
|
|
283
|
+
version: string;
|
|
284
|
+
name: string;
|
|
285
|
+
description: string;
|
|
286
|
+
/** Who is accountable for the outcome. */
|
|
287
|
+
owner: string;
|
|
288
|
+
goal: string;
|
|
289
|
+
cogs: OpCogSpec[];
|
|
290
|
+
/** Frames applied at the workflow level. */
|
|
291
|
+
frames: string[];
|
|
292
|
+
/** Every Frame that orients the Op, its Cogs' included. */
|
|
293
|
+
lineage: string[];
|
|
294
|
+
supervisor: {
|
|
295
|
+
model: string;
|
|
296
|
+
instructions: string;
|
|
297
|
+
};
|
|
298
|
+
guards: OpGuardsSpec;
|
|
299
|
+
/** The checks its Frames declare. */
|
|
300
|
+
frameGuards: FrameGuardSpec[];
|
|
301
|
+
/** The Gates, in the order they are met. */
|
|
302
|
+
gates: GateSpec[];
|
|
303
|
+
track: TrackSpec;
|
|
304
|
+
/** launcher, command, button, schedule. */
|
|
305
|
+
triggers: string[];
|
|
306
|
+
enabled: boolean;
|
|
307
|
+
tags: string[];
|
|
308
|
+
icon?: string;
|
|
309
|
+
emoji?: string;
|
|
310
|
+
color?: string;
|
|
311
|
+
}
|
|
312
|
+
/** What a tool does to the world (`agentspecs.actions`). */
|
|
313
|
+
export type ActionClass = 'read' | 'write' | 'send' | 'buy' | 'delete' | 'publish';
|
|
314
|
+
/** An argument that makes a tool do something more than its own class. */
|
|
315
|
+
export interface ActionConditionSpec {
|
|
316
|
+
/** The argument of the call. */
|
|
317
|
+
argument: string;
|
|
318
|
+
/** Holds when the argument is any of these: a word, a number, true or false. */
|
|
319
|
+
equals?: Array<string | number | boolean>;
|
|
320
|
+
/** Holds when the argument's values include any of these. */
|
|
321
|
+
includes?: Array<string | number | boolean>;
|
|
322
|
+
/** What the tool is then, besides its own. */
|
|
323
|
+
classes: ActionClass[];
|
|
324
|
+
}
|
|
325
|
+
/** A condition, and what an application does when it holds. */
|
|
326
|
+
export interface AppEscalation extends ActionConditionSpec {
|
|
327
|
+
behaviour: AppBehaviour;
|
|
328
|
+
}
|
|
329
|
+
/** What the tools of an MCP server do. */
|
|
330
|
+
export interface ServerActionsSpec {
|
|
331
|
+
/** The day the tool names were read off the running server; absent when nobody looked. */
|
|
332
|
+
checked?: string;
|
|
333
|
+
/** The classes of a tool nothing else names; empty means unknown. */
|
|
334
|
+
default: ActionClass[];
|
|
335
|
+
/** What each tool does of its own, by name or pattern. */
|
|
336
|
+
tools: Record<string, ActionClass[]>;
|
|
337
|
+
/** What an argument makes a tool do besides, by tool. */
|
|
338
|
+
conditions: Record<string, ActionConditionSpec[]>;
|
|
339
|
+
}
|
|
340
|
+
/** What kind of application it is: what its user meets. */
|
|
341
|
+
export type AppKind = 'chat' | 'widget' | 'decision' | 'worker';
|
|
342
|
+
/** What an application does when it meets an action. */
|
|
343
|
+
export type AppBehaviour = 'do_it' | 'if_asked' | 'ask_first' | 'leave_to_me';
|
|
344
|
+
export type AppLayout = 'chat' | 'page' | 'split';
|
|
345
|
+
/** The one colour of an application; everything else is neutral. */
|
|
346
|
+
export type AppAccent = 'green' | 'rose' | 'sky' | 'lime' | 'sun' | 'violet';
|
|
347
|
+
/** Something an application reaches. */
|
|
348
|
+
export interface AppConnectionSpec {
|
|
349
|
+
/** An MCP server, `id` or `id:version`. */
|
|
350
|
+
server: string;
|
|
351
|
+
access: 'read' | 'write';
|
|
352
|
+
/** In whose name: the builder's account, or each user's own. */
|
|
353
|
+
as: 'owner' | 'user';
|
|
354
|
+
/** The tools it may use, by name or pattern; all when empty. */
|
|
355
|
+
only: string[];
|
|
356
|
+
}
|
|
357
|
+
/** When an application acts alone, and when it asks. */
|
|
358
|
+
export interface AppRuleSpec {
|
|
359
|
+
/** The action, in the words a person reads. */
|
|
360
|
+
action: string;
|
|
361
|
+
/** Classes of action, or tools (`server.tool`), the rule applies to. */
|
|
362
|
+
appliesTo: string[];
|
|
363
|
+
behaviour: AppBehaviour;
|
|
364
|
+
}
|
|
365
|
+
/** What an application may reach beside its connections. Nothing, unless said. */
|
|
366
|
+
export interface AppPermissionsSpec {
|
|
367
|
+
/** The Spaces it reads or writes. */
|
|
368
|
+
spaces: Array<{
|
|
369
|
+
space: string;
|
|
370
|
+
access: 'read' | 'write';
|
|
371
|
+
}>;
|
|
372
|
+
/** Its computer; each off until it is turned on. */
|
|
373
|
+
computer: {
|
|
374
|
+
browse: boolean;
|
|
375
|
+
files: boolean;
|
|
376
|
+
shell: boolean;
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
export interface AppStarterSpec {
|
|
380
|
+
label: string;
|
|
381
|
+
message: string;
|
|
382
|
+
}
|
|
383
|
+
export interface AppSettingSpec {
|
|
384
|
+
id: string;
|
|
385
|
+
type: 'select' | 'text' | 'toggle' | 'slider' | 'number';
|
|
386
|
+
label: string;
|
|
387
|
+
options: string[];
|
|
388
|
+
default?: string | boolean | number;
|
|
389
|
+
min?: number;
|
|
390
|
+
max?: number;
|
|
391
|
+
}
|
|
392
|
+
/** The component tree a user meets, over the approved catalog (A2UI). */
|
|
393
|
+
export interface AppSurfaceSpec {
|
|
394
|
+
protocol: string;
|
|
395
|
+
components: Array<{
|
|
396
|
+
id: string;
|
|
397
|
+
component: string;
|
|
398
|
+
[property: string]: unknown;
|
|
399
|
+
}>;
|
|
400
|
+
composedBy: string;
|
|
401
|
+
composedAt: string;
|
|
402
|
+
}
|
|
403
|
+
/** What the user of an application sees. */
|
|
404
|
+
export interface AppInterfaceSpec {
|
|
405
|
+
layout: AppLayout;
|
|
406
|
+
accent: AppAccent;
|
|
407
|
+
welcome: string;
|
|
408
|
+
starters: AppStarterSpec[];
|
|
409
|
+
settings: AppSettingSpec[];
|
|
410
|
+
/** The components of the catalog the surface may use. */
|
|
411
|
+
components: string[];
|
|
412
|
+
surface?: AppSurfaceSpec;
|
|
413
|
+
}
|
|
414
|
+
export interface AppTestCaseSpec {
|
|
415
|
+
ask: string;
|
|
416
|
+
expect: string;
|
|
417
|
+
}
|
|
418
|
+
/** How an application is verified. */
|
|
419
|
+
export interface AppTestsSpec {
|
|
420
|
+
/** The share of tests that has to pass for it to be ready. */
|
|
421
|
+
readyAt: number;
|
|
422
|
+
evalset: string;
|
|
423
|
+
cases: AppTestCaseSpec[];
|
|
424
|
+
}
|
|
425
|
+
/** What is kept of what an application did, and for how long. */
|
|
426
|
+
export interface AppRecordSpec {
|
|
427
|
+
/** The retention, e.g. `1_years`. */
|
|
428
|
+
keepFor: string;
|
|
429
|
+
retentionDays: number;
|
|
430
|
+
include: string[];
|
|
431
|
+
}
|
|
432
|
+
/** Optional checks from the catalogue. */
|
|
433
|
+
export interface AppChecksSpec {
|
|
434
|
+
guards: string[];
|
|
435
|
+
gates: string[];
|
|
436
|
+
track: string;
|
|
437
|
+
}
|
|
438
|
+
export interface AppDeploymentSpec {
|
|
439
|
+
hosted?: {
|
|
440
|
+
visibility: 'private' | 'invited' | 'organization' | 'link' | 'public';
|
|
441
|
+
slug: string;
|
|
442
|
+
};
|
|
443
|
+
embedded?: {
|
|
444
|
+
mode: 'inline' | 'bubble' | 'panel';
|
|
445
|
+
origins: string[];
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
/** What starts a worker's work. */
|
|
449
|
+
export interface AppTriggerSpec {
|
|
450
|
+
type: 'schedule' | 'event' | 'once';
|
|
451
|
+
cron: string;
|
|
452
|
+
event: string;
|
|
453
|
+
at: string;
|
|
454
|
+
description: string;
|
|
455
|
+
prompt: string;
|
|
456
|
+
}
|
|
457
|
+
export interface AppCriterionSpec {
|
|
458
|
+
name: string;
|
|
459
|
+
kind: 'metric' | 'noul' | 'choice' | 'score';
|
|
460
|
+
weight: number;
|
|
461
|
+
instructions: string;
|
|
462
|
+
options: string[];
|
|
463
|
+
direction: 'higher' | 'lower';
|
|
464
|
+
measure: '' | 'pass_rate' | 'cost_per_task' | 'seconds_per_task';
|
|
465
|
+
}
|
|
466
|
+
export interface AppScenarioSpec {
|
|
467
|
+
name: string;
|
|
468
|
+
weights: Record<string, number>;
|
|
469
|
+
}
|
|
470
|
+
/** What a decision application decides. */
|
|
471
|
+
export interface AppDecisionSpec {
|
|
472
|
+
question: string;
|
|
473
|
+
alternatives: string[];
|
|
474
|
+
criteria: AppCriterionSpec[];
|
|
475
|
+
minConfidence: number;
|
|
476
|
+
scenarios: AppScenarioSpec[];
|
|
477
|
+
judgmentModel: string;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* An application (`agentspecs/apps`): the Appspec. An agent with an interface,
|
|
481
|
+
* rules, tests and a place to run — a chat, a widget, a decision or a worker.
|
|
482
|
+
* It stands alone: Guards, Gates and a Track are optional, under `checks`.
|
|
483
|
+
* In the generated catalogue it carries its layout, and what it names that
|
|
484
|
+
* is not enabled (`setup`).
|
|
485
|
+
*/
|
|
486
|
+
export interface AppSpec {
|
|
487
|
+
/** The version of the spec itself: `loop.app/v1`. */
|
|
488
|
+
schema: string;
|
|
489
|
+
id: string;
|
|
490
|
+
version: string;
|
|
491
|
+
name: string;
|
|
492
|
+
kind: AppKind;
|
|
493
|
+
description: string;
|
|
494
|
+
owner: string;
|
|
495
|
+
/** The agent or the Cog that does the work; empty when a team does. */
|
|
496
|
+
agent: string;
|
|
497
|
+
team: string;
|
|
498
|
+
instructions: string;
|
|
499
|
+
model: string;
|
|
500
|
+
skills: string[];
|
|
501
|
+
tools: string[];
|
|
502
|
+
/** The Frames it works under. */
|
|
503
|
+
context: string[];
|
|
504
|
+
/** The documents and datasets it answers from. */
|
|
505
|
+
contents: string[];
|
|
506
|
+
connections: AppConnectionSpec[];
|
|
507
|
+
rules: AppRuleSpec[];
|
|
508
|
+
permissions: AppPermissionsSpec;
|
|
509
|
+
interface: AppInterfaceSpec;
|
|
510
|
+
tests: AppTestsSpec;
|
|
511
|
+
record: AppRecordSpec;
|
|
512
|
+
checks: AppChecksSpec;
|
|
513
|
+
deployment: AppDeploymentSpec;
|
|
514
|
+
/** For a worker: what it works toward. */
|
|
515
|
+
goal: string;
|
|
516
|
+
triggers: AppTriggerSpec[];
|
|
517
|
+
memory: string;
|
|
518
|
+
notifications: string[];
|
|
519
|
+
decision?: AppDecisionSpec;
|
|
520
|
+
/** What it names that is not enabled today, in sentences. */
|
|
521
|
+
setup: string[];
|
|
522
|
+
enabled: boolean;
|
|
523
|
+
tags: string[];
|
|
524
|
+
icon?: string;
|
|
525
|
+
/** Its face: one emoji, shown wherever the application appears. */
|
|
526
|
+
emoji: string;
|
|
527
|
+
}
|
|
77
528
|
export interface Agentspec {
|
|
78
529
|
/** Unique agent identifier */
|
|
79
530
|
id: string;
|
|
@@ -154,8 +605,8 @@ export interface Agentspec {
|
|
|
154
605
|
delegable?: AgentCapability[];
|
|
155
606
|
/** Communication protocol (e.g., 'ag-ui', 'acp', 'a2a', 'vercel-ai') */
|
|
156
607
|
protocol?: string;
|
|
157
|
-
/** UI
|
|
158
|
-
|
|
608
|
+
/** UI plugin (e.g., 'a2ui', 'mcp-apps'), one of the `UI_PLUGIN_CATALOGUE`. */
|
|
609
|
+
uiPlugin?: string;
|
|
159
610
|
/** Trigger configuration (type, cron, event source, prompt) */
|
|
160
611
|
trigger?: AgentTriggerConfig;
|
|
161
612
|
/** Model configuration (temperature, max_tokens) */
|
package/lib/types/memory.d.ts
CHANGED
package/lib/types/models.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface AIModel {
|
|
|
13
13
|
description: string;
|
|
14
14
|
/** Provider name (anthropic, openai, bedrock, azure-openai) */
|
|
15
15
|
provider: string;
|
|
16
|
+
/** The page on the provider's website that describes this model. */
|
|
17
|
+
providerUrl?: string;
|
|
16
18
|
/** Whether this is the default model */
|
|
17
19
|
default: boolean;
|
|
18
20
|
/**
|
|
@@ -46,6 +48,56 @@ export interface AIModel {
|
|
|
46
48
|
* 'thinking'. Empty means unstated rather than incapable.
|
|
47
49
|
*/
|
|
48
50
|
capabilities?: string[];
|
|
51
|
+
/** How the provider bills it, when worth telling: 'standard' or 'credits'. */
|
|
52
|
+
billing?: 'standard' | 'credits';
|
|
53
|
+
/**
|
|
54
|
+
* How a Cloudflare model is reached: 'workers-ai' (a model Cloudflare
|
|
55
|
+
* hosts, ids 'cloudflare:wrk/…') or 'ai-gateway' (a third-party model its
|
|
56
|
+
* gateway fronts, ids 'cloudflare:gtw/…').
|
|
57
|
+
*/
|
|
58
|
+
route?: 'workers-ai' | 'ai-gateway';
|
|
59
|
+
/** The tokens a request may carry, input and output together. */
|
|
60
|
+
contextWindow?: number;
|
|
61
|
+
/** Whether the provider keeps nothing of a request once it is answered. */
|
|
62
|
+
zeroDataRetention?: boolean;
|
|
63
|
+
/** The provider's list price per million tokens, when a service meters by it. */
|
|
64
|
+
pricing?: {
|
|
65
|
+
inputUsdPerMillion: number;
|
|
66
|
+
outputUsdPerMillion: number;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Where the route keeps a log of the requests it carries, apart from what
|
|
70
|
+
* the provider retains: 'none', or 'gateway' (AI Gateway's request logs).
|
|
71
|
+
* Read beside zeroDataRetention.
|
|
72
|
+
*/
|
|
73
|
+
requestLogging?: 'none' | 'gateway';
|
|
74
|
+
/** Older ids this spec answers to, kept when an id had to move. */
|
|
75
|
+
aliases?: string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Who serves a model: the vendor's own API, a cloud that hosts it, or the
|
|
79
|
+
* user's machine — with what a person choosing it has to be able to read
|
|
80
|
+
* (`agentspecs/model-providers`).
|
|
81
|
+
*/
|
|
82
|
+
export interface ModelProvider {
|
|
83
|
+
/** What a model spec's `provider` names (e.g. 'anthropic'). */
|
|
84
|
+
id: string;
|
|
85
|
+
version: string;
|
|
86
|
+
name: string;
|
|
87
|
+
/** What the provider is, and what is worth knowing before choosing it. */
|
|
88
|
+
description: string;
|
|
89
|
+
/** The provider's product page. */
|
|
90
|
+
website?: string;
|
|
91
|
+
/** The provider's documentation. */
|
|
92
|
+
docsUrl?: string;
|
|
93
|
+
/** The terms of service a call is made under. */
|
|
94
|
+
termsUrl?: string;
|
|
95
|
+
/** The provider's privacy policy. */
|
|
96
|
+
privacyUrl?: string;
|
|
97
|
+
/** What the provider says about the data a request carries, when it has a page for it. */
|
|
98
|
+
dataUsageUrl?: string;
|
|
99
|
+
/** Where the model runs: the provider's cloud, or the user's machine. */
|
|
100
|
+
hosting: 'cloud' | 'local';
|
|
49
101
|
}
|
|
50
102
|
/**
|
|
51
103
|
* Configuration for an AI model runtime (as returned by the server).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalayer/agent-runtimes",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -264,6 +264,7 @@
|
|
|
264
264
|
"uuid": "^13.0.0",
|
|
265
265
|
"validator": "^13.7.0",
|
|
266
266
|
"vaul": "^1.1.2",
|
|
267
|
+
"yaml": "^2.9.0",
|
|
267
268
|
"zod": "^4.1.13",
|
|
268
269
|
"zustand": "^4.4.1"
|
|
269
270
|
},
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026 Datalayer, Inc.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
"""Hold the Cloudflare model specs to what Cloudflare serves.
|
|
5
|
+
|
|
6
|
+
The catalogue moves — a model the specs could have named in September had
|
|
7
|
+
been deprecated in May — so this reads the account's own listing and says
|
|
8
|
+
which spec names a model no longer served, which served model with tool
|
|
9
|
+
calling has no spec, and where a spec's context differs from the listing's.
|
|
10
|
+
Run by hand, with the account's token::
|
|
11
|
+
|
|
12
|
+
CLOUDFLARE_ACCOUNT_ID=… CLOUDFLARE_API_TOKEN=… python scripts/check-cloudflare-models.py
|
|
13
|
+
|
|
14
|
+
The names are the ones datalayer-ai-inference reads (``DATALAYER_CLOUDFLARE_*``
|
|
15
|
+
are read too). Exits 1 when a spec names a model that is not served.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
import urllib.request
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
import yaml
|
|
27
|
+
|
|
28
|
+
SPECS = Path(__file__).resolve().parent.parent / "agentspecs" / "agentspecs" / "models"
|
|
29
|
+
API = "https://api.cloudflare.com/client/v4/accounts"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def env(*names: str) -> str:
|
|
33
|
+
for name in names:
|
|
34
|
+
value = (os.environ.get(name) or "").strip()
|
|
35
|
+
if value:
|
|
36
|
+
return value
|
|
37
|
+
return ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def served(account: str, token: str) -> dict[str, dict]:
|
|
41
|
+
"""Every text-generation model Cloudflare lists for the account, by name."""
|
|
42
|
+
models: dict[str, dict] = {}
|
|
43
|
+
page = 1
|
|
44
|
+
while True:
|
|
45
|
+
request = urllib.request.Request(
|
|
46
|
+
f"{API}/{account}/ai/models/search?task=Text%20Generation&per_page=100&page={page}",
|
|
47
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
48
|
+
)
|
|
49
|
+
# The address is the constant https `API` above, never caller input.
|
|
50
|
+
with urllib.request.urlopen(request, timeout=60) as response: # nosec B310
|
|
51
|
+
answer = json.load(response)
|
|
52
|
+
if not answer.get("success"):
|
|
53
|
+
raise SystemExit(f"Cloudflare refused the listing: {answer.get('errors')}")
|
|
54
|
+
for model in answer.get("result") or []:
|
|
55
|
+
properties = {
|
|
56
|
+
p.get("property_id"): p.get("value")
|
|
57
|
+
for p in model.get("properties") or []
|
|
58
|
+
}
|
|
59
|
+
models[model["name"]] = {
|
|
60
|
+
# The listing says it as a string: "true".
|
|
61
|
+
"tools": str(properties.get("function_calling")).lower() == "true",
|
|
62
|
+
"context": properties.get("context_window"),
|
|
63
|
+
}
|
|
64
|
+
if len(answer.get("result") or []) < 100:
|
|
65
|
+
return models
|
|
66
|
+
page += 1
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def specs() -> list[dict]:
|
|
70
|
+
"""The Workers AI specs (``cloudflare-wrk-*.yaml``) that name a model Cloudflare
|
|
71
|
+
hosts under ``@cf/``. The gateway flavour (``cloudflare-gtw-*``) and the typed
|
|
72
|
+
judgment models (``typesafe/jev``, with no ``@cf/`` namespace) are not in the
|
|
73
|
+
account's model listing and are left out.
|
|
74
|
+
"""
|
|
75
|
+
found = []
|
|
76
|
+
for path in sorted(SPECS.glob("cloudflare-wrk-*.yaml")):
|
|
77
|
+
with open(path) as handle:
|
|
78
|
+
data = yaml.safe_load(handle) or {}
|
|
79
|
+
if "judgments" in (data.get("capabilities") or []):
|
|
80
|
+
continue
|
|
81
|
+
found.append({"file": path.name, **data})
|
|
82
|
+
return found
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main() -> int:
|
|
86
|
+
account = env("CLOUDFLARE_ACCOUNT_ID", "DATALAYER_CLOUDFLARE_ACCOUNT_ID")
|
|
87
|
+
token = env(
|
|
88
|
+
"CLOUDFLARE_API_TOKEN",
|
|
89
|
+
"DATALAYER_CLOUDFLARE_API_TOKEN",
|
|
90
|
+
"DATALAYER_CLOUDFLARE_ACCOUNT_API_TOKEN",
|
|
91
|
+
)
|
|
92
|
+
if not account or not token:
|
|
93
|
+
print(
|
|
94
|
+
"CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN are needed", file=sys.stderr
|
|
95
|
+
)
|
|
96
|
+
return 2
|
|
97
|
+
listing = served(account, token)
|
|
98
|
+
named = {}
|
|
99
|
+
failures = 0
|
|
100
|
+
for spec in specs():
|
|
101
|
+
name = "@cf/" + spec["id"].split(":", 1)[1]
|
|
102
|
+
named[name] = spec
|
|
103
|
+
entry = listing.get(name)
|
|
104
|
+
if entry is None:
|
|
105
|
+
failures += 1
|
|
106
|
+
print(f"NOT SERVED {spec['file']}: Cloudflare no longer lists {name}")
|
|
107
|
+
continue
|
|
108
|
+
if "tools" in (spec.get("capabilities") or []) and not entry["tools"]:
|
|
109
|
+
print(
|
|
110
|
+
f"NO TOOLS {spec['file']}: the listing says {name} has no function calling"
|
|
111
|
+
)
|
|
112
|
+
print(f"ok {spec['file']}: {name} (context {entry['context']})")
|
|
113
|
+
for name, entry in sorted(listing.items()):
|
|
114
|
+
if entry["tools"] and name not in named:
|
|
115
|
+
print(
|
|
116
|
+
f"unlisted {name} has tool calling and no spec (context {entry['context']})"
|
|
117
|
+
)
|
|
118
|
+
return 1 if failures else 0
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
sys.exit(main())
|