@zhivex-ai/core 1.16.1 → 1.18.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/dist/agent-evaluation.d.ts.map +1 -1
- package/dist/agent-evaluation.js +2 -0
- package/dist/agent-evaluation.js.map +1 -1
- package/dist/agent-reconciliation.d.ts +12 -0
- package/dist/agent-reconciliation.d.ts.map +1 -0
- package/dist/agent-reconciliation.js +87 -0
- package/dist/agent-reconciliation.js.map +1 -0
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +34 -0
- package/dist/agent-state.js.map +1 -1
- package/dist/agent-store.d.ts.map +1 -1
- package/dist/agent-store.js +110 -62
- package/dist/agent-store.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +82 -17
- package/dist/agent.js.map +1 -1
- package/dist/api-stability.d.ts.map +1 -1
- package/dist/api-stability.js +2 -0
- package/dist/api-stability.js.map +1 -1
- package/dist/generate-text.d.ts.map +1 -1
- package/dist/generate-text.js +39 -0
- package/dist/generate-text.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model-cost.d.ts +36 -0
- package/dist/model-cost.d.ts.map +1 -0
- package/dist/model-cost.js +89 -0
- package/dist/model-cost.js.map +1 -0
- package/dist/types.d.ts +45 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { refreshAgentTaskOutcome } from "./agent-reconciliation.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { createAgentApprovalMessage, getAgentApprovalRequests } from "./agent-approval.js";
|
|
3
4
|
import { createAgentHandoffMessage } from "./agent-handoff-contracts.js";
|
|
@@ -113,6 +114,7 @@ const cloneMetadata = (...values) => {
|
|
|
113
114
|
};
|
|
114
115
|
const toOutput = (state) => ({
|
|
115
116
|
status: state.status,
|
|
117
|
+
taskOutcome: state.taskOutcome,
|
|
116
118
|
outputText: state.outputText,
|
|
117
119
|
finalOutput: state.status === "completed" && state.finalOutput !== undefined
|
|
118
120
|
? state.finalOutput
|
|
@@ -637,19 +639,19 @@ export const createSubAgentTool = (options) => {
|
|
|
637
639
|
}
|
|
638
640
|
};
|
|
639
641
|
};
|
|
640
|
-
const saveStateWithRevision = async (store, state) => {
|
|
642
|
+
const saveStateWithRevision = async (store, state, serializedNextState) => {
|
|
641
643
|
const expectedRevision = state.revision ?? 0;
|
|
642
644
|
const nextRevision = expectedRevision + 1;
|
|
643
645
|
const nextState = { ...state, revision: nextRevision };
|
|
644
|
-
await store.save(cloneState(nextState), { expectedRevision });
|
|
646
|
+
await store.save(serializedNextState === undefined ? cloneState(nextState) : JSON.parse(serializedNextState), { expectedRevision });
|
|
645
647
|
state.revision = nextRevision;
|
|
646
648
|
};
|
|
647
649
|
const claimAgentExecution = async (agent, state) => {
|
|
648
650
|
state.status = "running";
|
|
649
651
|
state.updatedAt = Date.now();
|
|
650
|
-
assertStateSize(agent, state);
|
|
652
|
+
const serialized = assertStateSize(agent, agent.store ? normalizeAgentRunState({ ...state, revision: (state.revision ?? 0) + 1 }) : state);
|
|
651
653
|
if (agent.store) {
|
|
652
|
-
await saveStateWithRevision(agent.store, state);
|
|
654
|
+
await saveStateWithRevision(agent.store, state, serialized);
|
|
653
655
|
}
|
|
654
656
|
};
|
|
655
657
|
const assertStateSize = (agent, state, policy) => {
|
|
@@ -657,16 +659,19 @@ const assertStateSize = (agent, state, policy) => {
|
|
|
657
659
|
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
658
660
|
throw new ValidationError('Agent policy "maxStateBytes" must be a positive integer.');
|
|
659
661
|
}
|
|
660
|
-
const
|
|
662
|
+
const serialized = JSON.stringify(state);
|
|
663
|
+
const bytes = new TextEncoder().encode(serialized).byteLength;
|
|
661
664
|
if (bytes > limit) {
|
|
662
665
|
throw new ValidationError(`Agent run state is ${bytes} bytes and exceeds maxStateBytes=${limit}. Offload large tool outputs to artifacts or raise the explicit limit.`);
|
|
663
666
|
}
|
|
667
|
+
return serialized;
|
|
664
668
|
};
|
|
665
669
|
const persistState = async (agent, state, policy) => {
|
|
666
670
|
state.updatedAt = Date.now();
|
|
667
|
-
|
|
671
|
+
await refreshAgentTaskOutcome(state, agent.store);
|
|
672
|
+
const serialized = assertStateSize(agent, agent.store ? normalizeAgentRunState({ ...state, revision: (state.revision ?? 0) + 1 }) : state, policy);
|
|
668
673
|
if (agent.store) {
|
|
669
|
-
await saveStateWithRevision(agent.store, state);
|
|
674
|
+
await saveStateWithRevision(agent.store, state, serialized);
|
|
670
675
|
}
|
|
671
676
|
await emitTelemetryEvent(agent, {
|
|
672
677
|
type: "state-saved",
|
|
@@ -848,6 +853,11 @@ const resolveContext = async (agent, input) => {
|
|
|
848
853
|
ensureValidStateInput(normalizedInput);
|
|
849
854
|
const metadata = cloneMetadata(agent.metadata, loadedState?.metadata, input.metadata, input.handoff?.metadata);
|
|
850
855
|
if (loadedState) {
|
|
856
|
+
const groupIdentity = input.metadata?.agentGroupIdentity;
|
|
857
|
+
if (groupIdentity !== undefined && (loadedState.metadata?.agentGroupIdentity !== groupIdentity ||
|
|
858
|
+
loadedState.agentId !== agent.id)) {
|
|
859
|
+
throw new ConflictError("Agent group idempotency key belongs to a different member or agent.");
|
|
860
|
+
}
|
|
851
861
|
bindDurableRuntime(agent, input, loadedState, executionEnvironmentBinding);
|
|
852
862
|
const maxSteps = input.maxSteps ?? loadedState.maxSteps;
|
|
853
863
|
const resumed = await applyApprovalResponses(loadedState.messages, input.approvals, loadedState.pendingApprovals, loadedState.approvalHistory, agent.toolApprovalSigner);
|
|
@@ -967,6 +977,9 @@ const wrapToolWithJournal = (agent, state, tool) => {
|
|
|
967
977
|
throw new ValidationError(`Durable tool "${tool.name}" requires an execution context.`);
|
|
968
978
|
}
|
|
969
979
|
const serializedInput = serializeJsonValue(input);
|
|
980
|
+
const confirmed = state.reconciliations?.find(record => record.evidence.toolName === tool.name && canonicalJson(record.evidence.input) === canonicalJson(serializedInput));
|
|
981
|
+
if (confirmed)
|
|
982
|
+
return confirmed.evidence.output;
|
|
970
983
|
const step = context.step;
|
|
971
984
|
const toolCallId = durableToolCallId(state.runId, step, context.toolCall.id, tool.name, serializedInput);
|
|
972
985
|
const idempotencyKey = `${state.runId}:${toolCallId}`;
|
|
@@ -975,6 +988,7 @@ const wrapToolWithJournal = (agent, state, tool) => {
|
|
|
975
988
|
runId: state.runId,
|
|
976
989
|
scope: state.scope,
|
|
977
990
|
toolCallId,
|
|
991
|
+
providerToolCallId: context.toolCall.id,
|
|
978
992
|
toolName: tool.name,
|
|
979
993
|
status: "pending",
|
|
980
994
|
idempotencyKey,
|
|
@@ -1255,7 +1269,7 @@ const createGenerateOptions = (agent, state, input, messages, maxSteps, context,
|
|
|
1255
1269
|
].filter((value) => value !== undefined);
|
|
1256
1270
|
const maxTokens = tokenCeilings.length ? Math.min(...tokenCeilings) : undefined;
|
|
1257
1271
|
const requestedToolExecution = input.toolExecution ?? agent.toolExecution;
|
|
1258
|
-
const toolExecution = agent.subagents?.length
|
|
1272
|
+
const toolExecution = agent.subagents?.length && !(requestedToolExecution?.parallel && requestedToolExecution.independentOnly)
|
|
1259
1273
|
? {
|
|
1260
1274
|
...requestedToolExecution,
|
|
1261
1275
|
parallel: false,
|
|
@@ -1850,7 +1864,39 @@ export const prepareSubagentsForAgent = (agent, options = {}) => {
|
|
|
1850
1864
|
};
|
|
1851
1865
|
};
|
|
1852
1866
|
export const runAgentGroup = async (agents, input = {}) => {
|
|
1853
|
-
const { stopOnError, runId: _runId, state: _state, approvals: _approvals, handoff: _handoff, ...sharedInput } = input;
|
|
1867
|
+
const { stopOnError, maxConcurrency, runId: _runId, state: _state, approvals: _approvals, handoff: _handoff, ...sharedInput } = input;
|
|
1868
|
+
if (maxConcurrency !== undefined && (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1)) {
|
|
1869
|
+
throw new ValidationError('Agent group "maxConcurrency" must be a positive safe integer.');
|
|
1870
|
+
}
|
|
1871
|
+
// Validate the complete group before any member can claim a key or invoke a model.
|
|
1872
|
+
const identities = new Set();
|
|
1873
|
+
const claims = [];
|
|
1874
|
+
const memberInputs = agents.map((member) => {
|
|
1875
|
+
const merged = { ...sharedInput, ...member.input };
|
|
1876
|
+
ensureValidScope(merged.scope);
|
|
1877
|
+
ensureValidIdempotencyInput(merged, member.agent.store);
|
|
1878
|
+
if (!merged.idempotencyKey)
|
|
1879
|
+
return merged;
|
|
1880
|
+
const identity = member.name ?? member.agent.id;
|
|
1881
|
+
if (!identity || identities.has(identity)) {
|
|
1882
|
+
throw new ValidationError("Idempotent agent group members require unique names or agent IDs.");
|
|
1883
|
+
}
|
|
1884
|
+
identities.add(identity);
|
|
1885
|
+
const key = member.input?.idempotencyKey ?? `agent-group:${JSON.stringify([input.idempotencyKey, identity])}`;
|
|
1886
|
+
const scope = merged.scope;
|
|
1887
|
+
const scopedKey = JSON.stringify([scope?.namespace ?? "default", scope?.tenantId, scope?.userId, key]);
|
|
1888
|
+
if (claims.some((claim) => claim.store === member.agent.store && claim.key === scopedKey)) {
|
|
1889
|
+
throw new ConflictError("Agent group members cannot share an explicit idempotency key in the same store and scope.");
|
|
1890
|
+
}
|
|
1891
|
+
claims.push({ store: member.agent.store, key: scopedKey });
|
|
1892
|
+
return {
|
|
1893
|
+
...merged,
|
|
1894
|
+
idempotencyKey: key,
|
|
1895
|
+
metadata: cloneMetadata(input.metadata, member.input?.metadata, {
|
|
1896
|
+
agentGroupIdentity: JSON.stringify([input.idempotencyKey ?? null, identity])
|
|
1897
|
+
})
|
|
1898
|
+
};
|
|
1899
|
+
});
|
|
1854
1900
|
const parentRunId = input.parentRunId;
|
|
1855
1901
|
const controllers = agents.map(() => new AbortController());
|
|
1856
1902
|
let failFastTriggered = false;
|
|
@@ -1866,15 +1912,17 @@ export const runAgentGroup = async (agents, input = {}) => {
|
|
|
1866
1912
|
}
|
|
1867
1913
|
});
|
|
1868
1914
|
};
|
|
1869
|
-
const
|
|
1915
|
+
const runMember = async (member, index) => {
|
|
1870
1916
|
const merged = createMergedAbortSignal(input.abortSignal, member.input?.abortSignal, controllers[index].signal);
|
|
1871
1917
|
try {
|
|
1918
|
+
if (merged.signal?.aborted) {
|
|
1919
|
+
throw new DOMException("Agent group member aborted before execution.", "AbortError");
|
|
1920
|
+
}
|
|
1872
1921
|
const runInput = {
|
|
1873
|
-
...
|
|
1874
|
-
...(member.input ?? {}),
|
|
1922
|
+
...memberInputs[index],
|
|
1875
1923
|
parentRunId: member.input?.parentRunId ?? parentRunId,
|
|
1876
1924
|
abortSignal: merged.signal,
|
|
1877
|
-
metadata: cloneMetadata(input.metadata,
|
|
1925
|
+
metadata: cloneMetadata(input.metadata, memberInputs[index]?.metadata, {
|
|
1878
1926
|
...(member.name ? { agentGroupMember: member.name } : {})
|
|
1879
1927
|
})
|
|
1880
1928
|
};
|
|
@@ -1891,8 +1939,20 @@ export const runAgentGroup = async (agents, input = {}) => {
|
|
|
1891
1939
|
finally {
|
|
1892
1940
|
merged.cleanup();
|
|
1893
1941
|
}
|
|
1894
|
-
}
|
|
1895
|
-
const settled =
|
|
1942
|
+
};
|
|
1943
|
+
const settled = new Array(agents.length);
|
|
1944
|
+
let nextIndex = 0;
|
|
1945
|
+
await Promise.all(Array.from({ length: Math.min(maxConcurrency ?? agents.length, agents.length) }, async () => {
|
|
1946
|
+
while (nextIndex < agents.length) {
|
|
1947
|
+
const index = nextIndex++;
|
|
1948
|
+
try {
|
|
1949
|
+
settled[index] = { status: "fulfilled", value: await runMember(agents[index], index) };
|
|
1950
|
+
}
|
|
1951
|
+
catch (reason) {
|
|
1952
|
+
settled[index] = { status: "rejected", reason };
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}));
|
|
1896
1956
|
const outputs = settled.map((result, index) => {
|
|
1897
1957
|
const member = agents[index];
|
|
1898
1958
|
if (result.status === "fulfilled") {
|
|
@@ -1916,9 +1976,12 @@ export const runAgentGroup = async (agents, input = {}) => {
|
|
|
1916
1976
|
}
|
|
1917
1977
|
};
|
|
1918
1978
|
});
|
|
1919
|
-
const
|
|
1979
|
+
const precedence = [
|
|
1980
|
+
"failed", "timed_out", "cancel_requested", "running", "queued", "waiting_approval", "suspended", "cancelled", "completed"
|
|
1981
|
+
];
|
|
1982
|
+
const status = precedence.find((status) => outputs.some((output) => output.status === "rejected" ? status === "failed" : output.output?.status === status)) ?? "completed";
|
|
1920
1983
|
return {
|
|
1921
|
-
status
|
|
1984
|
+
status,
|
|
1922
1985
|
parentRunId,
|
|
1923
1986
|
outputs
|
|
1924
1987
|
};
|
|
@@ -2125,6 +2188,7 @@ export const runAgent = async (agent, input = {}) => {
|
|
|
2125
2188
|
...approvalsFromEvents(newSteps.flatMap((step) => step.response?.messages ?? []))
|
|
2126
2189
|
]);
|
|
2127
2190
|
await persistState(agent, output.state, policy);
|
|
2191
|
+
output.taskOutcome = output.state.taskOutcome;
|
|
2128
2192
|
await emitRunFinishTelemetry(agent, output.state);
|
|
2129
2193
|
executionEnvironmentStatus = output.status;
|
|
2130
2194
|
return returnInvocationOutput(output);
|
|
@@ -2456,6 +2520,7 @@ export const streamAgent = (agent, input = {}) => {
|
|
|
2456
2520
|
await emitApprovalTelemetry(agent, result.state, approvalsFromEvents(newSteps.flatMap((step) => step.response?.messages ?? [])));
|
|
2457
2521
|
}
|
|
2458
2522
|
await persistState(agent, result.state, policy);
|
|
2523
|
+
result.taskOutcome = result.state.taskOutcome;
|
|
2459
2524
|
await emitRunFinishTelemetry(agent, result.state);
|
|
2460
2525
|
await publish({
|
|
2461
2526
|
type: "agent-run-finish",
|