@datalayer/agent-runtimes 1.5.39 โ†’ 1.5.42

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.
@@ -572,6 +572,77 @@ export const AUTOMATE_REGULATORY_REPORTING_TEAM_SPEC_0_0_1 = {
572
572
  storage: 's3://reports/regulatory-submissions/',
573
573
  },
574
574
  };
575
+ export const CODING_AGENTS_TEAM_SPEC_0_0_1 = {
576
+ id: 'coding-agents',
577
+ version: '0.0.1',
578
+ name: 'Coding Agents',
579
+ description: `Claude Code writes the change and Codex reviews it, each behind the Shield: a supervisor delegates to them over ACP with a budget, a deadline and the files it may touch, and reads back their plans and their diffs.`,
580
+ tags: ['coding', 'harness', 'review'],
581
+ enabled: true,
582
+ icon: 'code',
583
+ emoji: '๐Ÿ›ก๏ธ',
584
+ color: '#1F6FEB',
585
+ agentSpecId: '',
586
+ orchestrationProtocol: 'datalayer',
587
+ executionMode: 'sequential',
588
+ supervisor: {
589
+ name: 'Lead',
590
+ ref: '',
591
+ model: 'bedrock:us.anthropic.claude-sonnet-4-6',
592
+ goal: `Split the request into a change and its review: hand the change to the Coder with the files it may touch, then the diff to the Reviewer, and answer with the change and what the review found.`,
593
+ instructions: `You lead two coding agents. Hand the change to the Coder with the files it may touch and a deadline, wait for its diff, hand the diff to the Reviewer, and answer with the change and the review. Never edit a file yourself.`,
594
+ approval: 'auto',
595
+ canTerminate: true,
596
+ },
597
+ routingInstructions: ``,
598
+ suggestions: [
599
+ {
600
+ text: 'Add a test for the function in the open file, then review it.',
601
+ summary: 'A change and its review',
602
+ icon: 'code',
603
+ emoji: '๐Ÿงช',
604
+ },
605
+ ],
606
+ delegation: {
607
+ maxDepth: 2,
608
+ allowPeerDelegation: false,
609
+ includeGeneralPurpose: false,
610
+ },
611
+ context: { sharing: 'shared' },
612
+ validation: undefined,
613
+ agents: [
614
+ {
615
+ id: 'coder',
616
+ name: 'Coder',
617
+ ref: '',
618
+ harness: 'claude-code',
619
+ role: 'contributor',
620
+ goal: `Make the change asked, inside the workspace, in the files the manifest names; answer with what changed and why.`,
621
+ dependsOn: [],
622
+ subagents: [],
623
+ model: '',
624
+ mcpServer: '',
625
+ tools: [],
626
+ trigger: '',
627
+ approval: 'auto',
628
+ },
629
+ {
630
+ id: 'reviewer',
631
+ name: 'Reviewer',
632
+ ref: '',
633
+ harness: 'codex',
634
+ role: 'reviewer',
635
+ goal: `Read the Coder's diff and say what is wrong with it, file by file; edit nothing.`,
636
+ dependsOn: ['coder'],
637
+ subagents: [],
638
+ model: '',
639
+ mcpServer: '',
640
+ tools: [],
641
+ trigger: '',
642
+ approval: 'auto',
643
+ },
644
+ ],
645
+ };
575
646
  export const COMPREHENSIVE_SALES_ANALYTICS_TEAM_SPEC_0_0_1 = {
576
647
  id: 'comprehensive-sales-analytics',
577
648
  version: '0.0.1',
@@ -704,9 +775,9 @@ export const COMPREHENSIVE_SALES_ANALYTICS_TEAM_SPEC_0_0_1 = {
704
775
  storage: 's3://reports/sales-analytics/',
705
776
  },
706
777
  };
