recursive-llm-ts 4.0.0 → 4.0.1
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/bin/rlm-go +0 -0
- package/go/internal/rlm/structured.go +63 -10
- package/package.json +1 -1
package/bin/rlm-go
CHANGED
|
Binary file
|
|
@@ -37,22 +37,28 @@ func (r *RLM) structuredCompletionDirect(query string, context string, config *S
|
|
|
37
37
|
|
|
38
38
|
// Build comprehensive prompt with context and schema
|
|
39
39
|
constraints := generateSchemaConstraints(config.Schema)
|
|
40
|
+
requiredFieldsHint := ""
|
|
41
|
+
if config.Schema.Type == "object" && len(config.Schema.Required) > 0 {
|
|
42
|
+
requiredFieldsHint = fmt.Sprintf("\nREQUIRED FIELDS (you MUST include these): %s\n", strings.Join(config.Schema.Required, ", "))
|
|
43
|
+
}
|
|
44
|
+
|
|
40
45
|
prompt := fmt.Sprintf(
|
|
41
46
|
"You are a data extraction assistant. Extract information from the context and return it as JSON.\n\n"+
|
|
42
47
|
"Context:\n%s\n\n"+
|
|
43
48
|
"Task: %s\n\n"+
|
|
44
|
-
"Required JSON Schema:\n%s\n\n"+
|
|
49
|
+
"Required JSON Schema:\n%s%s\n\n"+
|
|
45
50
|
"%s"+
|
|
46
51
|
"CRITICAL INSTRUCTIONS:\n"+
|
|
47
52
|
"1. Return ONLY valid JSON - no explanations, no markdown, no code blocks\n"+
|
|
48
53
|
"2. The JSON must match the schema EXACTLY\n"+
|
|
49
|
-
"3. Include ALL required fields\n"+
|
|
54
|
+
"3. Include ALL required fields (see list above)\n"+
|
|
50
55
|
"4. Use correct data types (strings in quotes, numbers without quotes, arrays in [], objects in {})\n"+
|
|
51
56
|
"5. For arrays, return actual JSON arrays [] not objects\n"+
|
|
52
57
|
"6. For enum fields, use ONLY the EXACT values listed - do not paraphrase or substitute\n"+
|
|
53
|
-
"7.
|
|
58
|
+
"7. For nested objects, ensure ALL required fields within those objects are included\n"+
|
|
59
|
+
"8. Start your response directly with { or [ depending on the schema\n\n"+
|
|
54
60
|
"JSON Response:",
|
|
55
|
-
context, query, string(schemaJSON), constraints,
|
|
61
|
+
context, query, string(schemaJSON), requiredFieldsHint, constraints,
|
|
56
62
|
)
|
|
57
63
|
|
|
58
64
|
var lastErr error
|
|
@@ -192,7 +198,7 @@ func generateSchemaConstraints(schema *JSONSchema) string {
|
|
|
192
198
|
if schema.Type == "object" && schema.Properties != nil {
|
|
193
199
|
for fieldName, fieldSchema := range schema.Properties {
|
|
194
200
|
if fieldSchema.Type == "number" {
|
|
195
|
-
if strings.Contains(strings.ToLower(fieldName), "sentiment") {
|
|
201
|
+
if strings.Contains(strings.ToLower(fieldName), "sentiment") || strings.Contains(strings.ToLower(fieldName), "score") {
|
|
196
202
|
constraints = append(constraints, fmt.Sprintf("- %s must be a number between 1 and 5 (inclusive)", fieldName))
|
|
197
203
|
}
|
|
198
204
|
}
|
|
@@ -202,6 +208,10 @@ func generateSchemaConstraints(schema *JSONSchema) string {
|
|
|
202
208
|
if fieldSchema.Type == "array" {
|
|
203
209
|
constraints = append(constraints, fmt.Sprintf("- %s must be a JSON array []", fieldName))
|
|
204
210
|
}
|
|
211
|
+
// Add constraint for nested objects with required fields
|
|
212
|
+
if fieldSchema.Type == "object" && len(fieldSchema.Required) > 0 {
|
|
213
|
+
constraints = append(constraints, fmt.Sprintf("- %s must be an object with these REQUIRED fields: %s", fieldName, strings.Join(fieldSchema.Required, ", ")))
|
|
214
|
+
}
|
|
205
215
|
}
|
|
206
216
|
}
|
|
207
217
|
|
|
@@ -228,7 +238,7 @@ func generateSchemaConstraints(schema *JSONSchema) string {
|
|
|
228
238
|
// generateFieldQuery creates a focused query for a specific field
|
|
229
239
|
func generateFieldQuery(fieldName string, schema *JSONSchema) string {
|
|
230
240
|
fieldQueries := map[string]string{
|
|
231
|
-
"sentiment": "Analyze the overall sentiment of this conversation.
|
|
241
|
+
"sentiment": "Analyze the overall sentiment of this conversation. Return a JSON object with: score (integer 1-5), confidence (number 0-1), and optional reasoning (string).",
|
|
232
242
|
"sentimentValue": "What is the overall sentiment score (1-5) of this conversation?",
|
|
233
243
|
"sentimentExplanation": "Explain in 2-3 sentences why the conversation has this sentiment score.",
|
|
234
244
|
"phrases": "Extract key phrases that significantly impacted the sentiment, excluding neutral (3-value) phrases. For each phrase, include the sentiment value and the phrase itself (1 sentence).",
|
|
@@ -239,6 +249,12 @@ func generateFieldQuery(fieldName string, schema *JSONSchema) string {
|
|
|
239
249
|
return query
|
|
240
250
|
}
|
|
241
251
|
|
|
252
|
+
// For object types, provide more detailed instructions about required fields
|
|
253
|
+
if schema.Type == "object" && len(schema.Required) > 0 {
|
|
254
|
+
return fmt.Sprintf("Extract the %s from the conversation. Return a JSON object with these required fields: %s.",
|
|
255
|
+
fieldName, strings.Join(schema.Required, ", "))
|
|
256
|
+
}
|
|
257
|
+
|
|
242
258
|
return fmt.Sprintf("Extract the %s from the conversation.", fieldName)
|
|
243
259
|
}
|
|
244
260
|
|
|
@@ -264,11 +280,48 @@ func parseAndValidateJSON(result string, schema *JSONSchema) (map[string]interfa
|
|
|
264
280
|
if parseErr == nil {
|
|
265
281
|
// Check if it's a map (LLM wrapped the value in an object)
|
|
266
282
|
if valueMap, ok := value.(map[string]interface{}); ok {
|
|
267
|
-
//
|
|
268
|
-
|
|
283
|
+
// Try to unwrap based on expected type
|
|
284
|
+
switch schema.Type {
|
|
285
|
+
case "array":
|
|
286
|
+
// Look for any array value in the map
|
|
287
|
+
for _, v := range valueMap {
|
|
288
|
+
if arr, ok := v.([]interface{}); ok {
|
|
289
|
+
value = arr
|
|
290
|
+
break
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
case "string":
|
|
294
|
+
// Look for any string value in the map
|
|
295
|
+
for _, v := range valueMap {
|
|
296
|
+
if str, ok := v.(string); ok {
|
|
297
|
+
value = str
|
|
298
|
+
break
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
case "number":
|
|
302
|
+
// Look for any number value in the map
|
|
269
303
|
for _, v := range valueMap {
|
|
270
|
-
|
|
271
|
-
|
|
304
|
+
switch v.(type) {
|
|
305
|
+
case float64, float32, int, int32, int64:
|
|
306
|
+
value = v
|
|
307
|
+
break
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
case "boolean":
|
|
311
|
+
// Look for any boolean value in the map
|
|
312
|
+
for _, v := range valueMap {
|
|
313
|
+
if b, ok := v.(bool); ok {
|
|
314
|
+
value = b
|
|
315
|
+
break
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
default:
|
|
319
|
+
// For other types, extract single-key value
|
|
320
|
+
if len(valueMap) == 1 {
|
|
321
|
+
for _, v := range valueMap {
|
|
322
|
+
value = v
|
|
323
|
+
break
|
|
324
|
+
}
|
|
272
325
|
}
|
|
273
326
|
}
|
|
274
327
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recursive-llm-ts",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "TypeScript bridge for recursive-llm: Recursive Language Models for unbounded context processing with structured outputs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|