pi2dsh 0.10.0 → 0.11.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.
@@ -303,9 +303,22 @@ var PiSessionBridge = class {
303
303
  //#endregion
304
304
  //#region src/subagent-bridge.ts
305
305
  let subagentSerial = 0;
306
+ /** Flatten a Pi message's content to text for transcript seeding. */
307
+ function piMessageText(message) {
308
+ const content = message.content;
309
+ if (typeof content === "string") return content;
310
+ if (!Array.isArray(content)) return "";
311
+ return content.map((block) => {
312
+ const record = block;
313
+ if (record?.type === "text" && typeof record.text === "string") return record.text;
314
+ if (record?.type === "toolCall" && typeof record.name === "string") return `(tool ${record.name})`;
315
+ return "";
316
+ }).filter((text) => text.length > 0).join("\n");
317
+ }
306
318
  var PiBridgedAgentSession = class {
307
319
  agent = {};
308
320
  messages = [];
321
+ #seed = [];
309
322
  #host;
310
323
  #handle;
311
324
  #session;
@@ -313,6 +326,10 @@ var PiBridgedAgentSession = class {
313
326
  #subscribers = /* @__PURE__ */ new Set();
314
327
  #disposers = [];
315
328
  #activeToolNames;
329
+ #state;
330
+ #model;
331
+ #streaming = false;
332
+ #pendingToolCalls = /* @__PURE__ */ new Set();
316
333
  #sessionName = "";
317
334
  #turns = 0;
318
335
  #aborted = false;
@@ -341,6 +358,51 @@ var PiBridgedAgentSession = class {
341
358
  return next();
342
359
  });
343
360
  this.#disposers.push(offEvents, offPre);
361
+ const session = this;
362
+ this.#state = {
363
+ get systemPrompt() {
364
+ return "";
365
+ },
366
+ get model() {
367
+ return session.#model;
368
+ },
369
+ get thinkingLevel() {
370
+ return "off";
371
+ },
372
+ get tools() {
373
+ return [...session.#tools];
374
+ },
375
+ set tools(_next) {},
376
+ get messages() {
377
+ return [...session.messages];
378
+ },
379
+ set messages(next) {
380
+ session.#assignTranscript(next);
381
+ },
382
+ get isStreaming() {
383
+ return session.#streaming;
384
+ },
385
+ get pendingToolCalls() {
386
+ return new Set(session.#pendingToolCalls);
387
+ }
388
+ };
389
+ this.agent.state = this.#state;
390
+ }
391
+ /** Pi's AgentState projection, shared by `session.state` and `session.agent.state`. */
392
+ get state() {
393
+ return this.#state;
394
+ }
395
+ /**
396
+ * Pi's `state.messages = …` assignment. Messages already present in this
397
+ * child's projection stay as they are (they are durable); anything new is
398
+ * queued and delivered with the next prompt so the child model really sees
399
+ * the transcript the package seeded.
400
+ */
401
+ #assignTranscript(next) {
402
+ const identity = (message) => JSON.stringify([message.role, message.content]);
403
+ const known = new Set(this.messages.map(identity));
404
+ this.#seed = next.filter((message) => !known.has(identity(message)));
405
+ for (const message of this.#seed) this.messages.push(message);
344
406
  }
345
407
  #project(event) {
346
408
  const type = event.type;
@@ -349,12 +411,27 @@ var PiBridgedAgentSession = class {
349
411
  handler(piEvent);
350
412
  } catch {}
351
413
  };
352
- if (type === "turn/start") emit({
353
- type: "turn_start",
354
- turnIndex: Number(event.data.turn ?? 1) - 1
355
- });
414
+ if (type === "turn/start") {
415
+ this.#streaming = true;
416
+ emit({
417
+ type: "turn_start",
418
+ turnIndex: Number(event.data.turn ?? 1) - 1
419
+ });
420
+ }
421
+ if (type === "request/header") {
422
+ const config = event.data.config ?? {};
423
+ if (typeof config.model === "string") this.#model = {
424
+ id: config.model,
425
+ provider: String(config.provider ?? "")
426
+ };
427
+ }
428
+ if (type === "tools/result" || type === "tool/result") {
429
+ const data = event.data;
430
+ this.#pendingToolCalls.delete(String(data.callId ?? ""));
431
+ }
356
432
  if (type === "tool/call") {
357
433
  const data = event.data;
434
+ this.#pendingToolCalls.add(String(data.callId ?? ""));
358
435
  let args = {};
359
436
  try {
360
437
  args = JSON.parse(String(data.arguments ?? "{}"));
@@ -401,6 +478,8 @@ var PiBridgedAgentSession = class {
401
478
  }
402
479
  if (type === "turn/end") {
403
480
  this.#turns += 1;
481
+ this.#streaming = false;
482
+ this.#pendingToolCalls.clear();
404
483
  emit({
405
484
  type: "turn_end",
406
485
  turnIndex: Number(event.data.turn ?? 1) - 1,
@@ -417,6 +496,28 @@ var PiBridgedAgentSession = class {
417
496
  return () => this.#subscribers.delete(handler);
418
497
  }
419
498
  async prompt(text) {
499
+ if (this.#seed.length > 0) {
500
+ const seeded = this.#seed;
501
+ this.#seed = [];
502
+ const rendered = seeded.map((message) => {
503
+ const role = String(message.role ?? "user");
504
+ const content = piMessageText(message);
505
+ return content.length === 0 ? void 0 : `[${role}]: ${content}`;
506
+ }).filter((line) => line !== void 0);
507
+ if (rendered.length > 0) {
508
+ const seedBlocks = await this.#host.piContentToDsh([{
509
+ type: "text",
510
+ text: `<prior-conversation>\n${rendered.join("\n\n")}\n</prior-conversation>`
511
+ }]);
512
+ this.#host.deliver(this.#handle.agent, createUserMessage({
513
+ content: seedBlocks,
514
+ source: {
515
+ kind: "plugin",
516
+ plugin: this.#host.messageSource
517
+ }
518
+ }), "inject");
519
+ }
520
+ }
420
521
  const blocks = await this.#host.piContentToDsh([{
