@haikeilabs/agentware 0.1.0 → 0.2.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.
Files changed (63) hide show
  1. package/README.md +19 -0
  2. package/dist/executor/agent_loop.d.ts +50 -0
  3. package/dist/executor/agent_loop.d.ts.map +1 -0
  4. package/dist/executor/agent_loop.js +255 -0
  5. package/dist/executor/executor.d.ts.map +1 -1
  6. package/dist/executor/executor.js +6 -2
  7. package/dist/executor/index.d.ts +2 -1
  8. package/dist/executor/index.d.ts.map +1 -1
  9. package/dist/executor/index.js +2 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -0
  13. package/dist/kei/index.d.ts +2 -0
  14. package/dist/kei/index.d.ts.map +1 -0
  15. package/dist/kei/index.js +1 -0
  16. package/dist/kei/runtimeLink.d.ts +281 -0
  17. package/dist/kei/runtimeLink.d.ts.map +1 -0
  18. package/dist/kei/runtimeLink.js +591 -0
  19. package/dist/llm/backend.d.ts +7 -0
  20. package/dist/llm/backend.d.ts.map +1 -1
  21. package/dist/llm/index.d.ts +2 -1
  22. package/dist/llm/index.d.ts.map +1 -1
  23. package/dist/llm/index.js +1 -0
  24. package/dist/llm/openai_backend.d.ts +51 -0
  25. package/dist/llm/openai_backend.d.ts.map +1 -0
  26. package/dist/llm/openai_backend.js +203 -0
  27. package/dist/llm/response.d.ts +5 -0
  28. package/dist/llm/response.d.ts.map +1 -1
  29. package/dist/middleware/guardrails/response_validator.d.ts +1 -1
  30. package/dist/middleware/guardrails/response_validator.d.ts.map +1 -1
  31. package/dist/middleware/guardrails/response_validator.js +1 -1
  32. package/dist/middleware/index.d.ts +5 -0
  33. package/dist/middleware/index.d.ts.map +1 -1
  34. package/dist/middleware/index.js +5 -0
  35. package/dist/middleware/inference.d.ts +8 -0
  36. package/dist/middleware/inference.d.ts.map +1 -1
  37. package/dist/middleware/inference.js +73 -31
  38. package/dist/reasoning/adapter.d.ts +33 -0
  39. package/dist/reasoning/adapter.d.ts.map +1 -0
  40. package/dist/reasoning/adapter.js +365 -0
  41. package/dist/reasoning/errors.d.ts +28 -0
  42. package/dist/reasoning/errors.d.ts.map +1 -0
  43. package/dist/reasoning/errors.js +57 -0
  44. package/dist/reasoning/index.d.ts +6 -0
  45. package/dist/reasoning/index.d.ts.map +1 -0
  46. package/dist/reasoning/index.js +4 -0
  47. package/dist/reasoning/options.d.ts +18 -0
  48. package/dist/reasoning/options.d.ts.map +1 -0
  49. package/dist/reasoning/options.js +18 -0
  50. package/dist/reasoning/types.d.ts +44 -0
  51. package/dist/reasoning/types.d.ts.map +1 -0
  52. package/dist/reasoning/types.js +32 -0
  53. package/dist/toolformat/formatter.d.ts +3 -3
  54. package/dist/toolformat/formatter.d.ts.map +1 -1
  55. package/dist/tools/index.d.ts +2 -2
  56. package/dist/tools/index.d.ts.map +1 -1
  57. package/dist/tools/index.js +2 -2
  58. package/dist/tools/registry.d.ts +4 -4
  59. package/dist/tools/registry.d.ts.map +1 -1
  60. package/dist/tools/tool.d.ts +8 -1
  61. package/dist/tools/tool.d.ts.map +1 -1
  62. package/dist/tools/tool.js +7 -0
  63. package/package.json +17 -1