707
- export const CROP_MONITORING_TEAM_SPEC_0_0_1 = {
778
+ export const CROP_MONITORING_TEAM_SPEC_0_0_2 = {
708
779
  id: 'crop-monitoring',
709
- version: '0.0.1',
780
+ version: '0.0.2',
710
781
  name: 'Crop Monitoring',
711
782
  description: `One agent, its data: Crop Monitoring follows crop vigour and growth over a season from the satellite imagery NASA Earthdata holds, and flags the fields that need attention.`,
712
783
  tags: [
@@ -780,9 +851,9 @@ export const CROP_MONITORING_TEAM_SPEC_0_0_1 = {
780
851
  },
781
852
  ],
782
853
  };
783
- export const DISASTER_ASSESSMENT_TEAM_SPEC_0_0_1 = {
854
+ export const DISASTER_ASSESSMENT_TEAM_SPEC_0_0_2 = {
784
855
  id: 'disaster-assessment',
785
- version: '0.0.1',
856
+ version: '0.0.2',
786
857
  name: 'Disaster Assessment',
787
858
  description: `An event desk in the browser that gets the area a disaster affected and the damage from Disaster Assessment, and what changed on the ground from Change detection, each on a runtime over A2A, each reading NASA Earthdata. Event response takes the event and reports; the two others read the imagery and answer.`,
788
859
  tags: [
@@ -1117,9 +1188,9 @@ export const JUPYTER_TEAM_SPEC_0_0_1 = {
1117
1188
  storage: '',
1118
1189
  },
1119
1190
  };
1120
- export const MONTH_END_CLOSE_TEAM_SPEC_0_0_1 = {
1191
+ export const MONTH_END_CLOSE_TEAM_SPEC_0_0_2 = {
1121
1192
  id: 'month-end-close',
1122
- version: '0.0.1',
1193
+ version: '0.0.2',
1123
1194
  name: 'Month-end Close',
1124
1195
  description: `One agent, its data: Month-end Close drives the close from the Odoo books, which it only reads โ€” the checklist, the accruals to book, the reconciliation gaps that remain.`,
1125
1196
  tags: ['example', 'scene', 'accounting', 'finance', 'odoo', 'a2a'],
@@ -1719,9 +1790,9 @@ export const PROCESS_CLINICAL_TRIAL_DATA_TEAM_SPEC_0_0_1 = {
1719
1790
  storage: 's3://reports/clinical-trials/',
1720
1791
  },
1721
1792
  };
1722
- export const SALES_AND_ACCOUNTING_TEAM_SPEC_0_0_1 = {
1793
+ export const SALES_AND_ACCOUNTING_TEAM_SPEC_0_0_2 = {
1723
1794
  id: 'sales-and-accounting',
1724
- version: '0.0.1',
1795
+ version: '0.0.2',
1725
1796
  name: 'Sales and Accounting',
1726
1797
  description: `A sales desk in the browser that gets financial reports from an accounting application on a runtime, over A2A. Sales takes the request and reports the answer; Accounting reads the Odoo books and answers.`,
1727
1798
  tags: ['example', 'sales', 'accounting', 'finance', 'a2a', 'odoo'],
@@ -1940,16 +2011,17 @@ export const TEAM_SPECS = {
1940
2011
  'analyze-support-tickets': ANALYZE_SUPPORT_TICKETS_TEAM_SPEC_0_0_1,
1941
2012
  'audit-inventory-levels': AUDIT_INVENTORY_LEVELS_TEAM_SPEC_0_0_1,
1942
2013
  'automate-regulatory-reporting': AUTOMATE_REGULATORY_REPORTING_TEAM_SPEC_0_0_1,
2014
+ 'coding-agents': CODING_AGENTS_TEAM_SPEC_0_0_1,
1943
2015
  'comprehensive-sales-analytics': COMPREHENSIVE_SALES_ANALYTICS_TEAM_SPEC_0_0_1,
1944
- 'crop-monitoring': CROP_MONITORING_TEAM_SPEC_0_0_1,
1945
- 'disaster-assessment': DISASTER_ASSESSMENT_TEAM_SPEC_0_0_1,
2016
+ 'crop-monitoring': CROP_MONITORING_TEAM_SPEC_0_0_2,
2017
+ 'disaster-assessment': DISASTER_ASSESSMENT_TEAM_SPEC_0_0_2,
1946
2018
  jupyter: JUPYTER_TEAM_SPEC_0_0_1,
1947
- 'month-end-close': MONTH_END_CLOSE_TEAM_SPEC_0_0_1,
2019
+ 'month-end-close': MONTH_END_CLOSE_TEAM_SPEC_0_0_2,
1948
2020
  'notebook-benchmark': NOTEBOOK_BENCHMARK_TEAM_SPEC_0_0_1,
1949
2021
  'optimize-grid-operations': OPTIMIZE_GRID_OPERATIONS_TEAM_SPEC_0_0_1,
1950
2022
  'process-citizen-requests': PROCESS_CITIZEN_REQUESTS_TEAM_SPEC_0_0_1,
1951
2023
  'process-clinical-trial-data': PROCESS_CLINICAL_TRIAL_DATA_TEAM_SPEC_0_0_1,
1952
- 'sales-and-accounting': SALES_AND_ACCOUNTING_TEAM_SPEC_0_0_1,
2024
+ 'sales-and-accounting': SALES_AND_ACCOUNTING_TEAM_SPEC_0_0_2,
1953
2025
  'sync-crm-contacts': SYNC_CRM_CONTACTS_TEAM_SPEC_0_0_1,
1954
2026
  };
1955
2027
  function resolveTeamId(teamId) {
@@ -238,7 +238,7 @@ export interface PolicySpec {
238
238
  description: string;
239
239
  enabled: boolean;
240
240
  tags: string[];
241
- /** The Shield's document: scope, version, rules, limits, network, mcp, harnesses. */
241
+ /** The Shield's document: scope, version, rules, limits, network, mcp, harnesses, authorize, authorizer. */
242
242
  policy: {
243
243
  scope: 'organization' | 'team' | 'session';
244
244
  version?: number;
@@ -267,6 +267,32 @@ export interface PolicySpec {
267
267
  admit?: string[];
268
268
  credentials?: 'account' | 'platform' | 'either';
269
269
  };
270
+ /** The classes that need an authorizer's allow beside the Rules (SHIELD ยง6.11). */
271
+ authorize?: Array<'read' | 'write' | 'send' | 'buy' | 'delete' | 'execute'>;
272
+ /** The standalone Shield's decision point: exactly one of these. */
273
+ authorizer?: {
274
+ local?: {
275
+ grants?: Array<{
276
+ subject: string;
277
+ relation: string;
278
+ object: string;
279
+ }>;
280
+ };
281
+ openfga?: {
282
+ url: string;
283
+ store: string;
284
+ model?: string | null;
285
+ };
286
+ authzen?: {
287
+ url: string;
288
+ headers?: Record<string, string>;
289
+ };
290
+ opa?: {
291
+ url: string;
292
+ package?: string;
293
+ headers?: Record<string, string>;
294
+ };
295
+ } | null;
270
296
  };
271
297
  }
272
298
  /**
@@ -334,6 +360,26 @@ export interface StandardSpec {
334
360
  }>;
335
361
  controls: StandardControl[];
336
362
  }
363
+ /**
364
+ * A harness of the register's *listed* tier (SHIELD SH-57): known to speak ACP,
365
+ * its documented command, licence, terms and credential read and cited; not
366
+ * drilled, so offered by nothing โ€” naming one is refused *listed, not drilled yet*.
367
+ */
368
+ export interface ListedHarness {
369
+ id: string;
370
+ name: string;
371
+ docs: string;
372
+ adapter: string;
373
+ version: string;
374
+ /** The launch command its project documents; null when undocumented. */
375
+ command: string | null;
376
+ licence: string;
377
+ licenceSource: string;
378
+ termsSource: string;
379
+ credential: string;
380
+ servedToThirdParties: 'api_key_only' | 'permitted' | 'refused' | 'unknown';
381
+ note: string;
382
+ }
337
383
  export interface HarnessSpec {
338
384
  /** What `harness:` names (e.g. 'claude-code'). */
339
385
  id: string;
@@ -66,7 +66,7 @@ export interface TeamLinkSpec {
66
66
  /** The member asked, by its id in the team. */
67
67
  member: string;
68
68
  /** The protocol: `a2a` to an agent or an application, `mcp` to a server member. */
69
- over: 'a2a' | 'mcp';
69
+ over: 'a2a' | 'mcp' | 'acp';
70
70
  }
71
71
  export interface TeamAgentspec {
72
72
  /** Agent identifier within the team */
@@ -91,6 +91,12 @@ export interface TeamAgentspec {
91
91
  * (LOOP A-04). It asks nobody.
92
92
  */
93
93
  server?: string;
94
+ /**
95
+ * Harness catalogue id, in place of `ref`, `app` and `server`: the member is
96
+ * that agent program over ACP behind the Shield โ€” Claude Code, Codex, an
97
+ * organization's own โ€” asked over A2A or ACP (SHIELD SH-45).
98
+ */
99
+ harness?: string;
94
100
  /** Where its loop turns: in the person's `browser`, or on a `runtime`. */
95
101
  runsIn?: 'browser' | 'runtime';
96
102
  /** The members it asks directly while it works, and over what. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.39",
3
+ "version": "1.5.42",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -209,7 +209,22 @@ def _t(value: Any) -> str:
209
209
  return json.dumps(" ".join(str(value or "").split()), ensure_ascii=False)
210
210
 
211
211
 
212
- def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
212
+ def load_listed(specs_dir: Path) -> list[dict[str, Any]]:
213
+ """The register's listed tier (SH-57): known to speak ACP, not drilled, offered by nothing."""
214
+ register = yaml.safe_load((specs_dir / REGISTER).read_text()) or {}
215
+ return sorted(
216
+ (
217
+ entry
218
+ for entry in register.get("entries") or []
219
+ if entry.get("tier") == "listed"
220
+ ),
221
+ key=lambda entry: str(entry["harness"]),
222
+ )
223
+
224
+
225
+ def generate_typescript_code(
226
+ specs: list[dict[str, Any]], listed: list[dict[str, Any]] = ()
227
+ ) -> str:
213
228
  lines = [
214
229
  "/*",
215
230
  " * Copyright (c) 2025-2026 Datalayer, Inc.",
@@ -225,7 +240,7 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
225
240
  " * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.",
226
241
  " */",
227
242
  "",
228
- "import type { HarnessSpec } from '../types/agentspecs';",
243
+ "import type { HarnessSpec, ListedHarness } from '../types/agentspecs';",
229
244
  ]
230
245
  for spec in specs:
231
246
  acp = spec.get("acp")
@@ -307,6 +322,27 @@ def generate_typescript_code(specs: list[dict[str, Any]]) -> str:
307
322
  " return Object.values(HARNESS_CATALOGUE);",
308
323
  "}",
309
324
  "",
325
+ "/**",
326
+ " * The register's listed tier (SH-57): agents known to speak ACP, registered",
327
+ " * with their documented command and their terms, not drilled โ€” offered by",
328
+ " * nothing until moved to the catalogue.",
329
+ " */",
330
+ "export const LISTED_HARNESSES: ListedHarness[] = [",
331
+ *[
332
+ " {"
333
+ + f" id: {_t(entry['harness'])}, name: {_t(entry.get('name'))}, docs: {_t(entry.get('docs'))},"
334
+ + f" adapter: {_t(entry.get('adapter'))}, version: {_t(entry.get('version'))},"
335
+ + f" command: {_t(entry['command']) if entry.get('command') else 'null'},"
336
+ + f" licence: {_t(entry.get('licence'))}, licenceSource: {_t(entry.get('licence_source'))},"
337
+ + f" termsSource: {_t(entry.get('terms_source'))}, credential: {_t(entry.get('credential'))},"
338
+ + f" servedToThirdParties: {_t(entry.get('served_to_third_parties'))}, note: {_t(entry.get('note'))} }},"
339
+ for entry in listed
340
+ ],
341
+ "];",
342
+ "",
343
+ "/** The sentence a listed harness is refused in (agentspecs' LISTED_NOT_DRILLED). */",
344
+ "export const LISTED_NOT_DRILLED = 'listed, not drilled yet';",
345
+ "",
310
346
  ]
311
347
  return "\n".join(lines)
312
348
 
@@ -319,7 +355,9 @@ def main() -> None:
319
355
  args = parser.parse_args()
320
356
  specs = load_harness_specs(args.specs_dir)
321
357
  args.python_output.write_text(generate_python_code(specs))
322
- args.typescript_output.write_text(generate_typescript_code(specs))
358
+ args.typescript_output.write_text(
359
+ generate_typescript_code(specs, load_listed(args.specs_dir))
360
+ )
323
361
  print(
324
362
  f"Generated {len(specs)} harnesses: {args.python_output}, {args.typescript_output}"
325
363
  )
@@ -153,6 +153,8 @@ def _generate_team_agent_py(agent: Dict[str, Any]) -> str:
153
153
  lines.append(f' app="{agent["app"]}",')
154
154
  if agent.get("server"):
155
155
  lines.append(f' server="{agent["server"]}",')
156
+ if agent.get("harness"):
157
+ lines.append(f' harness="{agent["harness"]}",')
156
158
  if agent.get("runs_in"):
157
159
  lines.append(f' runs_in="{agent["runs_in"]}",')
158
160
  links = agent.get("talks_to") or []
@@ -223,6 +225,7 @@ def _generate_team_agent_ts(agent: Dict[str, Any]) -> str:
223
225
  application = (
224
226
  (f"\n app: '{agent['app']}'," if agent.get("app") else "")
225
227
  + (f"\n server: '{agent['server']}'," if agent.get("server") else "")
228
+ + (f"\n harness: '{agent['harness']}'," if agent.get("harness") else "")
226
229
  + (f"\n runsIn: '{agent['runs_in']}'," if agent.get("runs_in") else "")
227
230
  + (
228
231
  "\n talksTo: ["