421
522
  type: "text",
422
523
  text: String(text)
@@ -496,6 +597,18 @@ var PiBridgedAgentSession = class {
496
597
  await this.#handle.dispose();
497
598
  }
498
599
  };
600
+ /**
601
+ * The name DSH's own child catalog shows for a side thread. Pi packages rarely
602
+ * label a child, so the package that started it is the honest fallback: with
603
+ * several Pi packages installed, their threads stay apart in one list.
604
+ * @param requested - a label the calling package supplied, if any.
605
+ * @param packageName - the Pi package the call came from.
606
+ */
607
+ function childLabel(requested, packageName) {
608
+ if (typeof requested === "string" && requested.trim().length > 0) return requested.trim().slice(0, 80);
609
+ const owner = packageName?.trim();
610
+ return owner === void 0 || owner.length === 0 ? "Pi side conversation" : `${owner} side conversation`;
611
+ }
499
612
  async function createBridgedAgentSession(host, options) {
500
613
  const agents = host.cordis.get("agents");
501
614
  if (agents?.create === void 0) throw new Error("pi2dsh: createAgentSession() needs the DSH agent registry in the host composition");
@@ -536,6 +649,17 @@ async function createBridgedAgentSession(host, options) {
536
649
  throw new Error(`pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
537
650
  }
538
651
  const tools = [...Array.isArray(options.tools) ? options.tools : [], ...Array.isArray(options.customTools) ? options.customTools : []];
652
+ const childSession = handle.agent.session;
653
+ if (typeof childSession?.append === "function") try {
654
+ childSession.append("subagent/descriptor", {
655
+ version: 2,
656
+ mode: "continuable",
657
+ provider: "pi2dsh",
658
+ label: childLabel(options.label, host.packageName)
659
+ });
660
+ } catch (error) {
661
+ host.cordis.logger?.warn?.(`[pi2dsh] child session could not record its subagent identity: ${error instanceof Error ? error.message : String(error)}`);
662
+ }
539
663
  return { session: new PiBridgedAgentSession(host, handle, tools) };
540
664
  }
541
665
  //#endregion
@@ -2908,7 +3032,7 @@ function registerCommand(ctx, state, command) {
2908
3032
  const definitionFor = (dshName) => ({
2909
3033
  name: dshName,
2910
3034
  description: command.description || `Migrated Pi command /${command.name}`,
2911
- ...command.argumentHint !== void 0 ? { input: { hint: command.argumentHint } } : {},
3035
+ input: { hint: command.argumentHint ?? "arguments (optional)" },
2912
3036
  async handler(invocation) {
2913
3037
  const agent = invocation.agent;
2914
3038
  const commandContext = contextFor(ctx, state, agent, invocation.signal, true);
@@ -3368,7 +3492,8 @@ async function applyPiPackage(ctx, options) {
3368
3492
  piContentToDsh: (content) => piToDshContent(ctx, content),
3369
3493
  deliver: (agent, message, mode) => deliverAgentMessage(agent, message, mode),
3370
3494
  messageFromSessionEvent,
3371
- messageSource: state.messageSource
3495
+ messageSource: state.messageSource,
3496
+ packageName: state.packageName
3372
3497
  }, subagentOptions));
3373
3498
  ctx.effect(() => () => __setSubagentSessionFactory(void 0));
3374
3499
  await registerPromptCommands(ctx, state, rootDir, options.manifest);
@@ -3410,4 +3535,4 @@ const runtimeInternals = {
3410
3535
  //#endregion
3411
3536
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
3412
3537
 
3413
- //# sourceMappingURL=runtime-Ce3PTbWU.mjs.map
3538
+ //# sourceMappingURL=runtime-DFD6u4NO.mjs.map