@rong/agentscript 0.1.3 → 0.1.4
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/CHANGELOG.md +14 -0
- package/README.md +3 -3
- package/dist/parser/parser.js +20 -5
- package/dist/providers/llm/anthropic.js +6 -2
- package/dist/providers/llm/ollama.js +9 -2
- package/dist/providers/llm/openai.js +15 -1
- package/dist/providers/llm/shared.js +4 -4
- package/dist/runtime/context.js +2 -2
- package/dist/runtime/generate.js +22 -6
- package/dist/runtime/shape.js +6 -4
- package/dist/semantic/analyzer.js +20 -3
- package/docs/cn/context-engineering.md +49 -322
- package/docs/cn/final-expression-return.md +1 -1
- package/docs/cn/generate.md +480 -0
- package/docs/cn/language.md +9 -2
- package/docs/cn/use-as.md +225 -0
- package/docs/en/context-engineering.md +50 -268
- package/docs/en/final-expression-return.md +1 -1
- package/docs/en/generate.md +480 -0
- package/docs/en/language.md +9 -2
- package/docs/en/use-as.md +225 -0
- package/examples/changelog.as +1 -1
- package/examples/extract.as +1 -1
- package/examples/review.as +1 -1
- package/examples/summarize.as +1 -1
- package/examples/translate.as +1 -1
- package/package.json +1 -1
- package/tutorials/cli.as +1 -1
- package/tutorials/plan-execute.as +4 -4
- package/tutorials/react.as +4 -4
- package/docs/cn/role-label.md +0 -492
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to AgentScript will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.1.4 - 2026-05-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `max_output` as the explicit `generate` output budget.
|
|
10
|
+
- Added `temperature`, `think`, and `strict` generate options.
|
|
11
|
+
- Added provider request mapping for generate provider hints.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Replaced generate `limit` usage with `max_output` in current docs, examples, tutorials, and fixtures.
|
|
16
|
+
- Expanded English and Chinese `generate` design docs with configuration semantics.
|
|
17
|
+
- Updated shape validation so `strict: true` disables coercion and rejects extra fields.
|
|
18
|
+
|
|
5
19
|
## 0.1.3 - 2026-05-08
|
|
6
20
|
|
|
7
21
|
### Added
|
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ main agent FileSummarizer {
|
|
|
66
66
|
|
|
67
67
|
generate({
|
|
68
68
|
input: "Summarize the file for a busy teammate"
|
|
69
|
-
|
|
69
|
+
max_output: 1000
|
|
70
70
|
}) -> {
|
|
71
71
|
title string
|
|
72
72
|
summary string
|
|
@@ -254,8 +254,8 @@ agentscript examples/review.as --quiet # value only, no trace
|
|
|
254
254
|
|
|
255
255
|
| Language | Links |
|
|
256
256
|
|----------|-------|
|
|
257
|
-
| English | [Language Reference](docs/en/language.md) · [Context Engineering](docs/en/context-engineering.md) · [Design History](docs/design-history/) |
|
|
258
|
-
| 中文 | [README-CN](./README-CN.md) · [语言参考](docs/cn/language.md) · [Context Engineering](docs/cn/context-engineering.md) |
|
|
257
|
+
| English | [Language Reference](docs/en/language.md) · [Context Engineering](docs/en/context-engineering.md) · [`use ... as ...`](docs/en/use-as.md) · [`generate`](docs/en/generate.md) · [Design History](docs/design-history/) |
|
|
258
|
+
| 中文 | [README-CN](./README-CN.md) · [语言参考](docs/cn/language.md) · [Context Engineering](docs/cn/context-engineering.md) · [`use ... as ...`](docs/cn/use-as.md) · [`generate`](docs/cn/generate.md) |
|
|
259
259
|
|
|
260
260
|
### Design principles
|
|
261
261
|
|
package/dist/parser/parser.js
CHANGED
|
@@ -434,16 +434,19 @@ class Parser {
|
|
|
434
434
|
const properties = [];
|
|
435
435
|
let input;
|
|
436
436
|
let attempts;
|
|
437
|
-
let
|
|
437
|
+
let maxOutput;
|
|
438
|
+
let temperature;
|
|
439
|
+
let think;
|
|
440
|
+
let strict;
|
|
438
441
|
let debug;
|
|
439
442
|
while (!this.check("}") && !this.isAtEnd()) {
|
|
440
443
|
const propStart = this.peek().range.start;
|
|
441
444
|
const key = this.consumeObjectKey();
|
|
442
445
|
this.consume(":");
|
|
443
446
|
let value;
|
|
444
|
-
if (key === "
|
|
445
|
-
const token = this.consumeKind("number", "Expected generate
|
|
446
|
-
|
|
447
|
+
if (key === "max_output") {
|
|
448
|
+
const token = this.consumeKind("number", "Expected generate max_output");
|
|
449
|
+
maxOutput = this.parseBudgetToken(token);
|
|
447
450
|
value = {
|
|
448
451
|
kind: "NumberExpr",
|
|
449
452
|
value: Number.parseFloat(token.value),
|
|
@@ -466,6 +469,15 @@ class Parser {
|
|
|
466
469
|
else if (key === "attempts" && value.kind === "NumberExpr") {
|
|
467
470
|
attempts = value;
|
|
468
471
|
}
|
|
472
|
+
else if (key === "temperature" && value.kind === "NumberExpr") {
|
|
473
|
+
temperature = value;
|
|
474
|
+
}
|
|
475
|
+
else if (key === "think" && (value.kind === "BooleanExpr" || value.kind === "StringExpr")) {
|
|
476
|
+
think = value;
|
|
477
|
+
}
|
|
478
|
+
else if (key === "strict" && value.kind === "BooleanExpr") {
|
|
479
|
+
strict = value;
|
|
480
|
+
}
|
|
469
481
|
else if (key === "debug" && value.kind === "BooleanExpr") {
|
|
470
482
|
debug = value;
|
|
471
483
|
}
|
|
@@ -477,7 +489,10 @@ class Parser {
|
|
|
477
489
|
properties,
|
|
478
490
|
input,
|
|
479
491
|
attempts,
|
|
480
|
-
|
|
492
|
+
maxOutput,
|
|
493
|
+
temperature,
|
|
494
|
+
think,
|
|
495
|
+
strict,
|
|
481
496
|
debug,
|
|
482
497
|
range: { start, end: this.previous().range.end }
|
|
483
498
|
};
|
|
@@ -5,7 +5,7 @@ export async function callAnthropic(request, parsed, options, fetchImpl, timeout
|
|
|
5
5
|
if (!apiKey) {
|
|
6
6
|
throw new RuntimeError("ANTHROPIC_API_KEY is required for anthropic:// models");
|
|
7
7
|
}
|
|
8
|
-
const
|
|
8
|
+
const body = {
|
|
9
9
|
model: parsed.model,
|
|
10
10
|
max_tokens: budgetToTokenLimit(request) ?? 1024,
|
|
11
11
|
system: request.builtContext.system,
|
|
@@ -15,7 +15,11 @@ export async function callAnthropic(request, parsed, options, fetchImpl, timeout
|
|
|
15
15
|
content: request.builtContext.finalUserMessage,
|
|
16
16
|
},
|
|
17
17
|
],
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
|
+
if (request.temperature !== undefined) {
|
|
20
|
+
body.temperature = request.temperature;
|
|
21
|
+
}
|
|
22
|
+
const response = await postJson(fetchImpl, `${baseUrl}/messages`, body, timeoutMs, {
|
|
19
23
|
"x-api-key": apiKey,
|
|
20
24
|
"anthropic-version": "2023-06-01",
|
|
21
25
|
});
|
|
@@ -3,7 +3,7 @@ export async function callOllama(request, parsed, fetchImpl, timeoutMs, baseUrl)
|
|
|
3
3
|
const body = {
|
|
4
4
|
model: parsed.model,
|
|
5
5
|
stream: false,
|
|
6
|
-
think: false,
|
|
6
|
+
think: request.think ?? false,
|
|
7
7
|
messages: [
|
|
8
8
|
{ role: "system", content: request.builtContext.system },
|
|
9
9
|
{ role: "user", content: request.builtContext.finalUserMessage },
|
|
@@ -13,8 +13,15 @@ export async function callOllama(request, parsed, fetchImpl, timeoutMs, baseUrl)
|
|
|
13
13
|
body.format = request.builtContext.returnSchema;
|
|
14
14
|
}
|
|
15
15
|
const maxTokens = budgetToTokenLimit(request);
|
|
16
|
+
const options = {};
|
|
16
17
|
if (maxTokens) {
|
|
17
|
-
|
|
18
|
+
options.num_predict = maxTokens;
|
|
19
|
+
}
|
|
20
|
+
if (request.temperature !== undefined) {
|
|
21
|
+
options.temperature = request.temperature;
|
|
22
|
+
}
|
|
23
|
+
if (Object.keys(options).length > 0) {
|
|
24
|
+
body.options = options;
|
|
18
25
|
}
|
|
19
26
|
const response = await postJson(fetchImpl, `${baseUrl}/api/chat`, body, timeoutMs);
|
|
20
27
|
const text = readPath(response, ["message", "content"]);
|
|
@@ -17,11 +17,18 @@ export async function callOpenAI(request, parsed, options, fetchImpl, timeoutMs,
|
|
|
17
17
|
type: "json_schema",
|
|
18
18
|
json_schema: {
|
|
19
19
|
name: "agentscript_generate",
|
|
20
|
-
strict:
|
|
20
|
+
strict: request.strict,
|
|
21
21
|
schema: request.builtContext.returnSchema,
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
if (request.temperature !== undefined) {
|
|
26
|
+
body.temperature = request.temperature;
|
|
27
|
+
}
|
|
28
|
+
const reasoningEffort = openAIReasoningEffort(request.think);
|
|
29
|
+
if (reasoningEffort) {
|
|
30
|
+
body.reasoning_effort = reasoningEffort;
|
|
31
|
+
}
|
|
25
32
|
const maxTokens = budgetToTokenLimit(request);
|
|
26
33
|
if (maxTokens) {
|
|
27
34
|
body.max_completion_tokens = maxTokens;
|
|
@@ -32,3 +39,10 @@ export async function callOpenAI(request, parsed, options, fetchImpl, timeoutMs,
|
|
|
32
39
|
const text = readPath(response, ["choices", 0, "message", "content"]);
|
|
33
40
|
return request.returnShape ? parseJsonText(text) : text;
|
|
34
41
|
}
|
|
42
|
+
function openAIReasoningEffort(think) {
|
|
43
|
+
if (think === true)
|
|
44
|
+
return "medium";
|
|
45
|
+
if (think === "low" || think === "medium" || think === "high")
|
|
46
|
+
return think;
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { RuntimeError } from "../../runtime/errors.js";
|
|
2
2
|
export function budgetToTokenLimit(request) {
|
|
3
|
-
if (!request.
|
|
3
|
+
if (!request.maxOutput) {
|
|
4
4
|
return undefined;
|
|
5
5
|
}
|
|
6
|
-
if (request.
|
|
7
|
-
return Math.max(1, Math.floor(request.
|
|
6
|
+
if (request.maxOutput.unit === "k") {
|
|
7
|
+
return Math.max(1, Math.floor(request.maxOutput.amount * 1000));
|
|
8
8
|
}
|
|
9
|
-
return Math.max(1, Math.floor(request.
|
|
9
|
+
return Math.max(1, Math.floor(request.maxOutput.amount));
|
|
10
10
|
}
|
|
11
11
|
export async function postJson(fetchImpl, url, body, timeoutMs, headers = {}) {
|
|
12
12
|
const controller = new AbortController();
|
package/dist/runtime/context.js
CHANGED
|
@@ -14,7 +14,7 @@ export function buildContext(input) {
|
|
|
14
14
|
instruction,
|
|
15
15
|
instructionText,
|
|
16
16
|
returnSchema,
|
|
17
|
-
|
|
17
|
+
maxOutput: input.maxOutput,
|
|
18
18
|
finalUserMessage: buildFinalUserMessage(context, instructionText, returnSchema),
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -166,7 +166,7 @@ export function builtContextToJson(context) {
|
|
|
166
166
|
})),
|
|
167
167
|
instruction: context.instruction,
|
|
168
168
|
returnSchema: context.returnSchema ?? null,
|
|
169
|
-
|
|
169
|
+
maxOutput: budgetToJson(context.maxOutput),
|
|
170
170
|
finalUserMessage: context.finalUserMessage,
|
|
171
171
|
};
|
|
172
172
|
}
|
package/dist/runtime/generate.js
CHANGED
|
@@ -29,7 +29,7 @@ export class GenerateRuntime {
|
|
|
29
29
|
instruction,
|
|
30
30
|
returnShape: expr.returnShape,
|
|
31
31
|
uses: context,
|
|
32
|
-
|
|
32
|
+
maxOutput: options.maxOutput,
|
|
33
33
|
});
|
|
34
34
|
if (options.debug) {
|
|
35
35
|
writeDebugPrompt(agent.name, attempt, builtContext);
|
|
@@ -44,7 +44,11 @@ export class GenerateRuntime {
|
|
|
44
44
|
returnShape: expr.returnShape,
|
|
45
45
|
context,
|
|
46
46
|
builtContext,
|
|
47
|
-
|
|
47
|
+
maxOutput: options.maxOutput,
|
|
48
|
+
temperature: options.temperature,
|
|
49
|
+
think: options.think,
|
|
50
|
+
strict: options.strict,
|
|
51
|
+
debug: options.debug,
|
|
48
52
|
});
|
|
49
53
|
}
|
|
50
54
|
catch (error) {
|
|
@@ -58,18 +62,27 @@ export class GenerateRuntime {
|
|
|
58
62
|
continue;
|
|
59
63
|
}
|
|
60
64
|
try {
|
|
61
|
-
const result = expr.returnShape ? coerceValueToShape(rawResult, expr.returnShape) : rawResult;
|
|
65
|
+
const result = expr.returnShape && !options.strict ? coerceValueToShape(rawResult, expr.returnShape) : rawResult;
|
|
62
66
|
if (expr.returnShape) {
|
|
63
|
-
validateValueAgainstShape(result, expr.returnShape, expr.range);
|
|
67
|
+
validateValueAgainstShape(result, expr.returnShape, expr.range, { rejectExtraFields: options.strict });
|
|
64
68
|
}
|
|
65
69
|
this.trace.push({
|
|
66
70
|
kind: "generate",
|
|
67
71
|
data: {
|
|
68
72
|
instruction: sanitizeForJson(options.input),
|
|
73
|
+
config: {
|
|
74
|
+
maxOutput: budgetToJson(options.maxOutput),
|
|
75
|
+
attempts: options.attempts,
|
|
76
|
+
temperature: options.temperature ?? null,
|
|
77
|
+
think: options.think ?? false,
|
|
78
|
+
strict: options.strict,
|
|
79
|
+
debug: options.debug,
|
|
80
|
+
},
|
|
69
81
|
attempts: attempt,
|
|
70
|
-
|
|
82
|
+
maxOutput: budgetToJson(options.maxOutput),
|
|
71
83
|
debug: options.debug,
|
|
72
84
|
context: builtContextToJson(builtContext),
|
|
85
|
+
validation: expr.returnShape ? { ok: true, strict: options.strict } : null,
|
|
73
86
|
result: sanitizeForJson(result),
|
|
74
87
|
},
|
|
75
88
|
});
|
|
@@ -99,7 +112,10 @@ export class GenerateRuntime {
|
|
|
99
112
|
return {
|
|
100
113
|
input: await this.host.evaluate(expr.options.input, scope),
|
|
101
114
|
attempts,
|
|
102
|
-
|
|
115
|
+
maxOutput: expr.options.maxOutput,
|
|
116
|
+
temperature: expr.options.temperature?.value,
|
|
117
|
+
think: expr.options.think?.value,
|
|
118
|
+
strict: expr.options.strict?.value ?? false,
|
|
103
119
|
debug: expr.options.debug?.value ?? false,
|
|
104
120
|
};
|
|
105
121
|
}
|
package/dist/runtime/shape.js
CHANGED
|
@@ -7,14 +7,16 @@ export function buildValueFromShape(shape) {
|
|
|
7
7
|
}
|
|
8
8
|
return result;
|
|
9
9
|
}
|
|
10
|
-
export function validateValueAgainstShape(value, shape, range) {
|
|
10
|
+
export function validateValueAgainstShape(value, shape, range, options = {}) {
|
|
11
11
|
if (!isObject(value)) {
|
|
12
12
|
throw new RuntimeError("LLM result must be an object matching the generate return shape", range);
|
|
13
13
|
}
|
|
14
14
|
const allowedFields = new Set(shape.fields.map((field) => field.name));
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if (options.rejectExtraFields) {
|
|
16
|
+
for (const key of Object.keys(value)) {
|
|
17
|
+
if (!allowedFields.has(key)) {
|
|
18
|
+
throw new RuntimeError(`LLM result contains unexpected field '${key}'`, range);
|
|
19
|
+
}
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
for (const field of shape.fields) {
|
|
@@ -395,9 +395,26 @@ class Analyzer {
|
|
|
395
395
|
this.error("INVALID_GENERATE_ATTEMPTS", "generate attempts must be a positive integer", property.value.range);
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
|
-
else if (property.key === "
|
|
399
|
-
if (!expr.options.
|
|
400
|
-
this.error("
|
|
398
|
+
else if (property.key === "max_output") {
|
|
399
|
+
if (!expr.options.maxOutput || expr.options.maxOutput.amount <= 0) {
|
|
400
|
+
this.error("INVALID_GENERATE_MAX_OUTPUT", "generate max_output must be a positive budget", property.value.range);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else if (property.key === "temperature") {
|
|
404
|
+
if (property.value.kind !== "NumberExpr") {
|
|
405
|
+
this.error("INVALID_GENERATE_TEMPERATURE", "generate temperature must be a number", property.value.range);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else if (property.key === "think") {
|
|
409
|
+
const validThinkString = property.value.kind === "StringExpr" &&
|
|
410
|
+
["auto", "low", "medium", "high"].includes(property.value.value);
|
|
411
|
+
if (property.value.kind !== "BooleanExpr" && !validThinkString) {
|
|
412
|
+
this.error("INVALID_GENERATE_THINK", "generate think must be a boolean or one of auto, low, medium, high", property.value.range);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
else if (property.key === "strict") {
|
|
416
|
+
if (property.value.kind !== "BooleanExpr") {
|
|
417
|
+
this.error("INVALID_GENERATE_STRICT", "generate strict must be a boolean", property.value.range);
|
|
401
418
|
}
|
|
402
419
|
}
|
|
403
420
|
else if (property.key === "debug") {
|