@@ -0,0 +1,203 @@
1
+ import { Role } from "./request.js";
2
+ export class OpenAIError extends Error {
3
+ status;
4
+ constructor(message, status) {
5
+ super(message);
6
+ this.name = "OpenAIError";
7
+ this.status = status;
8
+ }
9
+ }
10
+ const DEFAULT_BASE_URL = "https://api.openai.com/v1";
11
+ const DEFAULT_TIMEOUT_MS = 60_000;
12
+ const DEFAULT_MAX_RESPONSE_BYTES = 1_048_576;
13
+ const DEFAULT_MAX_TOOL_ARG_BYTES = 65_536;
14
+ const DEFAULT_CONTEXT_WINDOW = 128_000;
15
+ const MAX_ERROR_DETAIL_CHARS = 512;
16
+ export function parseToolArguments(raw, maxBytes) {
17
+ if (!raw) {
18
+ return {};
19
+ }
20
+ const bounded = raw.length > maxBytes ? raw.slice(0, maxBytes) : raw;
21
+ try {
22
+ const parsed = JSON.parse(bounded);
23
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
24
+ return parsed;
25
+ }
26
+ }
27
+ catch {
28
+ // fall through to raw fallback
29
+ }
30
+ return { _raw: bounded };
31
+ }
32
+ function toOpenAIMessage(message) {
33
+ switch (message.role) {
34
+ case Role.TOOL:
35
+ return {
36
+ role: "tool",
37
+ tool_call_id: message.tool_call_id ?? "",
38
+ content: message.content,
39
+ };
40
+ case Role.ASSISTANT:
41
+ if (message.tool_calls && message.tool_calls.length > 0) {
42
+ return {
43
+ role: "assistant",
44
+ content: message.content || null,
45
+ tool_calls: message.tool_calls.map((tc) => ({
46
+ id: tc.id,
47
+ type: "function",
48
+ function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
49
+ })),
50
+ };
51
+ }
52
+ return { role: "assistant", content: message.content };
53
+ default:
54
+ return { role: message.role, content: message.content };
55
+ }
56
+ }
57
+ function toOpenAITool(tool) {
58
+ return {
59
+ type: "function",
60
+ function: {
61
+ name: tool.name,
62
+ description: tool.description,
63
+ parameters: tool.input_schema,
64
+ },
65
+ };
66
+ }
67
+ function truncateDetail(text) {
68
+ if (text.length <= MAX_ERROR_DETAIL_CHARS) {
69
+ return text;
70
+ }
71
+ return text.slice(0, MAX_ERROR_DETAIL_CHARS) + "...";
72
+ }
73
+ function toError(err) {
74
+ return err instanceof Error ? err : new Error(String(err));
75
+ }
76
+ export class OpenAIBackend {
77
+ model;
78
+ baseUrl;
79
+ apiKey;
80
+ fetchFn;
81
+ timeoutMs;
82
+ maxResponseBytes;
83
+ maxToolArgBytes;
84
+ contextWindow;
85
+ temperature;
86
+ maxTokens;
87
+ constructor(config) {
88
+ this.model = config.model;
89
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
90
+ this.apiKey = config.apiKey ?? "";
91
+ this.fetchFn = config.fetchFn ?? fetch;
92
+ this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
93
+ this.maxResponseBytes = config.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
94
+ this.maxToolArgBytes = config.maxToolArgBytes ?? DEFAULT_MAX_TOOL_ARG_BYTES;
95
+ this.contextWindow = config.contextWindowSize ?? DEFAULT_CONTEXT_WINDOW;
96
+ this.temperature = config.temperature;
97
+ this.maxTokens = config.maxTokens;
98
+ }
99
+ async complete(messages, tools) {
100
+ const payload = {
101
+ model: this.model,
102
+ messages: messages.map(toOpenAIMessage),
103
+ };
104
+ if (this.temperature !== undefined) {
105
+ payload.temperature = this.temperature;
106
+ }
107
+ if (this.maxTokens !== undefined) {
108
+ payload.max_tokens = this.maxTokens;
109
+ }
110
+ if (tools && tools.length > 0) {
111
+ payload.tools = tools.map(toOpenAITool);
112
+ payload.tool_choice = "auto";
113
+ }
114
+ const headers = {
115
+ "Content-Type": "application/json",
116
+ };
117
+ if (this.apiKey) {
118
+ headers.Authorization = `Bearer ${this.apiKey}`;
119
+ }
120
+ const controller = new AbortController();
121
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
122
+ try {
123
+ let res;
124
+ try {
125
+ res = await this.fetchFn(`${this.baseUrl}/chat/completions`, {
126
+ method: "POST",
127
+ headers,
128
+ body: JSON.stringify(payload),
129
+ signal: controller.signal,
130
+ });
131
+ }
132
+ catch (err) {
133
+ if (controller.signal.aborted ||
134
+ (err instanceof Error && err.name === "AbortError")) {
135
+ throw new OpenAIError(`request timed out after ${this.timeoutMs}ms`);
136
+ }
137
+ throw new OpenAIError(`request failed: ${toError(err).message}`);
138
+ }
139
+ const text = await res.text();
140
+ if (text.length > this.maxResponseBytes) {
141
+ throw new OpenAIError(`response body exceeds limit of ${this.maxResponseBytes} bytes`);
142
+ }
143
+ if (!res.ok) {
144
+ throw new OpenAIError(`HTTP ${res.status}: ${truncateDetail(text)}`, res.status);
145
+ }
146
+ let data;
147
+ try {
148
+ data = JSON.parse(text);
149
+ }
150
+ catch {
151
+ throw new OpenAIError("malformed JSON in response body");
152
+ }
153
+ return this.parseCompletion(data);
154
+ }
155
+ finally {
156
+ clearTimeout(timer);
157
+ }
158
+ }
159
+ parseCompletion(data) {
160
+ const completion = data;
161
+ const choice = completion.choices?.[0];
162
+ const message = choice?.message;
163
+ if (!message) {
164
+ throw new OpenAIError("unexpected response shape: missing choices[0].message");
165
+ }
166
+ const toolCalls = [];
167
+ if (message.tool_calls) {
168
+ for (let i = 0; i < message.tool_calls.length; i++) {
169
+ const tc = message.tool_calls[i];
170
+ const name = tc.function?.name;
171
+ if (!name) {
172
+ continue;
173
+ }
174
+ toolCalls.push({
175
+ id: tc.id ?? `call_${i}`,
176
+ name,
177
+ arguments: parseToolArguments(tc.function?.arguments, this.maxToolArgBytes),
178
+ });
179
+ }
180
+ }
181
+ const usage = {
182
+ prompt_tokens: completion.usage?.prompt_tokens ?? 0,
183
+ completion_tokens: completion.usage?.completion_tokens ?? 0,
184
+ total_tokens: completion.usage?.total_tokens ?? 0,
185
+ };
186
+ return {
187
+ content: message.content ?? "",
188
+ reasoning: message.reasoning_content ?? "",
189
+ tool_calls: toolCalls,
190
+ finish_reason: choice?.finish_reason ?? "",
191
+ usage_tokens: usage,
192
+ };
193
+ }
194
+ supportsNativeToolCalling() {
195
+ return true;
196
+ }
197
+ modelName() {
198
+ return this.model;
199
+ }
200
+ contextWindowSize() {
201
+ return this.contextWindow;
202
+ }
203
+ }
@@ -10,6 +10,11 @@ export interface TokenUsage {
10
10
  }
