@riotprompt/riotprompt 0.0.13 → 0.0.14

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.
@@ -5,6 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const zod = require('zod');
6
6
  const fs = require('fs/promises');
7
7
  const path = require('path');
8
+ const zodToJsonSchema = require('zod-to-json-schema');
8
9
  const crypto = require('crypto');
9
10
  const tiktoken = require('tiktoken');
10
11
  const OpenAI = require('openai');
@@ -236,12 +237,21 @@ const create$7 = (text, options = {})=>{
236
237
  return create$c(text, weightedOptions);
237
238
  };
238
239
 
239
- const create$6 = ({ persona, instructions, contents, contexts })=>{
240
+ const create$6 = ({ persona, instructions, contents, contexts, constraints, tone, examples, reasoning, responseFormat, recap, safeguards, schema, validator })=>{
240
241
  return {
241
242
  persona,
242
243
  instructions,
243
244
  contents,
244
- contexts
245
+ contexts,
246
+ constraints,
247
+ tone,
248
+ examples,
249
+ reasoning,
250
+ responseFormat,
251
+ recap,
252
+ safeguards,
253
+ schema,
254
+ validator
245
255
  };
246
256
  };
247
257
 
@@ -519,6 +529,8 @@ const createRequest = (model)=>{
519
529
  return {
520
530
  model,
521
531
  messages,
532
+ responseFormat: undefined,
533
+ validator: undefined,
522
534
  addMessage: (message)=>{
523
535
  messages.push(message);
524
536
  }
@@ -671,24 +683,52 @@ const create$5 = (formatterOptions)=>{
671
683
  const formatPrompt = (model, prompt)=>{
672
684
  logger.silly('Formatting prompt');
673
685
  const chatRequest = createRequest(model);
674
- if (prompt.persona) {
675
- [
676
- prompt.persona
677
- ].forEach((persona)=>{
678
- chatRequest.addMessage(formatPersona(model, persona));
686
+ // --- System/Role Message Construction ---
687
+ // Collect sections that belong in the system/developer prompt (Persona, Tone, Constraints, etc.)
688
+ const systemSections = [];
689
+ if (prompt.persona) systemSections.push(prompt.persona);
690
+ if (prompt.tone) systemSections.push(prompt.tone);
691
+ if (prompt.constraints) systemSections.push(prompt.constraints);
692
+ if (prompt.safeguards) systemSections.push(prompt.safeguards);
693
+ if (prompt.responseFormat) systemSections.push(prompt.responseFormat);
694
+ if (systemSections.length > 0) {
695
+ // Combine all system sections into one system message content
696
+ const systemContent = systemSections.map((section)=>formatSection(section)).join('\n\n');
697
+ chatRequest.addMessage({
698
+ role: getPersonaRole(model),
699
+ content: systemContent
679
700
  });
680
701
  }
681
- let formattedAreas = formatSection(prompt.instructions) + '\n\n';
682
- if (prompt.contents) {
683
- formattedAreas += formatSection(prompt.contents) + '\n\n';
702
+ // --- User/Task Message Construction ---
703
+ // Logical flow: Context -> Examples -> Instructions -> Content -> Reasoning -> Recap
704
+ // This structure guides the model through the context and examples before presenting the core task
705
+ const userSections = [
706
+ prompt.contexts,
707
+ prompt.examples,
708
+ prompt.instructions,
709
+ prompt.contents,
710
+ prompt.reasoning,
711
+ prompt.recap
712
+ ];
713
+ let formattedUserContent = "";
714
+ for (const section of userSections){
715
+ if (section) {
716
+ formattedUserContent += formatSection(section) + '\n\n';
717
+ }
684
718
  }
685
- if (prompt.contexts) {
686
- formattedAreas += formatSection(prompt.contexts) + '\n\n';
719
+ // Ensure we always have a user message, or if we have content to send
720
+ if (formattedUserContent.trim().length > 0 || systemSections.length === 0) {
721
+ chatRequest.addMessage({
722
+ role: "user",
723
+ content: formattedUserContent.trim() || " "
724
+ });
725
+ }
726
+ if (prompt.schema) {
727
+ chatRequest.responseFormat = prompt.schema;
728
+ }
729
+ if (prompt.validator) {
730
+ chatRequest.validator = prompt.validator;
687
731
  }
688
- chatRequest.addMessage({
689
- role: "user",
690
- content: formattedAreas
691
- });
692
732
  return chatRequest;
693
733
  };
694
734
  return {
@@ -4891,6 +4931,15 @@ const RecipeConfigSchema = zod.z.object({
4891
4931
  instructions: zod.z.array(ContentItemSchema).optional().default([]),
4892
4932
  content: zod.z.array(ContentItemSchema).optional().default([]),
4893
4933
  context: zod.z.array(ContentItemSchema).optional().default([]),
4934
+ // Advanced prompting sections
4935
+ constraints: zod.z.array(ContentItemSchema).optional().default([]),
4936
+ tone: zod.z.array(ContentItemSchema).optional().default([]),
4937
+ examples: zod.z.array(ContentItemSchema).optional().default([]),
4938
+ reasoning: zod.z.array(ContentItemSchema).optional().default([]),
4939
+ responseFormat: zod.z.array(ContentItemSchema).optional().default([]),
4940
+ recap: zod.z.array(ContentItemSchema).optional().default([]),
4941
+ safeguards: zod.z.array(ContentItemSchema).optional().default([]),
4942
+ schema: zod.z.any().optional(),
4894
4943
  // Templates and inheritance
4895
4944
  extends: zod.z.string().optional(),
4896
4945
  template: zod.z.string().optional(),
@@ -5056,6 +5105,13 @@ const cook = async (config)=>{
5056
5105
  instructions: [],
5057
5106
  content: [],
5058
5107
  context: [],
5108
+ constraints: [],
5109
+ tone: [],
5110
+ examples: [],
5111
+ reasoning: [],
5112
+ responseFormat: [],
5113
+ recap: [],
5114
+ safeguards: [],
5059
5115
  ...config
5060
5116
  });
5061
5117
  // Handle template inheritance
@@ -5079,7 +5135,36 @@ const cook = async (config)=>{
5079
5135
  context: [
5080
5136
  ...template.context || [],
5081
5137
  ...validatedConfig.context || []
5082
- ]
5138
+ ],
5139
+ constraints: [
5140
+ ...template.constraints || [],
5141
+ ...validatedConfig.constraints || []
5142
+ ],
5143
+ tone: [
5144
+ ...template.tone || [],
5145
+ ...validatedConfig.tone || []
5146
+ ],
5147
+ examples: [
5148
+ ...template.examples || [],
5149
+ ...validatedConfig.examples || []
5150
+ ],
5151
+ reasoning: [
5152
+ ...template.reasoning || [],
5153
+ ...validatedConfig.reasoning || []
5154
+ ],
5155
+ responseFormat: [
5156
+ ...template.responseFormat || [],
5157
+ ...validatedConfig.responseFormat || []
5158
+ ],
5159
+ recap: [
5160
+ ...template.recap || [],
5161
+ ...validatedConfig.recap || []
5162
+ ],
5163
+ safeguards: [
5164
+ ...template.safeguards || [],
5165
+ ...validatedConfig.safeguards || []
5166
+ ],
5167
+ schema: validatedConfig.schema || template.schema
5083
5168
  };
5084
5169
  }
5085
5170
  }
@@ -5111,6 +5196,39 @@ const cook = async (config)=>{
5111
5196
  const contextSection = create$8({
5112
5197
  title: "Context"
5113
5198
  });
5199
+ // Advanced sections
5200
+ const constraintSection = create$8({
5201
+ title: "Constraints"
5202
+ });
5203
+ const toneSection = create$8({
5204
+ title: "Tone"
5205
+ });
5206
+ const exampleSection = create$8({
5207
+ title: "Examples"
5208
+ });
5209
+ const reasoningSection = create$8({
5210
+ title: "Reasoning"
5211
+ });
5212
+ const responseFormatSection = create$8({
5213
+ title: "Response Format"
5214
+ });
5215
+ const recapSection = create$8({
5216
+ title: "Recap"
5217
+ });
5218
+ const safeguardSection = create$8({
5219
+ title: "Safeguards"
5220
+ });
5221
+ // Helper for processing list items
5222
+ const processList = async (items, section, type)=>{
5223
+ for (const item of items){
5224
+ await processContentItem(item, section, type, {
5225
+ basePath: finalConfig.basePath,
5226
+ parser: parser$1,
5227
+ override: override$1,
5228
+ loader: loader$1,
5229
+ parameters: finalConfig.parameters});
5230
+ }
5231
+ };
5114
5232
  // Process persona
5115
5233
  if (finalConfig.persona) {
5116
5234
  await processContentItem(finalConfig.persona, personaSection, 'persona', {
@@ -5120,15 +5238,18 @@ const cook = async (config)=>{
5120
5238
  loader: loader$1,
5121
5239
  parameters: finalConfig.parameters});
5122
5240
  }
5123
- // Process instructions
5124
- for (const item of finalConfig.instructions || []){
5125
- await processContentItem(item, instructionSection, 'instruction', {
5126
- basePath: finalConfig.basePath,
5127
- parser: parser$1,
5128
- override: override$1,
5129
- loader: loader$1,
5130
- parameters: finalConfig.parameters});
5131
- }
5241
+ // Process standard sections
5242
+ await processList(finalConfig.instructions || [], instructionSection, 'instruction');
5243
+ await processList(finalConfig.content || [], contentSection, 'content');
5244
+ await processList(finalConfig.context || [], contextSection, 'context');
5245
+ // Process advanced sections
5246
+ await processList(finalConfig.constraints || [], constraintSection, 'instruction');
5247
+ await processList(finalConfig.tone || [], toneSection, 'instruction');
5248
+ await processList(finalConfig.examples || [], exampleSection, 'content');
5249
+ await processList(finalConfig.reasoning || [], reasoningSection, 'instruction');
5250
+ await processList(finalConfig.responseFormat || [], responseFormatSection, 'instruction');
5251
+ await processList(finalConfig.recap || [], recapSection, 'instruction');
5252
+ await processList(finalConfig.safeguards || [], safeguardSection, 'instruction');
5132
5253
  // Generate tool guidance if tools are provided
5133
5254
  if (finalConfig.tools) {
5134
5255
  const tools = Array.isArray(finalConfig.tools) ? finalConfig.tools : finalConfig.tools.getAll();
@@ -5142,30 +5263,59 @@ const cook = async (config)=>{
5142
5263
  instructionSection.add(toolSection);
5143
5264
  }
5144
5265
  }
5145
- // Process content
5146
- for (const item of finalConfig.content || []){
5147
- await processContentItem(item, contentSection, 'content', {
5148
- basePath: finalConfig.basePath,
5149
- parser: parser$1,
5150
- override: override$1,
5151
- loader: loader$1,
5152
- parameters: finalConfig.parameters});
5153
- }
5154
- // Process context
5155
- for (const item of finalConfig.context || []){
5156
- await processContentItem(item, contextSection, 'context', {
5157
- basePath: finalConfig.basePath,
5158
- parser: parser$1,
5159
- override: override$1,
5160
- loader: loader$1,
5161
- parameters: finalConfig.parameters});
5266
+ // Process schema
5267
+ let schema = finalConfig.schema;
5268
+ let validator = undefined;
5269
+ if (schema instanceof zod.z.ZodType) {
5270
+ var _jsonSchema_definitions;
5271
+ // It's a Zod schema!
5272
+ validator = schema;
5273
+ const jsonSchema = zodToJsonSchema(schema, "response");
5274
+ // Wrap in OpenAI Structured Output format
5275
+ // zod-to-json-schema returns { "$schema": "...", "definitions": { "response": { ... } }, "$ref": "#/definitions/response" }
5276
+ // We need to extract the schema part.
5277
+ // Simpler usage for OpenAI: just get the schema object.
5278
+ // Actually, zod-to-json-schema produces a full JSON schema object.
5279
+ // OpenAI expects: { type: "json_schema", json_schema: { name: "...", schema: ... } }
5280
+ // Let's create a clean schema object
5281
+ // NOTE: OpenAI requires strict: true and additionalProperties: false
5282
+ // zod-to-json-schema generally produces compatible schemas but strictness might need tweaking if required by OpenAI.
5283
+ // For now, let's assume "response" as the name.
5284
+ // We'll define a simpler conversion if possible, or trust the user to configure Zod strictly if they want strict mode.
5285
+ // Extract the definition if it exists
5286
+ const actualSchema = ((_jsonSchema_definitions = jsonSchema.definitions) === null || _jsonSchema_definitions === void 0 ? void 0 : _jsonSchema_definitions.response) || jsonSchema;
5287
+ schema = {
5288
+ type: "json_schema",
5289
+ json_schema: {
5290
+ name: "response",
5291
+ schema: actualSchema,
5292
+ strict: true // Try to enable strict mode for OpenAI
5293
+ }
5294
+ };
5295
+ } else if (typeof schema === 'string') {
5296
+ const schemaPath = path.resolve(finalConfig.basePath, schema);
5297
+ try {
5298
+ const schemaContent = await fs.readFile(schemaPath, 'utf-8');
5299
+ schema = JSON.parse(schemaContent);
5300
+ } catch (e) {
5301
+ throw new Error(`Failed to load schema from ${schemaPath}: ${e.message}`);
5302
+ }
5162
5303
  }
5163
5304
  // Build and return prompt
5164
5305
  return create$6({
5165
- persona: personaSection,
5306
+ persona: personaSection.items.length > 0 ? personaSection : undefined,
5166
5307
  instructions: instructionSection,
5167
- contents: contentSection,
5168
- contexts: contextSection
5308
+ contents: contentSection.items.length > 0 ? contentSection : undefined,
5309
+ contexts: contextSection.items.length > 0 ? contextSection : undefined,
5310
+ constraints: constraintSection.items.length > 0 ? constraintSection : undefined,
5311
+ tone: toneSection.items.length > 0 ? toneSection : undefined,
5312
+ examples: exampleSection.items.length > 0 ? exampleSection : undefined,
5313
+ reasoning: reasoningSection.items.length > 0 ? reasoningSection : undefined,
5314
+ responseFormat: responseFormatSection.items.length > 0 ? responseFormatSection : undefined,
5315
+ recap: recapSection.items.length > 0 ? recapSection : undefined,
5316
+ safeguards: safeguardSection.items.length > 0 ? safeguardSection : undefined,
5317
+ schema,
5318
+ validator
5169
5319
  });
5170
5320
  };
5171
5321
  const processContentItem = async (item, section, type, ctx)=>{
@@ -5243,6 +5393,59 @@ const recipe = (basePath)=>{
5243
5393
  ];
5244
5394
  return builder;
5245
5395
  },
5396
+ constraints: (...constraints)=>{
5397
+ config.constraints = [
5398
+ ...config.constraints || [],
5399
+ ...constraints
5400
+ ];
5401
+ return builder;
5402
+ },
5403
+ tone: (...tone)=>{
5404
+ config.tone = [
5405
+ ...config.tone || [],
5406
+ ...tone
5407
+ ];
5408
+ return builder;
5409
+ },
5410
+ examples: (...examples)=>{
5411
+ config.examples = [
5412
+ ...config.examples || [],
5413
+ ...examples
5414
+ ];
5415
+ return builder;
5416
+ },
5417
+ reasoning: (...reasoning)=>{
5418
+ config.reasoning = [
5419
+ ...config.reasoning || [],
5420
+ ...reasoning
5421
+ ];
5422
+ return builder;
5423
+ },
5424
+ responseFormat: (...responseFormat)=>{
5425
+ config.responseFormat = [
5426
+ ...config.responseFormat || [],
5427
+ ...responseFormat
5428
+ ];
5429
+ return builder;
5430
+ },
5431
+ recap: (...recap)=>{
5432
+ config.recap = [
5433
+ ...config.recap || [],
5434
+ ...recap
5435
+ ];
5436
+ return builder;
5437
+ },
5438
+ safeguards: (...safeguards)=>{
5439
+ config.safeguards = [
5440
+ ...config.safeguards || [],
5441
+ ...safeguards
5442
+ ];
5443
+ return builder;
5444
+ },
5445
+ schema: (schema)=>{
5446
+ config.schema = schema;
5447
+ return builder;
5448
+ },
5246
5449
  parameters: (parameters)=>{
5247
5450
  config.parameters = {
5248
5451
  ...config.parameters,
@@ -5666,7 +5869,8 @@ class OpenAIProvider {
5666
5869
  model: model,
5667
5870
  messages: messages,
5668
5871
  temperature: options.temperature,
5669
- max_tokens: options.maxTokens
5872
+ max_tokens: options.maxTokens,
5873
+ response_format: request.responseFormat
5670
5874
  });
5671
5875
  const choice = response.choices[0];
5672
5876
  return {
@@ -5682,6 +5886,7 @@ class OpenAIProvider {
5682
5886
 
5683
5887
  class AnthropicProvider {
5684
5888
  async execute(request, options = {}) {
5889
+ var _request_responseFormat, _request_responseFormat1;
5685
5890
  const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY;
5686
5891
  if (!apiKey) throw new Error('Anthropic API key is required');
5687
5892
  const client = new Anthropic({
@@ -5706,11 +5911,34 @@ class AnthropicProvider {
5706
5911
  system: systemPrompt.trim() || undefined,
5707
5912
  messages: messages,
5708
5913
  max_tokens: options.maxTokens || 4096,
5709
- temperature: options.temperature
5914
+ temperature: options.temperature,
5915
+ ...((_request_responseFormat = request.responseFormat) === null || _request_responseFormat === void 0 ? void 0 : _request_responseFormat.type) === 'json_schema' ? {
5916
+ tools: [
5917
+ {
5918
+ name: request.responseFormat.json_schema.name,
5919
+ description: request.responseFormat.json_schema.description || "Output data in this structured format",
5920
+ input_schema: request.responseFormat.json_schema.schema
5921
+ }
5922
+ ],
5923
+ tool_choice: {
5924
+ type: 'tool',
5925
+ name: request.responseFormat.json_schema.name
5926
+ }
5927
+ } : {}
5710
5928
  });
5711
5929
  // Handle ContentBlock
5712
- const contentBlock = response.content[0];
5713
- const text = contentBlock.type === 'text' ? contentBlock.text : '';
5930
+ // Check for tool_use first if we requested structured output
5931
+ let text = '';
5932
+ if (((_request_responseFormat1 = request.responseFormat) === null || _request_responseFormat1 === void 0 ? void 0 : _request_responseFormat1.type) === 'json_schema') {
5933
+ const toolUseBlock = response.content.find((block)=>block.type === 'tool_use');
5934
+ if (toolUseBlock && toolUseBlock.type === 'tool_use') {
5935
+ // Return the structured data as a JSON string to match OpenAI behavior
5936
+ text = JSON.stringify(toolUseBlock.input, null, 2);
5937
+ }
5938
+ } else {
5939
+ const contentBlock = response.content[0];
5940
+ text = contentBlock.type === 'text' ? contentBlock.text : '';
5941
+ }
5714
5942
  return {
5715
5943
  content: text,
5716
5944
  model: response.model,
@@ -5724,10 +5952,53 @@ class AnthropicProvider {
5724
5952
 
5725
5953
  class GeminiProvider {
5726
5954
  async execute(request, options = {}) {
5955
+ var _request_responseFormat;
5727
5956
  const apiKey = options.apiKey || process.env.GEMINI_API_KEY; // or GOOGLE_API_KEY
5728
5957
  if (!apiKey) throw new Error('Gemini API key is required');
5729
5958
  const genAI = new generativeAi.GoogleGenerativeAI(apiKey);
5730
5959
  const modelName = options.model || request.model || 'gemini-1.5-pro';
5960
+ // Handle generation config for structured output
5961
+ const generationConfig = {};
5962
+ if (((_request_responseFormat = request.responseFormat) === null || _request_responseFormat === void 0 ? void 0 : _request_responseFormat.type) === 'json_schema') {
5963
+ generationConfig.responseMimeType = "application/json";
5964
+ // Map OpenAI JSON schema to Gemini Schema
5965
+ // OpenAI: { name: "...", schema: { type: "object", properties: ... } }
5966
+ // Gemini expects the schema object directly
5967
+ const openAISchema = request.responseFormat.json_schema.schema;
5968
+ // We need to recursively map the types because Gemini uses uppercase enums
5969
+ // SchemaType.OBJECT, SchemaType.STRING, etc.
5970
+ // But the SDK also accepts string types "OBJECT", "STRING" etc.
5971
+ // Let's implement a simple converter or pass it if compatible.
5972
+ // Zod-to-json-schema produces lowercase types ("object", "string").
5973
+ // Google's SDK might need them to be uppercase or mapped.
5974
+ // Helper to clean up schema for Gemini
5975
+ // Removes $schema, strict, and additionalProperties if not supported or formatted differently
5976
+ // And maps 'type' to uppercase.
5977
+ const mapSchema = (s)=>{
5978
+ if (!s) return undefined;
5979
+ const newSchema = {
5980
+ ...s
5981
+ };
5982
+ if (newSchema.type) {
5983
+ newSchema.type = typeof newSchema.type === 'string' ? newSchema.type.toUpperCase() : newSchema.type;
5984
+ }
5985
+ if (newSchema.properties) {
5986
+ const newProps = {};
5987
+ for (const [key, val] of Object.entries(newSchema.properties)){
5988
+ newProps[key] = mapSchema(val);
5989
+ }
5990
+ newSchema.properties = newProps;
5991
+ }
5992
+ if (newSchema.items) {
5993
+ newSchema.items = mapSchema(newSchema.items);
5994
+ }
5995
+ // Remove unsupported OpenAI-specific fields if Gemini complains
5996
+ delete newSchema.additionalProperties;
5997
+ delete newSchema['$schema'];
5998
+ return newSchema;
5999
+ };
6000
+ generationConfig.responseSchema = mapSchema(openAISchema);
6001
+ }
5731
6002
  // Gemini format: system instruction is separate, history is separate from last message
5732
6003
  // generateContent accepts a string or parts.
5733
6004
  // We need to construct the prompt.
@@ -5744,7 +6015,8 @@ class GeminiProvider {
5744
6015
  // Let's try to prepend for compatibility if needed, but 'systemInstruction' param exists in getGenerativeModel config.
5745
6016
  const configuredModel = genAI.getGenerativeModel({
5746
6017
  model: modelName,
5747
- systemInstruction: systemInstruction ? systemInstruction.trim() : undefined
6018
+ systemInstruction: systemInstruction ? systemInstruction.trim() : undefined,
6019
+ generationConfig
5748
6020
  });
5749
6021
  // Build history/messages
5750
6022
  // Gemini `generateContent` takes the *last* user message.