@sema-agent/core 5.8.0 → 5.9.0
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 +42 -0
- package/dist/agents/cascade.js +24 -0
- package/dist/agents/subagent.d.ts +3 -0
- package/dist/agents/subagent.js +64 -14
- package/dist/brain/open-responses.d.ts +11 -0
- package/dist/brain/open-responses.js +721 -0
- package/dist/brain/request-params.d.ts +1 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/core/fs-write-gate-policy.js +2 -2
- package/dist/core/lsp-diagnostics.d.ts +3 -2
- package/dist/core/lsp-diagnostics.js +20 -7
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +14 -7
- package/dist/core/runner/prepare-task.d.ts +1 -0
- package/dist/core/runner/prepare-task.js +7 -4
- package/dist/core/runner/runtask.js +28 -22
- package/dist/core/runner/session-rule-policy.d.ts +1 -0
- package/dist/core/runner/session-rule-policy.js +4 -3
- package/dist/core/task-registry-shared.d.ts +0 -1
- package/dist/core/tool-policy.d.ts +8 -0
- package/dist/core/tool-policy.js +11 -0
- package/dist/core/trace.d.ts +0 -2
- package/dist/core/types.d.ts +3 -0
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +3 -0
- package/dist/engine/harness/types.d.ts +1 -0
- package/dist/engine/llm/types.d.ts +2 -73
- package/dist/engine/loop/agent-loop.js +6 -6
- package/dist/engine/loop/types.d.ts +1 -0
- package/dist/engine/session/repo-utils.d.ts +1 -2
- package/dist/engine/session/repo-utils.js +0 -7
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/workflow.js +14 -5
- package/dist/tools/web.js +20 -19
- package/package.json +4 -2
|
@@ -68,15 +68,9 @@ export interface SimpleStreamOptions extends StreamOptions {
|
|
|
68
68
|
}
|
|
69
69
|
export type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (model: Model<TApi>, context: Context, options?: TOptions) => AssistantMessageEventStreamContract;
|
|
70
70
|
export type ImagesFunction<TApi extends ImagesApi = ImagesApi, TOptions extends ImagesOptions = ImagesOptions> = (model: ImagesModel<TApi>, context: ImagesContext, options?: TOptions) => Promise<AssistantImages>;
|
|
71
|
-
export interface TextSignatureV1 {
|
|
72
|
-
v: 1;
|
|
73
|
-
id: string;
|
|
74
|
-
phase?: "commentary" | "final_answer";
|
|
75
|
-
}
|
|
76
71
|
export interface TextContent {
|
|
77
72
|
type: "text";
|
|
78
73
|
text: string;
|
|
79
|
-
textSignature?: string;
|
|
80
74
|
}
|
|
81
75
|
export interface ThinkingContent {
|
|
82
76
|
type: "thinking";
|
|
@@ -99,7 +93,6 @@ export interface ToolCall {
|
|
|
99
93
|
id: string;
|
|
100
94
|
name: string;
|
|
101
95
|
arguments: Record<string, unknown>;
|
|
102
|
-
thoughtSignature?: string;
|
|
103
96
|
executionMode?: "sequential" | "parallel";
|
|
104
97
|
}
|
|
105
98
|
export interface Usage {
|
|
@@ -259,28 +252,15 @@ export interface AssistantMessageEventStreamLike extends AsyncIterable<Assistant
|
|
|
259
252
|
result(): Promise<AssistantMessage>;
|
|
260
253
|
}
|
|
261
254
|
export interface OpenAICompletionsCompat {
|
|
262
|
-
supportsStore?: boolean;
|
|
263
|
-
supportsDeveloperRole?: boolean;
|
|
264
255
|
supportsReasoningEffort?: boolean;
|
|
265
256
|
reasoningEffortLevels?: ThinkingLevel[];
|
|
266
|
-
supportsUsageInStreaming?: boolean;
|
|
267
257
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
268
|
-
requiresToolResultName?: boolean;
|
|
269
|
-
requiresAssistantAfterToolResult?: boolean;
|
|
270
|
-
requiresThinkingAsText?: boolean;
|
|
271
258
|
requiresReasoningContentOnAssistantMessages?: boolean;
|
|
272
259
|
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template";
|
|
273
|
-
openRouterRouting?: OpenRouterRouting;
|
|
274
|
-
vercelGatewayRouting?: VercelGatewayRouting;
|
|
275
|
-
zaiToolStream?: boolean;
|
|
276
|
-
supportsStrictMode?: boolean;
|
|
277
|
-
cacheControlFormat?: "anthropic";
|
|
278
|
-
sendSessionAffinityHeaders?: boolean;
|
|
279
|
-
supportsLongCacheRetention?: boolean;
|
|
280
260
|
}
|
|
281
261
|
export interface OpenAIResponsesCompat {
|
|
282
|
-
|
|
283
|
-
|
|
262
|
+
supportsReasoningEffort?: boolean;
|
|
263
|
+
reasoningEffortLevels?: ThinkingLevel[];
|
|
284
264
|
}
|
|
285
265
|
export interface AnthropicMessagesCompat {
|
|
286
266
|
thinkingMode?: "budget" | "adaptive";
|
|
@@ -288,48 +268,6 @@ export interface AnthropicMessagesCompat {
|
|
|
288
268
|
supportsTemperature?: boolean;
|
|
289
269
|
contextManagement?: boolean;
|
|
290
270
|
interleavedThinking?: boolean;
|
|
291
|
-
supportsEagerToolInputStreaming?: boolean;
|
|
292
|
-
supportsLongCacheRetention?: boolean;
|
|
293
|
-
sendSessionAffinityHeaders?: boolean;
|
|
294
|
-
supportsCacheControlOnTools?: boolean;
|
|
295
|
-
}
|
|
296
|
-
export interface OpenRouterRouting {
|
|
297
|
-
allow_fallbacks?: boolean;
|
|
298
|
-
require_parameters?: boolean;
|
|
299
|
-
data_collection?: "deny" | "allow";
|
|
300
|
-
zdr?: boolean;
|
|
301
|
-
enforce_distillable_text?: boolean;
|
|
302
|
-
order?: string[];
|
|
303
|
-
only?: string[];
|
|
304
|
-
ignore?: string[];
|
|
305
|
-
quantizations?: string[];
|
|
306
|
-
sort?: string | {
|
|
307
|
-
by?: string;
|
|
308
|
-
partition?: string | null;
|
|
309
|
-
};
|
|
310
|
-
max_price?: {
|
|
311
|
-
prompt?: number | string;
|
|
312
|
-
completion?: number | string;
|
|
313
|
-
image?: number | string;
|
|
314
|
-
audio?: number | string;
|
|
315
|
-
request?: number | string;
|
|
316
|
-
};
|
|
317
|
-
preferred_min_throughput?: number | {
|
|
318
|
-
p50?: number;
|
|
319
|
-
p75?: number;
|
|
320
|
-
p90?: number;
|
|
321
|
-
p99?: number;
|
|
322
|
-
};
|
|
323
|
-
preferred_max_latency?: number | {
|
|
324
|
-
p50?: number;
|
|
325
|
-
p75?: number;
|
|
326
|
-
p90?: number;
|
|
327
|
-
p99?: number;
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
export interface VercelGatewayRouting {
|
|
331
|
-
only?: string[];
|
|
332
|
-
order?: string[];
|
|
333
271
|
}
|
|
334
272
|
export interface Model<TApi extends Api = Api> {
|
|
335
273
|
id: string;
|
|
@@ -357,15 +295,6 @@ export interface Model<TApi extends Api = Api> {
|
|
|
357
295
|
headers?: Record<string, string>;
|
|
358
296
|
promptGuidance?: string[];
|
|
359
297
|
compat?: TApi extends "openai-completions" ? OpenAICompletionsCompat : TApi extends "openai-responses" ? OpenAIResponsesCompat : TApi extends "anthropic-messages" ? AnthropicMessagesCompat : never;
|
|
360
|
-
mediaInput?: {
|
|
361
|
-
image?: {
|
|
362
|
-
maxBytes?: number;
|
|
363
|
-
maxPixels?: number;
|
|
364
|
-
maxSidePx?: number;
|
|
365
|
-
preferredSidePx?: number;
|
|
366
|
-
tokenMode?: "tile" | "detail" | "provider";
|
|
367
|
-
};
|
|
368
|
-
};
|
|
369
298
|
}
|
|
370
299
|
export interface ImagesModel<TApi extends ImagesApi = ImagesApi> extends Omit<Model, "api" | "provider" | "reasoning" | "contextWindow" | "maxTokens" | "compat"> {
|
|
371
300
|
api: TApi;
|
|
@@ -495,7 +495,7 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
|
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
497
|
else {
|
|
498
|
-
const executed = await executePreparedToolCall(preparation, signal, emit);
|
|
498
|
+
const executed = await executePreparedToolCall(preparation, signal, emit, config.abortResultDetails);
|
|
499
499
|
finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
|
|
500
500
|
}
|
|
501
501
|
await emitToolExecutionEnd(finalized, emit);
|
|
@@ -625,7 +625,7 @@ async function executeToolCallsPartitioned(currentContext, assistantMessage, too
|
|
|
625
625
|
return { messages, terminate: shouldTerminateToolBatch(allFinalized) };
|
|
626
626
|
async function settleBatch(entries, concurrent) {
|
|
627
627
|
const runOne = (entry) => async () => {
|
|
628
|
-
const executed = await executePreparedToolCall(entry.prepared, signal, emit);
|
|
628
|
+
const executed = await executePreparedToolCall(entry.prepared, signal, emit, config.abortResultDetails);
|
|
629
629
|
const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, entry.prepared, executed, config, signal);
|
|
630
630
|
await emitToolExecutionEnd(finalized, emit);
|
|
631
631
|
return finalized;
|
|
@@ -707,7 +707,7 @@ class StreamToolExecutor {
|
|
|
707
707
|
return;
|
|
708
708
|
}
|
|
709
709
|
entry.prepared = preparation;
|
|
710
|
-
entry.executed = await executePreparedToolCall(preparation, this.signal, this.emit);
|
|
710
|
+
entry.executed = await executePreparedToolCall(preparation, this.signal, this.emit, this.config.abortResultDetails);
|
|
711
711
|
}
|
|
712
712
|
catch (error) {
|
|
713
713
|
entry.immediate = {
|
|
@@ -829,7 +829,7 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
|
|
|
829
829
|
if (signal?.aborted) {
|
|
830
830
|
return {
|
|
831
831
|
kind: "immediate",
|
|
832
|
-
result: createErrorToolResult("Operation aborted"),
|
|
832
|
+
result: createErrorToolResult("Operation aborted", { details: config.abortResultDetails?.() }),
|
|
833
833
|
isError: true,
|
|
834
834
|
};
|
|
835
835
|
}
|
|
@@ -869,11 +869,11 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
|
|
|
869
869
|
};
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
|
-
async function executePreparedToolCall(prepared, signal, emit) {
|
|
872
|
+
async function executePreparedToolCall(prepared, signal, emit, abortResultDetails) {
|
|
873
873
|
const updateEvents = [];
|
|
874
874
|
let acceptingUpdates = true;
|
|
875
875
|
if (signal?.aborted) {
|
|
876
|
-
return { result: createErrorToolResult("operation aborted before execution"), isError: true };
|
|
876
|
+
return { result: createErrorToolResult("operation aborted before execution", { details: abortResultDetails?.() }), isError: true };
|
|
877
877
|
}
|
|
878
878
|
const work = (async () => {
|
|
879
879
|
try {
|
|
@@ -85,6 +85,7 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
85
85
|
getFollowUpMessages?: () => Promise<AgentMessage[]>;
|
|
86
86
|
toolExecution?: ToolExecutionMode;
|
|
87
87
|
beforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;
|
|
88
|
+
abortResultDetails?: () => Record<string, unknown> | undefined;
|
|
88
89
|
afterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;
|
|
89
90
|
}
|
|
90
91
|
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SessionMetadata, type SessionStorage, type SessionTreeEntry } from "../harness/types.js";
|
|
2
2
|
import type { Session } from "../harness/types.js";
|
|
3
3
|
export declare function createSessionId(): string;
|
|
4
4
|
export declare function createTimestamp(): string;
|
|
5
5
|
export declare function toSession<TMetadata extends SessionMetadata>(storage: SessionStorage<TMetadata>): Session<TMetadata>;
|
|
6
|
-
export declare function getFileSystemResultOrThrow<TValue>(result: Result<TValue, FileError>, message: string): TValue;
|
|
7
6
|
export declare function getEntriesToFork(storage: SessionStorage, options: {
|
|
8
7
|
entryId?: string;
|
|
9
8
|
position?: "before" | "at";
|
|
@@ -10,13 +10,6 @@ export function createTimestamp() {
|
|
|
10
10
|
export function toSession(storage) {
|
|
11
11
|
return new StoredSession(storage);
|
|
12
12
|
}
|
|
13
|
-
export function getFileSystemResultOrThrow(result, message) {
|
|
14
|
-
if (!result.ok) {
|
|
15
|
-
const code = result.error.code === "not_found" ? "not_found" : "storage";
|
|
16
|
-
throw new SessionError(code, `${message}: ${result.error.message}`, result.error);
|
|
17
|
-
}
|
|
18
|
-
return result.value;
|
|
19
|
-
}
|
|
20
13
|
function rerootIfHeadless(storage, entries) {
|
|
21
14
|
const head = entries[0];
|
|
22
15
|
if (head === undefined || head.parentId === null)
|
package/dist/index.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export type { SchedulerCapability, SchedulerErrorCode, ScheduledIntent, Schedule
|
|
|
113
113
|
export { createSchedulerTools, type SchedulerToolContext, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
|
|
114
114
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, type AutonomousLoopPromptOptions, } from "./tools/loop-tick.js";
|
|
115
115
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
116
|
-
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, } from "./core/tool-policy.js";
|
|
116
|
+
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, } from "./core/tool-policy.js";
|
|
117
117
|
export { parseAutoModeResponse, createAutoModeDecider, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassifyFn, type AutoModeClassifyInput, } from "./core/auto-mode.js";
|
|
118
118
|
export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
|
|
119
119
|
export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
|
|
@@ -151,7 +151,7 @@ export { runSpec, type RunSpecOptions, type RunSpecResult, type RunSpecOracleRep
|
|
|
151
151
|
export { isSelfOrchestrationActive, workflowsCapability, selfOrchestrationFailClosedReason, type WorkflowScriptRunner, type WorkflowMeta, type WorkflowPrimitives, } from "./orchestration/workflow-script-runner.js";
|
|
152
152
|
export { devWorkflowScriptRunner } from "./orchestration/dev-vm-script-runner.js";
|
|
153
153
|
export { parseWorkflowMeta, splitWorkflowMeta, WorkflowScriptError, workflowScriptReadsClockOrRandom } from "./orchestration/workflow-meta.js";
|
|
154
|
-
export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring } from "./orchestration/workflow-sandbox-conformance.js";
|
|
154
|
+
export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, assertWorkflowDeterminism } from "./orchestration/workflow-sandbox-conformance.js";
|
|
155
155
|
export { WorkflowModelNotAllowedError, type WorkflowAgentSpec } from "./orchestration/workflow-governance.js";
|
|
156
156
|
export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
|
|
157
157
|
export { createFileWorkflowScriptStore, mergeWorkflowArgs, type WorkflowScriptStore, type NamedWorkflowResolution, type NamedWorkflowListing, } from "./orchestration/workflow-script-store.js";
|
|
@@ -195,6 +195,7 @@ export { createTaskServer, type TaskServerOptions, type TaskRequestBody, } from
|
|
|
195
195
|
export { clearStaleToolResults, COMPACTABLE_TOOLS, editBudget, type ContextEditOptions, } from "./core/context-edit.js";
|
|
196
196
|
export { createOpenAIBrain, type OpenAIBrainConfig } from "./brain/openai.js";
|
|
197
197
|
export { createAnthropicBrain, type AnthropicBrainConfig } from "./brain/anthropic.js";
|
|
198
|
+
export { createOpenResponsesBrain, type OpenResponsesBrainConfig } from "./brain/open-responses.js";
|
|
198
199
|
export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
|
|
199
200
|
export { createFailoverBrain } from "./brain/failover.js";
|
|
200
201
|
export { createRoutingBrain, type RoutingBrainOptions } from "./brain/routing.js";
|
package/dist/index.js
CHANGED
|
@@ -135,7 +135,7 @@ export { runSpec } from "./orchestration/run-spec.js";
|
|
|
135
135
|
export { isSelfOrchestrationActive, workflowsCapability, selfOrchestrationFailClosedReason, } from "./orchestration/workflow-script-runner.js";
|
|
136
136
|
export { devWorkflowScriptRunner } from "./orchestration/dev-vm-script-runner.js";
|
|
137
137
|
export { parseWorkflowMeta, splitWorkflowMeta, WorkflowScriptError, workflowScriptReadsClockOrRandom } from "./orchestration/workflow-meta.js";
|
|
138
|
-
export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring } from "./orchestration/workflow-sandbox-conformance.js";
|
|
138
|
+
export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, assertWorkflowDeterminism } from "./orchestration/workflow-sandbox-conformance.js";
|
|
139
139
|
export { WorkflowModelNotAllowedError } from "./orchestration/workflow-governance.js";
|
|
140
140
|
export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
|
|
141
141
|
export { createFileWorkflowScriptStore, mergeWorkflowArgs, } from "./orchestration/workflow-script-store.js";
|
|
@@ -177,6 +177,7 @@ export { createTaskServer, } from "./server/http.js";
|
|
|
177
177
|
export { clearStaleToolResults, COMPACTABLE_TOOLS, editBudget, } from "./core/context-edit.js";
|
|
178
178
|
export { createOpenAIBrain } from "./brain/openai.js";
|
|
179
179
|
export { createAnthropicBrain } from "./brain/anthropic.js";
|
|
180
|
+
export { createOpenResponsesBrain } from "./brain/open-responses.js";
|
|
180
181
|
export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
|
|
181
182
|
export { createFailoverBrain } from "./brain/failover.js";
|
|
182
183
|
export { createRoutingBrain } from "./brain/routing.js";
|
package/dist/internal/llm.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { createAssistantMessageEventStream, stripEngineMetadata } from "../engine/llm/index.js";
|
|
2
|
-
export type { AnthropicMessagesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ResilienceOptions, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, Usage, UserMessage, } from "../engine/llm/index.js";
|
|
2
|
+
export type { AnthropicMessagesCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ResilienceOptions, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, Usage, UserMessage, } from "../engine/llm/index.js";
|
|
@@ -222,6 +222,14 @@ function normalizeWorkflowHardCap(name, v) {
|
|
|
222
222
|
}
|
|
223
223
|
return v;
|
|
224
224
|
}
|
|
225
|
+
function normalizeWorkflowStallMs(v) {
|
|
226
|
+
if (v === undefined)
|
|
227
|
+
return WORKFLOW_AGENT_STALL_MS;
|
|
228
|
+
if (!Number.isFinite(v)) {
|
|
229
|
+
throw new Error(`runWorkflow: stallMs must be a finite number of milliseconds (got ${v}); 0 or a negative value is the documented explicit "off", not NaN/Infinity`);
|
|
230
|
+
}
|
|
231
|
+
return v;
|
|
232
|
+
}
|
|
225
233
|
function createSemaphore(max) {
|
|
226
234
|
let active = 0;
|
|
227
235
|
const waiters = [];
|
|
@@ -307,12 +315,13 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
307
315
|
const maxAgents = normalizeWorkflowHardCap("maxAgents", opts.maxAgents);
|
|
308
316
|
const maxLogChars = normalizeWorkflowHardCap("maxLogChars", opts.maxLogChars);
|
|
309
317
|
const maxResultChars = normalizeWorkflowHardCap("maxResultChars", opts.maxResultChars);
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
const
|
|
318
|
+
const totalTimeoutMs = normalizeWorkflowHardCap("totalTimeoutMs", opts.totalTimeoutMs);
|
|
319
|
+
const stallMs = normalizeWorkflowStallMs(opts.stallMs);
|
|
320
|
+
const agentMaxRetries = normalizeWorkflowHardCap("agentMaxRetries", opts.agentMaxRetries) ?? WORKFLOW_AGENT_MAX_RETRIES;
|
|
321
|
+
const throttleBackoffMs = normalizeWorkflowHardCap("throttleBackoffMs", opts.throttleBackoffMs) ?? WORKFLOW_AGENT_THROTTLE_BACKOFF_MS;
|
|
313
322
|
const timers = opts.timers ?? REAL_WORKFLOW_TIMERS;
|
|
314
323
|
const cancelController = new AbortController();
|
|
315
|
-
const timeoutController =
|
|
324
|
+
const timeoutController = totalTimeoutMs !== undefined ? new AbortController() : undefined;
|
|
316
325
|
const signalSources = [cancelController.signal];
|
|
317
326
|
if (opts.signal)
|
|
318
327
|
signalSources.push(opts.signal);
|
|
@@ -375,7 +384,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
375
384
|
};
|
|
376
385
|
markWorkflowActive(runId, scope);
|
|
377
386
|
if (timeoutController) {
|
|
378
|
-
timeoutTimer = setTimeout(() => timeoutController.abort(new Error("workflow total timeout")),
|
|
387
|
+
timeoutTimer = setTimeout(() => timeoutController.abort(new Error("workflow total timeout")), totalTimeoutMs);
|
|
379
388
|
timeoutTimer.unref?.();
|
|
380
389
|
}
|
|
381
390
|
emit({ type: "run_start", runId, scope, ts: t0 });
|
package/dist/tools/web.js
CHANGED
|
@@ -3,11 +3,28 @@ import { defineTool, errorResult } from "../core/tools.js";
|
|
|
3
3
|
import { delimitUntrusted, inlineUntrusted } from "../core/untrusted-text.js";
|
|
4
4
|
import { redactSecrets } from "../core/untrusted-egress.js";
|
|
5
5
|
import { isPrivateHost } from "../core/runner/image.js";
|
|
6
|
+
import { binaryMagicFormat } from "./fs/safety.js";
|
|
7
|
+
import { pdfMagicMatches } from "./fs/pdf.js";
|
|
6
8
|
const MAX_REDIRECTS = 10;
|
|
7
9
|
const MAX_URL_LENGTH = 2048;
|
|
8
10
|
const WEBFETCH_ACCEPT = "text/markdown, text/html, */*";
|
|
9
11
|
const DEFAULT_WEBFETCH_USER_AGENT = "Sema-User (@sema-agent/core WebFetch)";
|
|
10
12
|
const DEFAULT_MAX_BYTES = 2 * 1024 * 1024;
|
|
13
|
+
function resolveWebMaxBytes(value) {
|
|
14
|
+
if (value === undefined)
|
|
15
|
+
return DEFAULT_MAX_BYTES;
|
|
16
|
+
if (value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY) {
|
|
17
|
+
const e = new Error(`WebFetch maxBytes cannot be ${value === Number.POSITIVE_INFINITY ? "Infinity" : "-Infinity"} — the byte cap cannot be turned off, only widened; pass a large finite value instead (got ${String(value)})`);
|
|
18
|
+
e.code = "config.web_max_bytes_invalid";
|
|
19
|
+
throw e;
|
|
20
|
+
}
|
|
21
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
22
|
+
const e = new Error(`WebFetch maxBytes must be a positive finite number of bytes (got ${String(value)})`);
|
|
23
|
+
e.code = "config.web_max_bytes_invalid";
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
11
28
|
const DEFAULT_FETCH_TIMEOUT_MS = 30_000;
|
|
12
29
|
const ERROR_BODY_EXCERPT_CHARS = 2048;
|
|
13
30
|
const ERROR_BODY_CONVERT_MAX_CHARS = 64 * 1024;
|
|
@@ -126,25 +143,9 @@ function isBinaryContentType(contentType) {
|
|
|
126
143
|
return true;
|
|
127
144
|
}
|
|
128
145
|
function sniffBinarySignature(b) {
|
|
129
|
-
|
|
130
|
-
const ascii = (str, off = 0) => [...str].every((ch, i) => at(off + i) === ch.charCodeAt(0));
|
|
131
|
-
if (ascii("%PDF"))
|
|
146
|
+
if (pdfMagicMatches(b))
|
|
132
147
|
return "PDF";
|
|
133
|
-
|
|
134
|
-
return "PNG";
|
|
135
|
-
if (at(0) === 0xff && at(1) === 0xd8 && at(2) === 0xff)
|
|
136
|
-
return "JPEG";
|
|
137
|
-
if (ascii("GIF8"))
|
|
138
|
-
return "GIF";
|
|
139
|
-
if (at(0) === 0x1f && at(1) === 0x8b)
|
|
140
|
-
return "gzip";
|
|
141
|
-
if (ascii("PK") && ((at(2) === 3 && at(3) === 4) || (at(2) === 5 && at(3) === 6)))
|
|
142
|
-
return "zip";
|
|
143
|
-
if (at(0) === 0x7f && ascii("ELF", 1))
|
|
144
|
-
return "ELF binary";
|
|
145
|
-
if (at(0) === 0x00 && ascii("asm", 1))
|
|
146
|
-
return "WebAssembly";
|
|
147
|
-
return undefined;
|
|
148
|
+
return binaryMagicFormat(b);
|
|
148
149
|
}
|
|
149
150
|
function isPermittedRedirectHop(from, to) {
|
|
150
151
|
const upgrade = from.protocol === "http:" && to.protocol === "https:";
|
|
@@ -209,7 +210,7 @@ async function fetchAllowlisted(doFetch, start, allowHosts, userAgent, signal, o
|
|
|
209
210
|
return { ok: false, error: "too many redirects" };
|
|
210
211
|
}
|
|
211
212
|
export function webFetchToolSpec(config = {}) {
|
|
212
|
-
const maxBytes = config.maxBytes
|
|
213
|
+
const maxBytes = resolveWebMaxBytes(config.maxBytes);
|
|
213
214
|
const doFetch = config.fetchImpl ?? globalThis.fetch;
|
|
214
215
|
const canSummarize = config.summarize !== undefined;
|
|
215
216
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"gate:message-branching": "node scripts/verify-no-message-branching.mjs",
|
|
62
62
|
"gate:failloud": "node scripts/verify-failloud.mjs",
|
|
63
63
|
"gate:domain-lexicon": "node scripts/verify-domain-lexicon.mjs",
|
|
64
|
-
"gate:single-mint": "node scripts/verify-single-mint.mjs"
|
|
64
|
+
"gate:single-mint": "node scripts/verify-single-mint.mjs",
|
|
65
|
+
"gate:nuia": "node scripts/verify-nuia-baseline.mjs",
|
|
66
|
+
"gate:field-liveness": "node scripts/verify-field-liveness.mjs"
|
|
65
67
|
},
|
|
66
68
|
"dependencies": {
|
|
67
69
|
"@modelcontextprotocol/sdk": "1.30.0",
|