@hiper2d/ai-agents 0.13.1 → 0.14.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/dist/index.d.mts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +76 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,7 @@ interface AIMessage {
|
|
|
16
16
|
googleThoughtSignature?: string;
|
|
17
17
|
grokEncryptedReasoning?: string;
|
|
18
18
|
metaEncryptedReasoning?: string;
|
|
19
|
+
openaiEncryptedReasoning?: string;
|
|
19
20
|
}
|
|
20
21
|
interface TokenUsage$1 {
|
|
21
22
|
inputTokens: number;
|
|
@@ -510,6 +511,7 @@ declare function getProviderSignatureFields(aiType: string, signature?: string):
|
|
|
510
511
|
googleThoughtSignature?: string;
|
|
511
512
|
grokEncryptedReasoning?: string;
|
|
512
513
|
metaEncryptedReasoning?: string;
|
|
514
|
+
openaiEncryptedReasoning?: string;
|
|
513
515
|
};
|
|
514
516
|
|
|
515
517
|
/**
|
|
@@ -1407,6 +1409,24 @@ declare class Gpt5Agent extends AbstractAgent {
|
|
|
1407
1409
|
* inherited from a default OpenAI can change under us.
|
|
1408
1410
|
*/
|
|
1409
1411
|
private reasoningParams;
|
|
1412
|
+
/**
|
|
1413
|
+
* Responses API input items, with each assistant turn's stored reasoning items replayed
|
|
1414
|
+
* immediately before it. OpenAI attaches `encrypted_content` to reasoning items whenever
|
|
1415
|
+
* `store` is false, which is how we call it: the documented stateless route is to preserve
|
|
1416
|
+
* the output items and replay the history yourself, rather than lean on
|
|
1417
|
+
* `previous_response_id` and OpenAI-side session state.
|
|
1418
|
+
*
|
|
1419
|
+
* This was a single flattened string before ("User: ... / Assistant: ..."), which left
|
|
1420
|
+
* nowhere to put reasoning items. The system prompt still travels ONLY as `instructions`.
|
|
1421
|
+
*
|
|
1422
|
+
* Reasoning is readable only within one model family and the API silently omits items it
|
|
1423
|
+
* cannot read, so a bot moved between GPT-6 and GPT-5.6 Terra loses its reasoning and keeps
|
|
1424
|
+
* working. A bot moved to another provider never reaches this code at all: every agent
|
|
1425
|
+
* reads only its own field, and a missing one falls back to a plain message.
|
|
1426
|
+
*/
|
|
1427
|
+
private buildResponsesInput;
|
|
1428
|
+
/** The response's reasoning items, JSON-serialized for the caller to store on the message. */
|
|
1429
|
+
private extractReasoningItems;
|
|
1410
1430
|
/**
|
|
1411
1431
|
* Structured output method using Zod with OpenAI's Responses API
|
|
1412
1432
|
* This provides better schema handling and runtime validation
|
|
@@ -1725,6 +1745,13 @@ declare class QwenAgent extends AbstractAgent {
|
|
|
1725
1745
|
* this agent stays ignored — deliberately, not because effort is broken.
|
|
1726
1746
|
*/
|
|
1727
1747
|
private thinkingParams;
|
|
1748
|
+
/**
|
|
1749
|
+
* Assistant turns carry their own `reasoning_content` back so the model can reference what
|
|
1750
|
+
* it was thinking on earlier turns (paired with `preserve_thinking` in thinkingParams).
|
|
1751
|
+
* Qwen's reasoning is PLAIN TEXT, not a signed or encrypted blob, so there is nothing for
|
|
1752
|
+
* another provider to reject: a bot whose model changes mid-game simply stops sending it
|
|
1753
|
+
* and keeps working. The text is the same one the caller already stores as `thinking`.
|
|
1754
|
+
*/
|
|
1728
1755
|
private convertToOpenAIMessages;
|
|
1729
1756
|
private extractThinkingAndUsage;
|
|
1730
1757
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ interface AIMessage {
|
|
|
16
16
|
googleThoughtSignature?: string;
|
|
17
17
|
grokEncryptedReasoning?: string;
|
|
18
18
|
metaEncryptedReasoning?: string;
|
|
19
|
+
openaiEncryptedReasoning?: string;
|
|
19
20
|
}
|
|
20
21
|
interface TokenUsage$1 {
|
|
21
22
|
inputTokens: number;
|
|
@@ -510,6 +511,7 @@ declare function getProviderSignatureFields(aiType: string, signature?: string):
|
|
|
510
511
|
googleThoughtSignature?: string;
|
|
511
512
|
grokEncryptedReasoning?: string;
|
|
512
513
|
metaEncryptedReasoning?: string;
|
|
514
|
+
openaiEncryptedReasoning?: string;
|
|
513
515
|
};
|
|
514
516
|
|
|
515
517
|
/**
|
|
@@ -1407,6 +1409,24 @@ declare class Gpt5Agent extends AbstractAgent {
|
|
|
1407
1409
|
* inherited from a default OpenAI can change under us.
|
|
1408
1410
|
*/
|
|
1409
1411
|
private reasoningParams;
|
|
1412
|
+
/**
|
|
1413
|
+
* Responses API input items, with each assistant turn's stored reasoning items replayed
|
|
1414
|
+
* immediately before it. OpenAI attaches `encrypted_content` to reasoning items whenever
|
|
1415
|
+
* `store` is false, which is how we call it: the documented stateless route is to preserve
|
|
1416
|
+
* the output items and replay the history yourself, rather than lean on
|
|
1417
|
+
* `previous_response_id` and OpenAI-side session state.
|
|
1418
|
+
*
|
|
1419
|
+
* This was a single flattened string before ("User: ... / Assistant: ..."), which left
|
|
1420
|
+
* nowhere to put reasoning items. The system prompt still travels ONLY as `instructions`.
|
|
1421
|
+
*
|
|
1422
|
+
* Reasoning is readable only within one model family and the API silently omits items it
|
|
1423
|
+
* cannot read, so a bot moved between GPT-6 and GPT-5.6 Terra loses its reasoning and keeps
|
|
1424
|
+
* working. A bot moved to another provider never reaches this code at all: every agent
|
|
1425
|
+
* reads only its own field, and a missing one falls back to a plain message.
|
|
1426
|
+
*/
|
|
1427
|
+
private buildResponsesInput;
|
|
1428
|
+
/** The response's reasoning items, JSON-serialized for the caller to store on the message. */
|
|
1429
|
+
private extractReasoningItems;
|
|
1410
1430
|
/**
|
|
1411
1431
|
* Structured output method using Zod with OpenAI's Responses API
|
|
1412
1432
|
* This provides better schema handling and runtime validation
|
|
@@ -1725,6 +1745,13 @@ declare class QwenAgent extends AbstractAgent {
|
|
|
1725
1745
|
* this agent stays ignored — deliberately, not because effort is broken.
|
|
1726
1746
|
*/
|
|
1727
1747
|
private thinkingParams;
|
|
1748
|
+
/**
|
|
1749
|
+
* Assistant turns carry their own `reasoning_content` back so the model can reference what
|
|
1750
|
+
* it was thinking on earlier turns (paired with `preserve_thinking` in thinkingParams).
|
|
1751
|
+
* Qwen's reasoning is PLAIN TEXT, not a signed or encrypted blob, so there is nothing for
|
|
1752
|
+
* another provider to reject: a bot whose model changes mid-game simply stops sending it
|
|
1753
|
+
* and keeps working. The text is the same one the caller already stores as `thinking`.
|
|
1754
|
+
*/
|
|
1728
1755
|
private convertToOpenAIMessages;
|
|
1729
1756
|
private extractThinkingAndUsage;
|
|
1730
1757
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1702,6 +1702,9 @@ function getProviderSignatureFields(aiType, signature) {
|
|
|
1702
1702
|
if (aiType.startsWith("grok")) {
|
|
1703
1703
|
return { grokEncryptedReasoning: signature };
|
|
1704
1704
|
}
|
|
1705
|
+
if (aiType.startsWith("gpt")) {
|
|
1706
|
+
return { openaiEncryptedReasoning: signature };
|
|
1707
|
+
}
|
|
1705
1708
|
if (aiType.startsWith("muse-")) {
|
|
1706
1709
|
return { metaEncryptedReasoning: signature };
|
|
1707
1710
|
}
|
|
@@ -2526,7 +2529,54 @@ ${instruction}`);
|
|
|
2526
2529
|
* inherited from a default OpenAI can change under us.
|
|
2527
2530
|
*/
|
|
2528
2531
|
reasoningParams() {
|
|
2529
|
-
return
|
|
2532
|
+
return {
|
|
2533
|
+
reasoning: {
|
|
2534
|
+
...this.reasoningEffort ? { effort: toOpenAIEffort(this.reasoningEffort) } : {},
|
|
2535
|
+
// Render reasoning from earlier turns into this sample. It is already the
|
|
2536
|
+
// default on all four models we run, but stated explicitly for the same reason
|
|
2537
|
+
// effort is. It only does anything because we replay the items ourselves.
|
|
2538
|
+
context: "all_turns"
|
|
2539
|
+
}
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Responses API input items, with each assistant turn's stored reasoning items replayed
|
|
2544
|
+
* immediately before it. OpenAI attaches `encrypted_content` to reasoning items whenever
|
|
2545
|
+
* `store` is false, which is how we call it: the documented stateless route is to preserve
|
|
2546
|
+
* the output items and replay the history yourself, rather than lean on
|
|
2547
|
+
* `previous_response_id` and OpenAI-side session state.
|
|
2548
|
+
*
|
|
2549
|
+
* This was a single flattened string before ("User: ... / Assistant: ..."), which left
|
|
2550
|
+
* nowhere to put reasoning items. The system prompt still travels ONLY as `instructions`.
|
|
2551
|
+
*
|
|
2552
|
+
* Reasoning is readable only within one model family and the API silently omits items it
|
|
2553
|
+
* cannot read, so a bot moved between GPT-6 and GPT-5.6 Terra loses its reasoning and keeps
|
|
2554
|
+
* working. A bot moved to another provider never reaches this code at all: every agent
|
|
2555
|
+
* reads only its own field, and a missing one falls back to a plain message.
|
|
2556
|
+
*/
|
|
2557
|
+
buildResponsesInput(messages) {
|
|
2558
|
+
const input = [];
|
|
2559
|
+
for (const msg of this.prepareMessages(messages)) {
|
|
2560
|
+
if (msg.role === "assistant" && msg.openaiEncryptedReasoning) {
|
|
2561
|
+
try {
|
|
2562
|
+
const items = JSON.parse(msg.openaiEncryptedReasoning);
|
|
2563
|
+
if (Array.isArray(items)) {
|
|
2564
|
+
input.push(...items);
|
|
2565
|
+
}
|
|
2566
|
+
} catch {
|
|
2567
|
+
this.logger("Failed to parse stored encrypted reasoning, replaying message without it");
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
input.push({ role: msg.role, content: msg.content });
|
|
2571
|
+
}
|
|
2572
|
+
return input;
|
|
2573
|
+
}
|
|
2574
|
+
/** The response's reasoning items, JSON-serialized for the caller to store on the message. */
|
|
2575
|
+
extractReasoningItems(response) {
|
|
2576
|
+
const items = (response?.output ?? []).filter(
|
|
2577
|
+
(item) => item?.type === "reasoning" && item.encrypted_content
|
|
2578
|
+
);
|
|
2579
|
+
return items.length > 0 ? JSON.stringify(items) : void 0;
|
|
2530
2580
|
}
|
|
2531
2581
|
/**
|
|
2532
2582
|
* Structured output method using Zod with OpenAI's Responses API
|
|
@@ -2538,7 +2588,7 @@ ${instruction}`);
|
|
|
2538
2588
|
try {
|
|
2539
2589
|
this.logAsking(messages);
|
|
2540
2590
|
this.logMessages(messages);
|
|
2541
|
-
const input = this.
|
|
2591
|
+
const input = this.buildResponsesInput(messages);
|
|
2542
2592
|
const schemaToSend = zodSchema;
|
|
2543
2593
|
let response;
|
|
2544
2594
|
try {
|
|
@@ -2548,6 +2598,8 @@ ${instruction}`);
|
|
|
2548
2598
|
input,
|
|
2549
2599
|
max_output_tokens: this.maxOutputTokens,
|
|
2550
2600
|
prompt_cache_key: this.promptCacheKey,
|
|
2601
|
+
// Stateless: encrypted reasoning is only returned for unstored responses.
|
|
2602
|
+
store: false,
|
|
2551
2603
|
...this.reasoningParams(),
|
|
2552
2604
|
text: {
|
|
2553
2605
|
format: (0, import_zod2.zodTextFormat)(schemaToSend, "response_schema")
|
|
@@ -2608,7 +2660,7 @@ ${instruction}`);
|
|
|
2608
2660
|
this.logReply(response.output_parsed, reasoningContent, tokenUsage);
|
|
2609
2661
|
}
|
|
2610
2662
|
this.logger(`\u2705 Response validated successfully with Zod schema`);
|
|
2611
|
-
return [response.output_parsed, reasoningContent, tokenUsage];
|
|
2663
|
+
return [response.output_parsed, reasoningContent, tokenUsage, this.extractReasoningItems(response)];
|
|
2612
2664
|
} catch (error) {
|
|
2613
2665
|
this.logger(this.logTemplates.error(this.name, error));
|
|
2614
2666
|
if (error instanceof ModelError) {
|
|
@@ -2627,13 +2679,14 @@ ${instruction}`);
|
|
|
2627
2679
|
try {
|
|
2628
2680
|
this.logAsking(messages);
|
|
2629
2681
|
this.logMessages(messages);
|
|
2630
|
-
const input = this.
|
|
2682
|
+
const input = this.buildResponsesInput(messages);
|
|
2631
2683
|
const response = await this.client.responses.create({
|
|
2632
2684
|
model: this.model,
|
|
2633
2685
|
instructions: this.instruction,
|
|
2634
2686
|
input,
|
|
2635
2687
|
max_output_tokens: this.maxOutputTokens,
|
|
2636
2688
|
prompt_cache_key: this.promptCacheKey,
|
|
2689
|
+
store: false,
|
|
2637
2690
|
...this.reasoningParams()
|
|
2638
2691
|
});
|
|
2639
2692
|
const content = response.output_text;
|
|
@@ -2675,7 +2728,7 @@ ${instruction}`);
|
|
|
2675
2728
|
}
|
|
2676
2729
|
}
|
|
2677
2730
|
this.logReply(content, "", tokenUsage);
|
|
2678
|
-
return [content, "", tokenUsage];
|
|
2731
|
+
return [content, "", tokenUsage, this.extractReasoningItems(response)];
|
|
2679
2732
|
} catch (error) {
|
|
2680
2733
|
this.logger(this.logTemplates.error(this.name, error));
|
|
2681
2734
|
if (error instanceof ModelError) {
|
|
@@ -4767,13 +4820,29 @@ var QwenAgent = class extends AbstractAgent {
|
|
|
4767
4820
|
const budget = this.thinkingBudgetTokens;
|
|
4768
4821
|
return {
|
|
4769
4822
|
enable_thinking: this.enableThinking,
|
|
4770
|
-
...this.enableThinking && budget !== void 0 ? { thinking_budget: budget } : {}
|
|
4823
|
+
...this.enableThinking && budget !== void 0 ? { thinking_budget: budget } : {},
|
|
4824
|
+
// Lets the model read the `reasoning_content` we replay on assistant messages, so a
|
|
4825
|
+
// bot keeps its own train of thought across turns. Qwen documents models as NOT
|
|
4826
|
+
// reading replayed reasoning unless this is set (qwen3.8-max and qwen3.8-flash are
|
|
4827
|
+
// both on the supported list). Measured 2026-09-22: qwen3.8-max actually used the
|
|
4828
|
+
// replayed reasoning with the flag off too, but we follow the documented contract
|
|
4829
|
+
// rather than rely on that. Stateless — the reasoning comes from our payload, not
|
|
4830
|
+
// from any server-side session.
|
|
4831
|
+
...this.enableThinking ? { preserve_thinking: true } : {}
|
|
4771
4832
|
};
|
|
4772
4833
|
}
|
|
4834
|
+
/**
|
|
4835
|
+
* Assistant turns carry their own `reasoning_content` back so the model can reference what
|
|
4836
|
+
* it was thinking on earlier turns (paired with `preserve_thinking` in thinkingParams).
|
|
4837
|
+
* Qwen's reasoning is PLAIN TEXT, not a signed or encrypted blob, so there is nothing for
|
|
4838
|
+
* another provider to reject: a bot whose model changes mid-game simply stops sending it
|
|
4839
|
+
* and keeps working. The text is the same one the caller already stores as `thinking`.
|
|
4840
|
+
*/
|
|
4773
4841
|
convertToOpenAIMessages(messages) {
|
|
4774
4842
|
return messages.map((msg) => ({
|
|
4775
4843
|
role: msg.role,
|
|
4776
|
-
content: msg.content
|
|
4844
|
+
content: msg.content,
|
|
4845
|
+
...msg.role === "assistant" && msg.thinking ? { reasoning_content: msg.thinking } : {}
|
|
4777
4846
|
}));
|
|
4778
4847
|
}
|
|
4779
4848
|
extractThinkingAndUsage(completion) {
|