perstack 0.0.120 → 0.0.122

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/bin/cli.js CHANGED
@@ -21327,7 +21327,7 @@ async function expertVersionsHandler(scopeName, options) {
21327
21327
 
21328
21328
  //#endregion
21329
21329
  //#region ../../packages/runtime/package.json
21330
- var version$1 = "0.0.133";
21330
+ var version$1 = "0.0.134";
21331
21331
 
21332
21332
  //#endregion
21333
21333
  //#region ../../packages/runtime/src/helpers/usage.ts
@@ -89359,6 +89359,8 @@ const PROVIDERS_WITHOUT_REASONING_HISTORY = [
89359
89359
  "deepseek",
89360
89360
  "ollama"
89361
89361
  ];
89362
+ /** Providers that don't handle multiple consecutive system messages well */
89363
+ const PROVIDERS_REQUIRING_MERGED_SYSTEM_MESSAGES = ["openai", "azure-openai"];
89362
89364
  /**
89363
89365
  * Filter out reasoning parts from messages for providers that don't support them.
89364
89366
  * This prevents "Non-OpenAI reasoning parts are not supported" warnings from AI SDK.
@@ -89377,6 +89379,43 @@ function filterReasoningPartsForProvider(messages, providerName) {
89377
89379
  };
89378
89380
  });
89379
89381
  }
89382
+ /**
89383
+ * Merge consecutive system messages into a single message for providers that
89384
+ * don't support multiple system/developer messages (e.g., OpenAI reasoning models).
89385
+ * Preserves providerOptions from the last message in each group.
89386
+ */
89387
+ function mergeConsecutiveSystemMessages(messages, providerName) {
89388
+ if (!PROVIDERS_REQUIRING_MERGED_SYSTEM_MESSAGES.includes(providerName)) return messages;
89389
+ const result = [];
89390
+ let systemGroup = [];
89391
+ const flushSystemGroup = () => {
89392
+ if (systemGroup.length === 0) return;
89393
+ if (systemGroup.length === 1) result.push({
89394
+ role: "system",
89395
+ content: systemGroup[0].content,
89396
+ providerOptions: systemGroup[0].providerOptions
89397
+ });
89398
+ else {
89399
+ const lastOptions = systemGroup[systemGroup.length - 1].providerOptions;
89400
+ result.push({
89401
+ role: "system",
89402
+ content: systemGroup.map((m) => m.content).join("\n\n"),
89403
+ providerOptions: lastOptions
89404
+ });
89405
+ }
89406
+ systemGroup = [];
89407
+ };
89408
+ for (const message of messages) if (message.role === "system") systemGroup.push({
89409
+ content: message.content,
89410
+ providerOptions: message.providerOptions
89411
+ });
89412
+ else {
89413
+ flushSystemGroup();
89414
+ result.push(message);
89415
+ }
89416
+ flushSystemGroup();
89417
+ return result;
89418
+ }
89380
89419
  var LLMExecutor = class {
89381
89420
  constructor(adapter, model) {
89382
89421
  this.adapter = adapter;
@@ -89387,7 +89426,7 @@ var LLMExecutor = class {
89387
89426
  const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
89388
89427
  const reasoningOptions = shouldEnableReasoning(params.reasoningBudget) && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
89389
89428
  const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
89390
- const messages = filterReasoningPartsForProvider(params.messages, this.adapter.providerName);
89429
+ const messages = mergeConsecutiveSystemMessages(filterReasoningPartsForProvider(params.messages, this.adapter.providerName), this.adapter.providerName);
89391
89430
  try {
89392
89431
  return {
89393
89432
  success: true,
@@ -89426,7 +89465,7 @@ var LLMExecutor = class {
89426
89465
  const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
89427
89466
  const reasoningOptions = shouldEnableReasoning(params.reasoningBudget) && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
89428
89467
  const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
89429
- const messages = filterReasoningPartsForProvider(params.messages, this.adapter.providerName);
89468
+ const messages = mergeConsecutiveSystemMessages(filterReasoningPartsForProvider(params.messages, this.adapter.providerName), this.adapter.providerName);
89430
89469
  try {
89431
89470
  return {
89432
89471
  success: true,
@@ -89451,7 +89490,7 @@ var LLMExecutor = class {
89451
89490
  const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
89452
89491
  const reasoningOptions = shouldEnableReasoning(params.reasoningBudget) && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
89453
89492
  const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
89454
- const messages = filterReasoningPartsForProvider(params.messages, this.adapter.providerName);
89493
+ const messages = mergeConsecutiveSystemMessages(filterReasoningPartsForProvider(params.messages, this.adapter.providerName), this.adapter.providerName);
89455
89494
  const streamResult = streamText({
89456
89495
  model: this.model,
89457
89496
  messages,
@@ -92621,49 +92660,8 @@ async function callingInteractiveToolsLogic({ setting, checkpoint, step }) {
92621
92660
  });
92622
92661
  }
92623
92662
 
92624
- //#endregion
92625
- //#region ../../node_modules/.bun/ts-dedent@2.2.0/node_modules/ts-dedent/dist/index.js
92626
- var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
92627
- Object.defineProperty(exports, "__esModule", { value: true });
92628
- exports.dedent = void 0;
92629
- function dedent(templ) {
92630
- var values = [];
92631
- for (var _i = 1; _i < arguments.length; _i++) values[_i - 1] = arguments[_i];
92632
- var strings = Array.from(typeof templ === "string" ? [templ] : templ);
92633
- strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, "");
92634
- var indentLengths = strings.reduce(function(arr, str) {
92635
- var matches = str.match(/\n([\t ]+|(?!\s).)/g);
92636
- if (matches) return arr.concat(matches.map(function(match) {
92637
- var _a, _b;
92638
- return (_b = (_a = match.match(/[\t ]/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
92639
- }));
92640
- return arr;
92641
- }, []);
92642
- if (indentLengths.length) {
92643
- var pattern_1 = new RegExp("\n[ ]{" + Math.min.apply(Math, indentLengths) + "}", "g");
92644
- strings = strings.map(function(str) {
92645
- return str.replace(pattern_1, "\n");
92646
- });
92647
- }
92648
- strings[0] = strings[0].replace(/^\r?\n/, "");
92649
- var string = strings[0];
92650
- values.forEach(function(value, i) {
92651
- var endentations = string.match(/(?:^|\n)( *)$/);
92652
- var endentation = endentations ? endentations[1] : "";
92653
- var indentedValue = value;
92654
- if (typeof value === "string" && value.includes("\n")) indentedValue = String(value).split("\n").map(function(str, i) {
92655
- return i === 0 ? str : "" + endentation + str;
92656
- }).join("\n");
92657
- string += indentedValue + strings[i + 1];
92658
- });
92659
- return string;
92660
- }
92661
- exports.dedent = dedent;
92662
- }));
92663
-
92664
92663
  //#endregion
92665
92664
  //#region ../../packages/runtime/src/messages/message.ts
92666
- var import_dist = require_dist();
92667
92665
  function createUserMessage(contents) {
92668
92666
  return {
92669
92667
  type: "userMessage",
@@ -92700,36 +92698,31 @@ function createToolMessage(contents) {
92700
92698
  }
92701
92699
  function messageToCoreMessage(message) {
92702
92700
  switch (message.type) {
92703
- case "instructionMessage": return {
92704
- role: "system",
92705
- content: instructionContentsToCoreContent(message.contents),
92706
- providerOptions: message.cache ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0
92707
- };
92708
- case "userMessage": return {
92701
+ case "instructionMessage": {
92702
+ const { contents, cache } = message;
92703
+ return contents.map((part, index) => ({
92704
+ role: "system",
92705
+ content: part.text,
92706
+ providerOptions: cache && index === contents.length - 1 ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0
92707
+ }));
92708
+ }
92709
+ case "userMessage": return [{
92709
92710
  role: "user",
92710
92711
  content: userContentsToCoreContent(message.contents),
92711
92712
  providerOptions: message.cache ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0
92712
- };
92713
- case "expertMessage": return {
92713
+ }];
92714
+ case "expertMessage": return [{
92714
92715
  role: "assistant",
92715
92716
  content: expertContentsToCoreContent(message.contents),
92716
92717
  providerOptions: message.cache ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0
92717
- };
92718
- case "toolMessage": return {
92718
+ }];
92719
+ case "toolMessage": return [{
92719
92720
  role: "tool",
92720
92721
  content: toolContentsToCoreContent(message.contents),
92721
92722
  providerOptions: message.cache ? { anthropic: { cacheControl: { type: "ephemeral" } } } : void 0
92722
- };
92723
+ }];
92723
92724
  }
92724
92725
  }
92725
- function instructionContentsToCoreContent(contents) {
92726
- return contents.reduce((acc, part) => {
92727
- return import_dist.dedent`
92728
- ${acc}
92729
- ${part.text}
92730
- `.trim();
92731
- }, "");
92732
- }
92733
92726
  function userContentsToCoreContent(contents) {
92734
92727
  return contents.map((part) => {
92735
92728
  switch (part.type) {
@@ -93032,7 +93025,7 @@ async function generatingToolCallLogic({ setting, checkpoint, step, skillManager
93032
93025
  const { messages } = checkpoint;
93033
93026
  let reasoningCompletedViaCallback = false;
93034
93027
  const executionResult = await llmExecutor.streamText({
93035
- messages: messages.map(messageToCoreMessage),
93028
+ messages: messages.flatMap(messageToCoreMessage),
93036
93029
  maxRetries: setting.maxRetries,
93037
93030
  tools: getToolSet(skillManager),
93038
93031
  toolChoice: "auto",
@@ -93252,12 +93245,51 @@ async function generatingToolCallLogic({ setting, checkpoint, step, skillManager
93252
93245
  throw new Error(`Unexpected finish reason: ${finishReason}`);
93253
93246
  }
93254
93247
 
93248
+ //#endregion
93249
+ //#region ../../node_modules/.bun/ts-dedent@2.2.0/node_modules/ts-dedent/dist/index.js
93250
+ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
93251
+ Object.defineProperty(exports, "__esModule", { value: true });
93252
+ exports.dedent = void 0;
93253
+ function dedent(templ) {
93254
+ var values = [];
93255
+ for (var _i = 1; _i < arguments.length; _i++) values[_i - 1] = arguments[_i];
93256
+ var strings = Array.from(typeof templ === "string" ? [templ] : templ);
93257
+ strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, "");
93258
+ var indentLengths = strings.reduce(function(arr, str) {
93259
+ var matches = str.match(/\n([\t ]+|(?!\s).)/g);
93260
+ if (matches) return arr.concat(matches.map(function(match) {
93261
+ var _a, _b;
93262
+ return (_b = (_a = match.match(/[\t ]/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
93263
+ }));
93264
+ return arr;
93265
+ }, []);
93266
+ if (indentLengths.length) {
93267
+ var pattern_1 = new RegExp("\n[ ]{" + Math.min.apply(Math, indentLengths) + "}", "g");
93268
+ strings = strings.map(function(str) {
93269
+ return str.replace(pattern_1, "\n");
93270
+ });
93271
+ }
93272
+ strings[0] = strings[0].replace(/^\r?\n/, "");
93273
+ var string = strings[0];
93274
+ values.forEach(function(value, i) {
93275
+ var endentations = string.match(/(?:^|\n)( *)$/);
93276
+ var endentation = endentations ? endentations[1] : "";
93277
+ var indentedValue = value;
93278
+ if (typeof value === "string" && value.includes("\n")) indentedValue = String(value).split("\n").map(function(str, i) {
93279
+ return i === 0 ? str : "" + endentation + str;
93280
+ }).join("\n");
93281
+ string += indentedValue + strings[i + 1];
93282
+ });
93283
+ return string;
93284
+ }
93285
+ exports.dedent = dedent;
93286
+ }));
93287
+
93255
93288
  //#endregion
93256
93289
  //#region ../../packages/runtime/src/messages/instruction-message.ts
93290
+ var import_dist = require_dist();
93257
93291
  function getDelegateMetaInstruction(startedAt) {
93258
93292
  return import_dist.dedent`
93259
- Call tools iteratively to complete the user's task.
93260
-
93261
93293
  Before starting work, investigate the workspace and understand the current state. Then use the todo tool to create a plan of action. Work through the todos step by step, marking each completed as you go.
93262
93294
 
93263
93295
  When the task is complete, call attemptCompletion with a result parameter containing your final response.
@@ -93270,14 +93302,36 @@ function getDelegateMetaInstruction(startedAt) {
93270
93302
  }
93271
93303
  function getCoordinatorMetaInstruction(startedAt) {
93272
93304
  return import_dist.dedent`
93273
- You are a Coordinator. Your role is to plan, split tasks, and delegate. Never execute concrete tasks yourself.
93305
+ Your role:
93306
+ - Act as the coordinator for the given task: define the task, set goals, and delegate.
93307
+ - Decompose tasks and delegate subtasks to delegate experts.
93308
+ - Review and aggregate deliverables from delegates.
93309
+ - Determine whether the task meets the completion criteria.
93310
+
93311
+ Rules:
93312
+ - Never produce deliverables yourself. You are a thin coordinator — route all production work to delegates.
93313
+ - Always verify delegate outputs yourself. You are the gatekeeper: run code to confirm it works, read documents to confirm content quality, call APIs to confirm data was persisted, and cross-check research claims with independent sources. Never trust delegate results at face value.
93314
+ - Delegates receive only the query string, not your conversation history. Use workspace files to exchange data between delegates (e.g., have delegate A write results to a file, then instruct delegate B to read that file).
93315
+
93316
+ Workflow:
93317
+ 1. Investigate the workspace and understand the current state.
93318
+ 2. Decompose the task into fine-grained subtasks and create todos.
93319
+ 3. Delegate subtasks to experts in parallel. Maximize parallelism — delegate to multiple types of experts and run multiple experts of the same type concurrently.
93320
+ 4. Review delegate outputs: verify deliverables exist, check consistency across outputs, and validate against the original request.
93321
+ 5. If a delegate fails, assess the error and decide: retry the same delegate, delegate to a different expert, or report the failure.
93322
+ 6. Aggregate results and ensure the workspace contains only clean deliverables.
93274
93323
 
93275
93324
  Delegation best practices:
93276
- - Parallelism: When there are N independent tasks, delegate them simultaneously in a single response.
93277
- - Task splitting: Distribute N tasks across M Experts. Do not send all tasks to a single Expert.
93278
- - Specificity: Include context, constraints, and expected output format in every delegation. No vague delegations.
93279
- - Planning as delegation: If planning is needed, delegate to a planner Expert. If none exists, create one with createExpert, then addDelegate, then delegate.
93280
- - Creating Experts: If no suitable delegate exists, use createExpert to create a specialized Expert, then addDelegate, then delegate to it.
93325
+ - Delegate experts are purpose-specialized, so they handle individual tasks better than you.
93326
+ - To avoid context explosion, do not assign one large subtask to a single delegate. Instead, decompose it into fine-grained subtasks and assign them to multiple delegates.
93327
+ - Higher parallelism leads to faster task completion and improved accuracy.
93328
+ - Specificity: Include context, file paths, constraints, and expected output format in every delegation. No vague delegations.
93329
+ - If no suitable delegate exists for a given purpose, use createExpert to create a purpose-specialized expert, then addDelegate to make it available as a delegate.
93330
+
93331
+ Task completion criteria:
93332
+ - The user's request has been fully fulfilled.
93333
+ - The task deliverables are confirmed to be high quality: high-quality deliverables are defined as those that are verifiable by the user, available, and professional.
93334
+ - Cleanup is complete and only pure deliverables remain in the workspace: specifically, no duplicate files, notes, or loosely related files created by delegates should remain.
93281
93335
 
93282
93336
  When the task is complete, call attemptCompletion with a result parameter containing your final response.
93283
93337
  When you cannot help, call attemptCompletion without a result.
@@ -93288,26 +93342,29 @@ function getCoordinatorMetaInstruction(startedAt) {
93288
93342
  `;
93289
93343
  }
93290
93344
  function createInstructionMessage(expert, startedAt) {
93291
- const instruction = import_dist.dedent`
93345
+ const preamble = import_dist.dedent`
93292
93346
  You are Perstack, an AI expert that tackles tasks requested by users by utilizing all available tools.
93293
93347
 
93294
93348
  ${isCoordinatorExpert(expert.name) ? getCoordinatorMetaInstruction(startedAt) : getDelegateMetaInstruction(startedAt)}
93295
-
93296
- ---
93297
-
93298
- ${expert.instruction}
93299
-
93300
- ---
93301
-
93302
- ${getSkillRules(expert)}
93303
93349
  `;
93350
+ const contents = [{
93351
+ id: createId(),
93352
+ type: "textPart",
93353
+ text: preamble
93354
+ }, {
93355
+ id: createId(),
93356
+ type: "textPart",
93357
+ text: expert.instruction
93358
+ }];
93359
+ const skillRules = getSkillRules(expert);
93360
+ if (skillRules) contents.push({
93361
+ id: createId(),
93362
+ type: "textPart",
93363
+ text: skillRules
93364
+ });
93304
93365
  return {
93305
93366
  type: "instructionMessage",
93306
- contents: [{
93307
- id: createId(),
93308
- type: "textPart",
93309
- text: instruction
93310
- }],
93367
+ contents,
93311
93368
  id: createId()
93312
93369
  };
93313
93370
  }
@@ -122888,7 +122945,7 @@ async function startHandler(expertKey, query, options, handlerOptions) {
122888
122945
  //#endregion
122889
122946
  //#region package.json
122890
122947
  var name = "perstack";
122891
- var version = "0.0.120";
122948
+ var version = "0.0.122";
122892
122949
  var description = "PerStack CLI";
122893
122950
 
122894
122951
  //#endregion