pi2dsh 0.10.0 → 0.12.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.
@@ -1,5 +1,5 @@
1
1
 
2
- import { F as AssistantMessageEventStream, a as builtinProviders, i as __setPiAiLlmBridge } from "./pi-ai-Dyg4zyLZ.mjs";
2
+ import { F as AssistantMessageEventStream, a as builtinProviders, h as getSupportedThinkingLevels, i as __setPiAiLlmBridge } from "./pi-ai-Dyg4zyLZ.mjs";
3
3
  import { P as generateBranchSummary, Tn as PiCapabilityError, b as Theme, d as ExtensionRunner, w as __setSubagentSessionFactory, wn as CapabilityLedger } from "./pi-coding-agent-Ctw-BhoY.mjs";
4
4
  import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
5
5
  import { a as resolvePiProviderAuth, n as loginPiProvider, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-CfyImWx4.mjs";
@@ -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
@@ -1155,6 +1279,33 @@ const PI_CARRIED_FIELDS = [
1155
1279
  "compat",
1156
1280
  "headers"
1157
1281
  ];
1282
+ /**
1283
+ * Pi's reasoning capability, in DSH's shape.
1284
+ *
1285
+ * The two sides say the same thing differently: Pi carries a `reasoning`
1286
+ * boolean plus a `thinkingLevelMap` whose `null` entries mark unsupported
1287
+ * levels, while DSH asks an adapter for the selectable efforts directly.
1288
+ * Translating is this layer's job — carrying Pi's boolean through under the
1289
+ * name `reasoning` would collide with DSH's `{efforts}` object, and carrying
1290
+ * nothing (what this bridge did before) leaves every package-registered route
1291
+ * with no selectable effort at all, so any reasoning request is rejected.
1292
+ *
1293
+ * The mapping is DSH's own: its native pi-ai adapter derives efforts from
1294
+ * `getSupportedThinkingLevels` and names them the same way, so a route a Pi
1295
+ * package registers offers exactly the efforts it would through the host's
1296
+ * own adapter. It belongs to the exact-route resolve, not the catalog listing
1297
+ * — `reasoning` is a resolved-model field in DSH's contract.
1298
+ * @param model - the Pi model descriptor as its package declared it.
1299
+ */
1300
+ function reasoningProjection(model) {
1301
+ if (model.reasoning !== true) return {};
1302
+ const levels = getSupportedThinkingLevels(model);
1303
+ if (levels.length === 0) return {};
1304
+ return { reasoning: { efforts: levels.map((level) => ({
1305
+ id: level,
1306
+ name: `${level.charAt(0).toUpperCase()}${level.slice(1)}`
1307
+ })) } };
1308
+ }
1158
1309
  function piCarriedFields(model) {
1159
1310
  const carried = {};
1160
1311
  for (const field of PI_CARRIED_FIELDS) if (model[field] !== void 0) carried[field] = model[field];
@@ -1182,6 +1333,7 @@ function piProviderDshAdapter(providerId, provider, host) {
1182
1333
  const known = providerModels(provider).find((model) => model.id === modelId);
1183
1334
  return {
1184
1335
  ...known === void 0 ? {} : piCarriedFields(known),
1336
+ ...known === void 0 ? {} : reasoningProjection(known),
1185
1337
  provider: id,
1186
1338
  id: modelId,
1187
1339
  name: String(known?.name ?? modelId),
@@ -1203,7 +1355,8 @@ function piProviderDshAdapter(providerId, provider, host) {
1203
1355
  ...auth?.headers === void 0 ? {} : { headers: auth.headers },
1204
1356
  ...options.signal instanceof AbortSignal ? { signal: options.signal } : {},
1205
1357
  ...typeof options.maxTokens === "number" ? { maxTokens: options.maxTokens } : {},
1206
- ...typeof options.temperature === "number" ? { temperature: options.temperature } : {}
1358
+ ...typeof options.temperature === "number" ? { temperature: options.temperature } : {},
1359
+ ...typeof options.reasoningEffort === "string" ? { reasoningEffort: options.reasoningEffort } : {}
1207
1360
  };
1208
1361
  yield* piEventsToDshChunks(provider.stream(model, piContext, piOptions));
1209
1362
  }
@@ -2908,7 +3061,7 @@ function registerCommand(ctx, state, command) {
2908
3061
  const definitionFor = (dshName) => ({
2909
3062
  name: dshName,
2910
3063
  description: command.description || `Migrated Pi command /${command.name}`,
2911
- ...command.argumentHint !== void 0 ? { input: { hint: command.argumentHint } } : {},
3064
+ input: { hint: command.argumentHint ?? "arguments (optional)" },
2912
3065
  async handler(invocation) {
2913
3066
  const agent = invocation.agent;
2914
3067
  const commandContext = contextFor(ctx, state, agent, invocation.signal, true);
@@ -3368,7 +3521,8 @@ async function applyPiPackage(ctx, options) {
3368
3521
  piContentToDsh: (content) => piToDshContent(ctx, content),
3369
3522
  deliver: (agent, message, mode) => deliverAgentMessage(agent, message, mode),
3370
3523
  messageFromSessionEvent,
3371
- messageSource: state.messageSource
3524
+ messageSource: state.messageSource,
3525
+ packageName: state.packageName
3372
3526
  }, subagentOptions));
3373
3527
  ctx.effect(() => () => __setSubagentSessionFactory(void 0));
3374
3528
  await registerPromptCommands(ctx, state, rootDir, options.manifest);
@@ -3410,4 +3564,4 @@ const runtimeInternals = {
3410
3564
  //#endregion
3411
3565
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
3412
3566
 
3413
- //# sourceMappingURL=runtime-Ce3PTbWU.mjs.map
3567
+ //# sourceMappingURL=runtime-Bh5k4Kjt.mjs.map