11
11
  export interface Response {
12
12
  content: string;
13
+ /** Raw reasoning returned on a separate channel (e.g. reasoning_content for
14
+ * DeepSeek-style models). Never written into content, never returned to the
15
+ * end user, and never recorded on a default audit record; consumers
16
+ * normalize it with the reasoning adapter. */
17
+ reasoning: string;
13
18
  tool_calls: ToolCall[];
14
19
  finish_reason: string;
15
20
  usage_tokens: TokenUsage;
@@ -1 +1 @@
1
- {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/llm/response.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,UAAU,CAAC;CAC1B"}
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/llm/response.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB;;;kDAG8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,UAAU,CAAC;CAC1B"}
@@ -1,4 +1,4 @@
1
- import { Nudge } from "./nudge";
1
+ import { Nudge } from "./nudge.js";
2
2
  export interface ToolCall {
3
3
  tool: string;
4
4
  args: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"response_validator.d.ts","sourceRoot":"","sources":["../../../src/middleware/guardrails/response_validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAgC,MAAM,SAAS,CAAC;AAE9D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,YAAY,CAAsD;IAE1E,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,mBAAmB,CAAS;gBAGlC,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,GAAE,OAAc,EAC7B,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,KAAK;IAapE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IAYxD,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,gBAAgB;IAoB1D,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,oBAAoB;IAqC5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,yBAAyB;IA0BjC,OAAO,CAAC,uBAAuB;CAGhC"}
1
+ {"version":3,"file":"response_validator.d.ts","sourceRoot":"","sources":["../../../src/middleware/guardrails/response_validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAgC,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,YAAY,CAAsD;IAE1E,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,mBAAmB,CAAS;gBAGlC,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,GAAE,OAAc,EAC7B,YAAY,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,KAAK;IAapE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IAYxD,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,gBAAgB;IAoB1D,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,oBAAoB;IAqC5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,yBAAyB;IA0BjC,OAAO,CAAC,uBAAuB;CAGhC"}
@@ -1,4 +1,4 @@
1
- import { retryNudge, unknownToolNudge } from "./nudge";
1
+ import { retryNudge, unknownToolNudge } from "./nudge.js";
2
2
  export class ResponseValidator {
3
3
  toolNames;
4
4
  rescueEnabled;
@@ -2,4 +2,9 @@ export { MiddlewareImpl, Middleware, ToolExecutor } from "./middleware.js";
2
2
  export { Action, CallerContext, Decision, MessageType, MessageMeta } from "./types.js";
3
3
  export { PolicyEvaluator, Policy, Rule, Condition, Operator, SimplePolicyEvaluator } from "./policy.js";
4
4
  export { Auditor, AuditRecord, InMemoryAuditor, AuditFilter } from "./audit.js";
5
+ export { runInference, InferenceConfig, InferenceResult, RetriesExhaustedError, } from "./inference.js";
6
+ export { ResponseValidator, ValidationResult, ToolCall as ValidatedToolCall, } from "./guardrails/response_validator.js";
7
+ export { Nudge, NudgeKind, retryNudge, unknownToolNudge, stepNudge, prerequisiteNudge, } from "./guardrails/nudge.js";
8
+ export { ErrorTracker, ErrorCategory, ToolError, } from "./guardrails/error_tracker.js";
9
+ export { StepEnforcer, StepNotAllowedError } from "./guardrails/step_enforcer.js";
5
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,IAAI,iBAAiB,GAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,KAAK,EACL,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC"}
@@ -2,3 +2,8 @@ export { MiddlewareImpl } from "./middleware.js";
2
2
  export { Action, MessageType } from "./types.js";
3
3
  export { Operator, SimplePolicyEvaluator } from "./policy.js";
4
4
  export { InMemoryAuditor } from "./audit.js";
5
+ export { runInference, RetriesExhaustedError, } from "./inference.js";
6
+ export { ResponseValidator, } from "./guardrails/response_validator.js";
7
+ export { NudgeKind, retryNudge, unknownToolNudge, stepNudge, prerequisiteNudge, } from "./guardrails/nudge.js";
8
+ export { ErrorTracker, ErrorCategory, } from "./guardrails/error_tracker.js";
9
+ export { StepEnforcer, StepNotAllowedError } from "./guardrails/step_enforcer.js";
@@ -5,6 +5,7 @@ import type { ContextWindowManager } from "../llmcontext/context_window.js";
5
5
  import type { ResponseValidator } from "./guardrails/response_validator.js";
6
6
  import { ErrorTracker } from "./guardrails/error_tracker.js";
7
7
  import { StepEnforcer } from "./guardrails/step_enforcer.js";
8
+ import { ReasoningAdapter, type ContextTree } from "../reasoning/index.js";
8
9
  export declare class RetriesExhaustedError extends Error {
9
10
  constructor(message: string);
10
11
  }
@@ -13,6 +14,10 @@ export interface InferenceResult {
13
14
  newMessages: Message[];
14
15
  toolCallCounter: number;
15
16
  attempts: number;
17
+ /** Normalized context tree for the final turn's reasoning (native
18
+ * reasoning_content and/or thinking tags). Null when the turn carried no
19
+ * reasoning. Holds bounded summaries only; raw reasoning is never attached. */
20
+ reasoningTree: ContextTree | null;
16
21
  }
17
22
  export interface InferenceConfig {
18
23
  client: Backend;
@@ -23,6 +28,9 @@ export interface InferenceConfig {
23
28
  toolSpecs: ToolDefinition[];
24
29
  maxAttempts: number;
25
30
  stepIndex?: number;
31
+ /** Optional reasoning adapter override for limits and registered model
32
+ * fields. */
33
+ reasoning?: ReasoningAdapter;
26
34
  }
27
35
  export declare function runInference(messages: Message[], cfg: InferenceConfig, sessionId?: string): Promise<InferenceResult | null>;
28
36
  //# sourceMappingURL=inference.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/middleware/inference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAA2B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAA8B,MAAM,oCAAoC,CAAC;AACxG,OAAO,EAAE,YAAY,EAAiB,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,EAAE,eAAe,EACpB,SAAS,GAAE,MAAW,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAwJjC"}
1
+ {"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/middleware/inference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAA2B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAA8B,MAAM,oCAAoC,CAAC;AACxG,OAAO,EAAE,YAAY,EAAiB,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAkB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE3F,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB;;mFAE+E;IAC/E,aAAa,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;iBACa;IACb,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAKD,wBAAsB,YAAY,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,EAAE,eAAe,EACpB,SAAS,GAAE,MAAW,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA8LjC"}
@@ -2,12 +2,15 @@ import { Role } from "../llm/request.js";
2
2
  import { MessageType } from "./types.js";
3
3
  import { ErrorCategory } from "./guardrails/error_tracker.js";
4
4
  import { stepNudge } from "./guardrails/nudge.js";
5
+ import { ReasoningAdapter, ReasoningError } from "../reasoning/index.js";
5
6
  export class RetriesExhaustedError extends Error {
6
7
  constructor(message) {
7
8
  super(message);
8
9
  this.name = "RetriesExhaustedError";
9
10
  }
10
11
  }
12
+ // Default adapter strips and normalizes reasoning in the inference loop.
13
+ const defaultAdapter = new ReasoningAdapter();
11
14
  export async function runInference(messages, cfg, sessionId = "") {
12
15
  let maxAttempts = cfg.maxAttempts;
13
16
  if (maxAttempts <= 0) {
@@ -49,43 +52,81 @@ export async function runInference(messages, cfg, sessionId = "") {
49
52
  cfg.contextManager.updateTokenCount(resp.usage_tokens.total_tokens);
50
53
  }
51
54
  let validationResult = null;
52
- if (resp.tool_calls && resp.tool_calls.length > 0) {
53
- const guardrailsToolCalls = resp.tool_calls.map((tc) => ({
54
- tool: tc.name,
55
- args: tc.arguments,
56
- }));
57
- if (cfg.validator) {
58
- validationResult = cfg.validator.validateToolCalls(guardrailsToolCalls);
55
+ // AR-1: normalize reasoning and strip it before ordinary tool-call
56
+ // parsing. Reasoning can arrive as a native reasoning_content field or as
57
+ // embedded thinking tags in content; both are combined into a synthetic
58
+ // structured input so the adapter sees the full picture. Malformed or
59
+ // unbounded reasoning fails closed: this turn is treated as invalid and
60
+ // retried rather than parsed partially.
61
+ let reasoningTree = null;
62
+ let cleanContent = resp.content;
63
+ let reasoningFailed = false;
64
+ if (resp.content || resp.reasoning) {
65
+ const reasoningInput = { content: resp.content };
66
+ if (resp.reasoning) {
67
+ reasoningInput["reasoning_content"] = resp.reasoning;
59
68
  }
60
- else {
61
- validationResult = {
62
- toolCalls: guardrailsToolCalls,
63
- nudge: null,
64
- needsRetry: false,
65
- };
66
- }
67
- }
68
- else if (resp.content) {
69
- if (cfg.validator) {
70
- validationResult = cfg.validator.validateTextResponse(resp.content);
69
+ const adapter = cfg.reasoning ?? defaultAdapter;
70
+ try {
71
+ reasoningTree = adapter.extract(reasoningInput, cfg.client.modelName(), "llm-backend");
72
+ cleanContent = adapter.strip(reasoningInput);
71
73
  }
72
- else {
73
- validationResult = { toolCalls: [], nudge: null, needsRetry: false };
74
+ catch (e) {
75
+ if (e instanceof ReasoningError) {
76
+ reasoningFailed = true;
77
+ // Fail closed: never echo content that may carry reasoning we could
78
+ // not parse.
79
+ cleanContent = "";
80
+ validationResult = {
81
+ toolCalls: [],
82
+ nudge: null,
83
+ needsRetry: true,
84
+ };
85
+ }
86
+ else {
87
+ throw e;
88
+ }
74
89
  }
75
- if (!validationResult.needsRetry && validationResult.toolCalls.length > 0) {
76
- resp.tool_calls = validationResult.toolCalls.map((tc) => ({
77
- id: "",
78
- name: tc.tool,
79
- arguments: tc.args,
90
+ }
91
+ if (!reasoningFailed) {
92
+ if (resp.tool_calls && resp.tool_calls.length > 0) {
93
+ const guardrailsToolCalls = resp.tool_calls.map((tc) => ({
94
+ tool: tc.name,
95
+ args: tc.arguments,
80
96
  }));
97
+ if (cfg.validator) {
98
+ validationResult = cfg.validator.validateToolCalls(guardrailsToolCalls);
99
+ }
100
+ else {
101
+ validationResult = {
102
+ toolCalls: guardrailsToolCalls,
103
+ nudge: null,
104
+ needsRetry: false,
105
+ };
106
+ }
81
107
  }
82
- }
83
- else {
84
- if (cfg.validator) {
85
- validationResult = cfg.validator.validateTextResponse("");
108
+ else if (cleanContent) {
109
+ if (cfg.validator) {
110
+ validationResult = cfg.validator.validateTextResponse(cleanContent);
111
+ }
112
+ else {
113
+ validationResult = { toolCalls: [], nudge: null, needsRetry: false };
114
+ }
115
+ if (!validationResult.needsRetry && validationResult.toolCalls.length > 0) {
116
+ resp.tool_calls = validationResult.toolCalls.map((tc) => ({
117
+ id: "",
118
+ name: tc.tool,
119
+ arguments: tc.args,
120
+ }));
121
+ }
86
122
  }
87
123
  else {
88
- validationResult = { toolCalls: [], nudge: null, needsRetry: true };
124
+ if (cfg.validator) {
125
+ validationResult = cfg.validator.validateTextResponse("");
126
+ }
127
+ else {
128
+ validationResult = { toolCalls: [], nudge: null, needsRetry: true };
129
+ }
89
130
  }
90
131
  }
91
132
  lastResponse = resp;
@@ -114,6 +155,7 @@ export async function runInference(messages, cfg, sessionId = "") {
114
155
  newMessages: currentMessages,
115
156
  toolCallCounter,
116
157
  attempts,
158
+ reasoningTree,
117
159
  };
118
160
  }
119
161
  if (cfg.errorTracker) {
@@ -132,7 +174,7 @@ export async function runInference(messages, cfg, sessionId = "") {
132
174
  }
133
175
  const failedMsg = {
134
176
  role: Role.ASSISTANT,
135
- content: resp.content,
177
+ content: cleanContent,
136
178
  meta: { type: MessageType.TEXT_RESPONSE },
137
179
  };
138
180
  currentMessages.push(failedMsg);
@@ -0,0 +1,33 @@
1
+ import { ReasoningError } from "./errors.js";
2
+ import { ReasoningOptions } from "./options.js";
3
+ import { ContextTree } from "./types.js";
4
+ export { ReasoningError };
5
+ export declare class ReasoningAdapter {
6
+ private readonly opts;
7
+ private readonly modelFields;
8
+ constructor(options?: ReasoningOptions);
9
+ get options(): Required<ReasoningOptions>;
10
+ /** Map a model name to a model-specific reasoning field name. Fields
11
+ * registered here are consulted before the known field set. */
12
+ registerModelField(model: string, fieldName: string): void;
13
+ /** Remove reasoning from raw and return the clean content that ordinary
14
+ * tool-call parsers should see. Fails closed. */
15
+ strip(raw: unknown): string;
16
+ /** Normalize reasoning found in raw into a versioned context tree. Raw
17
+ * reasoning is never stored on the tree: nodes carry bounded summaries. */
18
+ extract(raw: unknown, model?: string, backend?: string): ContextTree;
19
+ /** Strip and extract in one call: return the clean content and tree. */
20
+ parse(raw: unknown, model?: string, backend?: string): {
21
+ clean: string;
22
+ tree: ContextTree;
23
+ };
24
+ private analyze;
25
+ private analyzeString;
26
+ private analyzeBytes;
27
+ private analyzeStructured;
28
+ private extractReasoningField;
29
+ private analyzeText;
30
+ private hasRecognizedKey;
31
+ private parseNodes;
32
+ }
33
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/reasoning/adapter.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,cAAc,EAKf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAoB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAoB,WAAW,EAAsC,MAAM,YAAY,CAAC;AAE/F,OAAO,EAAE,cAAc,EAAE,CAAC;AAmE1B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;gBAEtC,OAAO,CAAC,EAAE,gBAAgB;IAKtC,IAAI,OAAO,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAExC;IAED;mEAC+D;IAC/D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAM1D;qDACiD;IACjD,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAI3B;+EAC2E;IAC3E,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,SAAK,EAAE,OAAO,SAAK,GAAG,WAAW;IA0B5D,wEAAwE;IACxE,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,SAAK,EAAE,OAAO,SAAK,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE;IAKnF,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,qBAAqB;IAqC7B,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;CA2DnB"}