@particle-academy/agent-integrations 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4093,7 +4093,15 @@ function registerDocBridge(host, options) {
4093
4093
  const disposers = [];
4094
4094
  ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
4095
4095
  let idSeq = 0;
4096
- const mintId = () => adapter.newId?.() ?? `${surface}-${idSeq += 1}`;
4096
+ const mintId = () => {
4097
+ if (adapter.newId) return adapter.newId();
4098
+ const taken = adapter.get().nodes;
4099
+ let id;
4100
+ do
4101
+ id = `${surface}-${idSeq += 1}`;
4102
+ while (taken[id]);
4103
+ return id;
4104
+ };
4097
4105
  const target = (elementId) => ({ kind: surface, screenId: adapter.screenId, elementId });
4098
4106
  const pending = /* @__PURE__ */ new Map();
4099
4107
  function commit(op, label, targetId) {
@@ -4112,10 +4120,10 @@ function registerDocBridge(host, options) {
4112
4120
  }
4113
4121
  function submit(op, label, targetId) {
4114
4122
  if (stage(op) === "confirm") {
4115
- const id = `${surface}-pending-${idSeq += 1}`;
4116
- pending.set(id, { op, label, targetId });
4117
- options.onPending?.({ id, op, label });
4118
- return { staged: true, id };
4123
+ const pendingId = `${surface}-pending-${idSeq += 1}`;
4124
+ pending.set(pendingId, { op, label, targetId });
4125
+ options.onPending?.({ id: pendingId, op, label });
4126
+ return { staged: true, id: targetId, pendingId };
4119
4127
  }
4120
4128
  commit(op, label, targetId);
4121
4129
  return { staged: false, id: targetId };
@@ -4198,18 +4206,26 @@ function registerDocBridge(host, options) {
4198
4206
  type: { type: "string", description: "Node type discriminant." },
4199
4207
  parent: { type: ["string", "null"], description: "Parent id, or null for a root." },
4200
4208
  props: { type: "object", description: "JSON props bag." },
4201
- order: { type: "string", description: "Fractional order key (default: append)." }
4209
+ order: { type: "string", description: "Fractional order key (default: append)." },
4210
+ id: {
4211
+ type: "string",
4212
+ description: "Id for the new node. Supply a meaningful one if you intend to address this node later; omitted means one is minted for you. Must not already exist."
4213
+ }
4202
4214
  },
4203
4215
  ["type"],
4204
4216
  (args) => {
4205
4217
  const tree = adapter.get();
4206
4218
  const parent = typeof args.parent === "string" ? args.parent : null;
4207
- const id = mintId();
4219
+ const requested = typeof args.id === "string" ? args.id : void 0;
4220
+ if (requested !== void 0 && tree.nodes[requested]) {
4221
+ throw new Error(`Node ${requested} already exists \u2014 pick a different id or update it instead`);
4222
+ }
4223
+ const id = requested ?? mintId();
4208
4224
  const order = typeof args.order === "string" ? args.order : fancyDocCommons.appendOrder(tree, parent);
4209
4225
  const props = args.props && typeof args.props === "object" ? args.props : {};
4210
4226
  const node = makeNode({ id, type: String(args.type), parent, order }, props);
4211
4227
  const res = submit({ t: "insert", node }, `add ${args.type} ${id}`, id);
4212
- return { ...res, _text: res.staged ? `staged add ${id}` : `added ${id}` };
4228
+ return { ...res, _text: res.staged ? `staged add ${id} \u2014 confirm ${res.pendingId}` : `added ${id}` };
4213
4229
  },
4214
4230
  true,
4215
4231
  (_args, result) => target(result.id)
@@ -4224,7 +4240,7 @@ function registerDocBridge(host, options) {
4224
4240
  if (!adapter.get().nodes[id]) throw new Error(`No node ${id}`);
4225
4241
  const patch = args.patch && typeof args.patch === "object" ? args.patch : {};
4226
4242
  const res = submit({ t: "set_props", id, patch }, `update ${id}`, id);
4227
- return { ...res, id, _text: res.staged ? `staged update ${id}` : `updated ${id}` };
4243
+ return { ...res, id, _text: res.staged ? `staged update ${id} \u2014 confirm ${res.pendingId}` : `updated ${id}` };
4228
4244
  },
4229
4245
  true,
4230
4246
  (args) => target(String(args.id))
@@ -4240,7 +4256,7 @@ function registerDocBridge(host, options) {
4240
4256
  if (!tree.nodes[id]) throw new Error(`No node ${id}`);
4241
4257
  const count = fancyDocCommons.descendantsOf(tree, id).length + 1;
4242
4258
  const res = submit({ t: "remove", id }, `remove ${id} (${count} node${count === 1 ? "" : "s"})`, id);
4243
- return { ...res, id, removed: count, _text: res.staged ? `staged remove ${id}` : `removed ${id}` };
4259
+ return { ...res, id, removed: count, _text: res.staged ? `staged remove ${id} \u2014 confirm ${res.pendingId}` : `removed ${id}` };
4244
4260
  },
4245
4261
  true,
4246
4262
  (args) => target(String(args.id))
@@ -4257,7 +4273,7 @@ function registerDocBridge(host, options) {
4257
4273
  const parent = args.parent === null ? null : typeof args.parent === "string" ? args.parent : tree.nodes[id].parent;
4258
4274
  const order = typeof args.order === "string" ? args.order : fancyDocCommons.appendOrder(tree, parent);
4259
4275
  const res = submit({ t: "move", id, parent, order }, `move ${id}`, id);
4260
- return { ...res, id, _text: res.staged ? `staged move ${id}` : `moved ${id}` };
4276
+ return { ...res, id, _text: res.staged ? `staged move ${id} \u2014 confirm ${res.pendingId}` : `moved ${id}` };
4261
4277
  },
4262
4278
  true,
4263
4279
  (args) => target(String(args.id))
@@ -4273,7 +4289,7 @@ function registerDocBridge(host, options) {
4273
4289
  if (built && typeof built === "object" && "error" in built) throw new Error(built.error);
4274
4290
  const tid = t.targetId?.(args);
4275
4291
  const res = submit(built, `${t.verb} ${tid ?? ""}`.trim(), tid);
4276
- return { ...res, id: tid, _text: res.staged ? `staged ${t.verb}` : t.verb };
4292
+ return { ...res, id: tid, _text: res.staged ? `staged ${t.verb} \u2014 confirm ${res.pendingId}` : t.verb };
4277
4293
  },
4278
4294
  true,
4279
4295
  (args) => target(t.targetId?.(args))
@@ -4281,8 +4297,8 @@ function registerDocBridge(host, options) {
4281
4297
  }
4282
4298
  reg(
4283
4299
  "confirm",
4284
- "Apply a staged op by its pending id (from a staged mutation).",
4285
- { id: { type: "string" } },
4300
+ "Apply a staged op. Pass the `pendingId` a staged mutation returned \u2014 not the node `id` it also returns.",
4301
+ { id: { type: "string", description: "The `pendingId` from a staged mutation." } },
4286
4302
  ["id"],
4287
4303
  (args) => {
4288
4304
  const id = String(args.id);
@@ -4297,8 +4313,8 @@ function registerDocBridge(host, options) {
4297
4313
  );
4298
4314
  reg(
4299
4315
  "reject",
4300
- "Discard a staged op by its pending id.",
4301
- { id: { type: "string" } },
4316
+ "Discard a staged op. Pass the `pendingId` a staged mutation returned \u2014 not the node `id` it also returns.",
4317
+ { id: { type: "string", description: "The `pendingId` from a staged mutation." } },
4302
4318
  ["id"],
4303
4319
  (args) => {
4304
4320
  const id = String(args.id);
@@ -4390,6 +4406,90 @@ function registerCmsBridge(host, options) {
4390
4406
  ]
4391
4407
  });
4392
4408
  }
4409
+ var SCREEN_TEXT_NODE_TYPE = "#text";
4410
+ function registerScreenDocBridge(host, options) {
4411
+ const { adapter } = options;
4412
+ const surface = options.surface ?? "screen";
4413
+ const setText = {
4414
+ verb: "set_text",
4415
+ description: "Replace the literal text of an element node \u2014 the natural way to change a label, heading or paragraph. Pass the ELEMENT's id, not the text node's.",
4416
+ properties: {
4417
+ id: { type: "string", description: "Id of the element whose text to set." },
4418
+ text: { type: "string" }
4419
+ },
4420
+ required: ["id", "text"],
4421
+ build: (args, tree) => {
4422
+ const id = String(args.id);
4423
+ const node = tree.nodes[id];
4424
+ if (!node) return { error: `No node ${id}` };
4425
+ if (node.type === SCREEN_TEXT_NODE_TYPE) {
4426
+ return { t: "set_props", id, patch: { value: String(args.text) } };
4427
+ }
4428
+ const texts = fancyDocCommons.childrenOf(tree, id).filter((c) => c.type === SCREEN_TEXT_NODE_TYPE);
4429
+ if (texts.length === 1) {
4430
+ return { t: "set_props", id: texts[0].id, patch: { value: String(args.text) } };
4431
+ }
4432
+ if (texts.length === 0) {
4433
+ return {
4434
+ t: "insert",
4435
+ node: {
4436
+ id: `${id}-text`,
4437
+ type: SCREEN_TEXT_NODE_TYPE,
4438
+ parent: id,
4439
+ order: fancyDocCommons.appendOrder(tree, id),
4440
+ props: { value: String(args.text) }
4441
+ }
4442
+ };
4443
+ }
4444
+ return {
4445
+ error: `Node ${id} has ${texts.length} text children (${texts.map((t) => t.id).join(", ")}) \u2014 set_text on the one you mean`
4446
+ };
4447
+ },
4448
+ targetId: (args) => String(args.id)
4449
+ };
4450
+ const bridge = registerDocBridge(host, {
4451
+ adapter,
4452
+ surface,
4453
+ agent: options.agent,
4454
+ stagePolicy: options.stagePolicy,
4455
+ onPending: options.onPending,
4456
+ // Anything the AGENT adds is authored by definition — it chose or was given
4457
+ // the id — so it must not inherit the synthetic flag from its neighbours.
4458
+ makeNode: ({ id, type, parent, order }, props) => ({ id, type, parent, order, props }),
4459
+ describeNode: (n) => ({
4460
+ id: n.id,
4461
+ type: n.type,
4462
+ parent: n.parent,
4463
+ ...n.synthetic ? { synthetic: true } : {},
4464
+ ...n.type === SCREEN_TEXT_NODE_TYPE ? { text: String(n.props?.value ?? "") } : { props: Object.keys(n.props ?? {}) }
4465
+ }),
4466
+ opTools: [setText]
4467
+ });
4468
+ const disposeAddressable = host.registerTool(
4469
+ {
4470
+ name: `${surface}_addressable`,
4471
+ description: "List the node ids that are safe to remember and use later. Ids NOT listed here were minted from a node's position: they resolve today and silently point at a different node once a sibling is inserted above them. Address those in the same turn you read them, and never store one.",
4472
+ inputSchema: { type: "object", properties: {}, required: [], additionalProperties: false }
4473
+ },
4474
+ (async () => {
4475
+ const nodes = Object.values(adapter.get().nodes);
4476
+ const authored = nodes.filter((n) => !n.synthetic).map((n) => ({ id: n.id, type: n.type }));
4477
+ const syntheticCount = nodes.length - authored.length;
4478
+ return textResult(
4479
+ authored.length ? `${authored.length} addressable, ${syntheticCount} positional` : `no addressable ids \u2014 all ${syntheticCount} nodes are positional`,
4480
+ { addressable: authored, syntheticCount }
4481
+ );
4482
+ })
4483
+ );
4484
+ return {
4485
+ id: surface,
4486
+ title: "Screen content",
4487
+ dispose: () => {
4488
+ disposeAddressable();
4489
+ bridge.dispose();
4490
+ }
4491
+ };
4492
+ }
4393
4493
 
4394
4494
  // src/sharing/token.ts
4395
4495
  var TOKEN_BYTES = 24;
@@ -5911,6 +6011,7 @@ exports.MemoryHumanPlusEventStore = MemoryHumanPlusEventStore;
5911
6011
  exports.MicroMcpServer = MicroMcpServer;
5912
6012
  exports.PASSKEY_BRIDGE_TOOLS = PASSKEY_BRIDGE_TOOLS;
5913
6013
  exports.RelayTransport = RelayTransport;
6014
+ exports.SCREEN_TEXT_NODE_TYPE = SCREEN_TEXT_NODE_TYPE;
5914
6015
  exports.ScreensActivityBridge = ScreensActivityBridge;
5915
6016
  exports.ShareControls = ShareControls;
5916
6017
  exports.SimulateUsersButton = SimulateUsersButton;
@@ -5953,6 +6054,7 @@ exports.registerMapBridge = registerMapBridge;
5953
6054
  exports.registerNavigationBridge = registerNavigationBridge;
5954
6055
  exports.registerPasskeyBridge = registerPasskeyBridge;
5955
6056
  exports.registerSceneBridge = registerSceneBridge;
6057
+ exports.registerScreenDocBridge = registerScreenDocBridge;
5956
6058
  exports.registerScreensBridge = registerScreensBridge;
5957
6059
  exports.registerSheetsBridge = registerSheetsBridge;
5958
6060
  exports.registerSlidesBridge = registerSlidesBridge;