@gea-ai/agent-sdk 0.1.261020-alpha.0 → 0.1.261021-alpha.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.
@@ -23,6 +23,7 @@ const sessionSchema = z
23
23
  })
24
24
  .nullable();
25
25
  const receiptSchema = z.object({
26
+ queued: z.boolean().default(false),
26
27
  runId: z.uuid(),
27
28
  inputId: z.string().min(1),
28
29
  conversationId: z.string(),
@@ -231,6 +231,7 @@ export async function handleCustomChannelAddressRequest(request, storage, enviro
231
231
  });
232
232
  return json({
233
233
  conversationId: config.address.providerLocalKey,
234
+ queued: receipt.queued,
234
235
  duplicate: receipt.duplicate,
235
236
  executionTarget: receipt.executionTarget,
236
237
  operationId: operation.input.operationId,
@@ -1185,6 +1185,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
1185
1185
  return Response.json({ error: "input_not_found" }, { status: 404 });
1186
1186
  const accepted = agentSessionEnqueueSchema.parse(stored);
1187
1187
  return Response.json(agentSessionEnqueueReceiptSchema.parse({
1188
+ ...(await tx.get(`inbox:admission:${id}`)),
1188
1189
  id,
1189
1190
  runId: accepted.runId,
1190
1191
  executionTarget: accepted.executionTarget,
@@ -1212,6 +1213,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
1212
1213
  canonicalAgentChannelJson(input))
1213
1214
  return Response.json({ error: "message_identity_conflict" }, { status: 409 });
1214
1215
  return Response.json(agentSessionEnqueueReceiptSchema.parse({
1216
+ ...(await tx.get(`inbox:admission:${accepted.message.id}`)),
1215
1217
  id: accepted.message.id,
1216
1218
  runId: accepted.runId,
1217
1219
  executionTarget: accepted.executionTarget,
@@ -1227,8 +1229,37 @@ export async function handleAgentSessionInboxRequest(request, storage) {
1227
1229
  (await tx.get(`inbox:message:${input.message.id}`)) !== undefined)
1228
1230
  return Response.json({ error: "message_identity_conflict" }, { status: 409 });
1229
1231
  if (state.messages.length >= 128 ||
1230
- new TextEncoder().encode(JSON.stringify(state) + JSON.stringify(input)).byteLength > 2_000_000)
1231
- return Response.json({ error: "inbox_full" }, { status: 429 });
1232
+ new TextEncoder().encode(JSON.stringify(state) + JSON.stringify(input)).byteLength > 2_000_000) {
1233
+ if (!input.channel)
1234
+ return Response.json({ error: "inbox_full" }, { status: 429 });
1235
+ // Freeze Channel rejection before any ACK/feedback. Replays must never
1236
+ // become accepted after capacity frees, even if this response is lost.
1237
+ // A first input can exceed the byte bound before an inbox exists.
1238
+ await writeState(tx, state);
1239
+ await putSessionPayload(tx, key, input);
1240
+ await tx.put(`inbox:admission:${input.message.id}`, {
1241
+ queued: false,
1242
+ rejected: true,
1243
+ });
1244
+ return Response.json(agentSessionEnqueueReceiptSchema.parse({
1245
+ id: input.message.id,
1246
+ runId: input.runId,
1247
+ executionTarget: input.executionTarget,
1248
+ duplicate: false,
1249
+ queued: false,
1250
+ rejected: true,
1251
+ }));
1252
+ }
1253
+ const requiresQueue = Boolean(state.messages.length ||
1254
+ state.execution ||
1255
+ state.wait ||
1256
+ state.inputWait ||
1257
+ state.draining ||
1258
+ state.terminal ||
1259
+ state.queuePaused);
1260
+ await tx.put(`inbox:admission:${input.message.id}`, {
1261
+ queued: requiresQueue,
1262
+ });
1232
1263
  const message = {
1233
1264
  ...input.message,
1234
1265
  runId: input.runId,
@@ -1240,6 +1271,7 @@ export async function handleAgentSessionInboxRequest(request, storage) {
1240
1271
  await tx.put(`inbox:enqueue-run:${input.runId}`, message.id);
1241
1272
  await save(tx, state, runs);
1242
1273
  return Response.json(agentSessionEnqueueReceiptSchema.parse({
1274
+ queued: requiresQueue,
1243
1275
  id: message.id,
1244
1276
  runId: input.runId,
1245
1277
  executionTarget: input.executionTarget,
@@ -1,3 +1,4 @@
1
+ import { recordModelRequest, recordModelSkills } from "./model-diagnostics.js";
1
2
  import { agentModelTerminationSchema, } from "@gea-ai/contract/agent-usage";
2
3
  export { uploadChannelInput } from "./agent-channel-api.js";
3
4
  import { createChannelSessionNamespace } from "./agent-channel-session-transport.js";
@@ -3406,6 +3407,7 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
3406
3407
  }
3407
3408
  input = { ...input, bindings: { ...scopedBindings, computer } };
3408
3409
  }
3410
+ await recordModelSkills(input.skillMount?.files ?? []);
3409
3411
  const skillTool = createAgentSkillTool({
3410
3412
  files: input.skillMount?.files ?? [],
3411
3413
  mountedRoot: mountedSkillRoot,
@@ -4291,8 +4293,14 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
4291
4293
  let failure;
4292
4294
  const executionErrorText = (error, fallback = "Agent execution failed.") => {
4293
4295
  const original = failure?.error ?? error;
4294
- return original instanceof AgentMediaReadError
4295
- ? original.message
4296
+ if (original instanceof AgentMediaReadError)
4297
+ return original.message;
4298
+ // Copy only the opaque Host correlation ID across the masked UI boundary.
4299
+ const diagnosticId = original instanceof Error
4300
+ ? /Diagnostic ID: ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i.exec(original.message)?.[1]
4301
+ : undefined;
4302
+ return diagnosticId
4303
+ ? `${fallback} Diagnostic ID: ${diagnosticId}`
4296
4304
  : fallback;
4297
4305
  };
4298
4306
  let executionDiagnostics;
@@ -4778,6 +4786,7 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
4778
4786
  onError: engine.onError,
4779
4787
  async fetch(request, init) {
4780
4788
  const startedAt = performance.now();
4789
+ await recordModelRequest(init?.body, coreConnection.provider.format, modelSpan);
4781
4790
  const response = await coreConnection.fetch(request, init);
4782
4791
  modelSpan?.setAttributes({
4783
4792
  "gea.model.protocol": coreConnection.provider.format,
@@ -1,3 +1,4 @@
1
+ import { recordModelRequest } from "./model-diagnostics.js";
1
2
  import { moveOpenAICompatibleCacheControlToMessageContent } from "./openai-compatible-cache-control.js";
2
3
  export { moveOpenAICompatibleCacheControlToMessageContent } from "./openai-compatible-cache-control.js";
3
4
  import { createAnthropic } from "@ai-sdk/anthropic";
@@ -125,6 +126,7 @@ export function createCatalogLanguageModel(config) {
125
126
  headers.delete("authorization");
126
127
  headers.delete("x-api-key");
127
128
  headers.set(config.auth === "bearer" ? "authorization" : "x-api-key", config.auth === "bearer" ? `Bearer ${config.apiKey}` : config.apiKey);
129
+ await recordModelRequest(body, config.format);
128
130
  return config.fetch(input, {
129
131
  ...init,
130
132
  headers,
@@ -21,6 +21,7 @@ declare const ChannelInputError_base: import("better-result").TaggedErrorClass<"
21
21
  export declare class ChannelInputError extends ChannelInputError_base {
22
22
  }
23
23
  export type ChannelSendReceipt = {
24
+ queued: boolean;
24
25
  runId: string;
25
26
  inputId: string;
26
27
  conversationId: string;
@@ -1,3 +1,4 @@
1
+ import { recordModelRequest } from "./model-diagnostics.js";
1
2
  import { SpanStatusCode, trace } from "@opentelemetry/api";
2
3
  import { AgentCoreError, createAgentCore, runAgentCore, } from "./experimental/agent-core.js";
3
4
  import { fromModelMessages, toModelMessages, } from "./experimental/agent-core-messages.js";
@@ -40,7 +41,10 @@ export async function runJudgeCore(input) {
40
41
  });
41
42
  const turn = runAgentCore(core, { type: "start" }, {
42
43
  ...tools,
43
- fetch: connection.fetch,
44
+ async fetch(request, init) {
45
+ await recordModelRequest(init?.body, connection.provider.format, modelSpan);
46
+ return connection.fetch(request, init);
47
+ },
44
48
  async prepareStep(value) {
45
49
  step = value.step;
46
50
  input.onStep(step);
@@ -0,0 +1,14 @@
1
+ import { type Span } from "@opentelemetry/api";
2
+ export declare const modelDiagnosticContext: symbol;
3
+ export type ModelDiagnosticContext = {
4
+ skillsSha256?: string;
5
+ };
6
+ /** Sort object keys recursively; preserve array order (including anyOf/ref lists). */
7
+ export declare function canonicalHash(value: unknown): Promise<string>;
8
+ export declare function recordModelSkills(files: ReadonlyArray<{
9
+ path: string;
10
+ dataBase64: string;
11
+ }>): Promise<void>;
12
+ /** Called after codec/default merging, immediately before transport. Never retain
13
+ * headers, endpoints, user messages, schema text, or arbitrary provider options. */
14
+ export declare function recordModelRequest(body: unknown, format: string, span?: Span | undefined): Promise<void>;
@@ -0,0 +1,117 @@
1
+ import { context, createContextKey, trace, } from "@opentelemetry/api";
2
+ import { z } from "zod";
3
+ export const modelDiagnosticContext = createContextKey("gea model diagnostics");
4
+ /** Sort object keys recursively; preserve array order (including anyOf/ref lists). */
5
+ export async function canonicalHash(value) {
6
+ const serialized = JSON.stringify(value, (_key, entry) => {
7
+ if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) {
8
+ return Object.fromEntries(Object.entries(entry).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
9
+ }
10
+ return entry;
11
+ });
12
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(serialized));
13
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
14
+ }
15
+ export async function recordModelSkills(files) {
16
+ const scope = context.active().getValue(modelDiagnosticContext);
17
+ if (scope)
18
+ scope.skillsSha256 = await canonicalHash([...files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
19
+ }
20
+ const wireTool = z.object({
21
+ type: z.string().optional(),
22
+ name: z.string().optional(),
23
+ parameters: z.json().optional(),
24
+ input_schema: z.json().optional(),
25
+ strict: z.boolean().nullable().optional(),
26
+ function: z
27
+ .object({
28
+ name: z.string(),
29
+ parameters: z.json().optional(),
30
+ strict: z.boolean().nullable().optional(),
31
+ })
32
+ .optional(),
33
+ });
34
+ const wireRequest = z.object({
35
+ model: z.string().optional(),
36
+ tools: z.array(wireTool).optional(),
37
+ tool_choice: z
38
+ .union([
39
+ z.enum(["auto", "none", "required"]),
40
+ z.object({
41
+ type: z.string().max(64),
42
+ name: z.string().max(256).optional(),
43
+ function: z.object({ name: z.string().max(256) }).optional(),
44
+ disable_parallel_tool_use: z.boolean().optional(),
45
+ }),
46
+ ])
47
+ .optional(),
48
+ system: z.json().optional(),
49
+ instructions: z.json().optional(),
50
+ messages: z
51
+ .array(z.object({ role: z.string(), content: z.json().optional() }))
52
+ .optional(),
53
+ input: z
54
+ .union([
55
+ z.string(),
56
+ z.array(z
57
+ .object({ role: z.string().optional(), content: z.json().optional() })
58
+ .passthrough()),
59
+ ])
60
+ .optional(),
61
+ temperature: z.number().nullable().optional(),
62
+ top_p: z.number().nullable().optional(),
63
+ max_tokens: z.number().optional(),
64
+ max_completion_tokens: z.number().optional(),
65
+ max_output_tokens: z.number().optional(),
66
+ parallel_tool_calls: z.boolean().optional(),
67
+ stream: z.boolean().optional(),
68
+ reasoning_effort: z.string().optional(),
69
+ reasoning: z.object({ effort: z.string().optional() }).optional(),
70
+ thinking: z
71
+ .object({
72
+ type: z.string().optional(),
73
+ budget_tokens: z.number().optional(),
74
+ })
75
+ .optional(),
76
+ });
77
+ /** Called after codec/default merging, immediately before transport. Never retain
78
+ * headers, endpoints, user messages, schema text, or arbitrary provider options. */
79
+ export async function recordModelRequest(body, format, span = trace.getActiveSpan()) {
80
+ if (!span?.isRecording())
81
+ return;
82
+ const parsed = wireRequest.safeParse(typeof body === "string" ? JSON.parse(body) : body);
83
+ if (!parsed.success) {
84
+ span.setAttribute("gea.model.diagnostics.status", "unsupported-request-shape");
85
+ return;
86
+ }
87
+ const { tools, system, instructions, messages, input, ...parameters } = parsed.data;
88
+ const definitions = await Promise.all((tools ?? []).slice(0, 128).map(async (tool) => {
89
+ const definition = tool.function ?? tool;
90
+ return {
91
+ name: definition.name?.slice(0, 256),
92
+ type: tool.type ?? "function",
93
+ schemaSha256: await canonicalHash(definition.parameters ?? tool.input_schema ?? null),
94
+ strict: definition.strict ?? null,
95
+ };
96
+ }));
97
+ const systemMessages = (messages ?? (Array.isArray(input) ? input : []))
98
+ .filter((message) => message.role === "system" || message.role === "developer")
99
+ .map((message) => ({ role: message.role, content: message.content }));
100
+ const scope = context.active().getValue(modelDiagnosticContext);
101
+ span.setAttributes({
102
+ "gea.model.diagnostics.version": 1,
103
+ "gea.model.request.format": format,
104
+ "gea.model.request.parameters": JSON.stringify(parameters),
105
+ "gea.model.tools": JSON.stringify(definitions),
106
+ "gea.model.tools.count": tools?.length ?? 0,
107
+ "gea.model.tools.sha256": await canonicalHash(tools ?? []),
108
+ "gea.model.system.sha256": await canonicalHash({
109
+ system,
110
+ instructions,
111
+ messages: systemMessages,
112
+ }),
113
+ ...(scope?.skillsSha256
114
+ ? { "gea.model.skills.sha256": scope.skillsSha256 }
115
+ : {}),
116
+ });
117
+ }
package/dist/tracing.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { modelDiagnosticContext, } from "./model-diagnostics.js";
1
2
  import { agentSdkVersion } from "./version.js";
2
3
  import { Result } from "better-result";
3
4
  import { captureTraceContext } from "./trace-context.js";
@@ -166,7 +167,9 @@ export async function traceWorkerRequest(request, name, attributes, execute) {
166
167
  exports: new Set(),
167
168
  errors: [],
168
169
  };
169
- const parent = extractTraceContext(request.headers).setValue(requestTraceScope, scope);
170
+ const parent = extractTraceContext(request.headers)
171
+ .setValue(requestTraceScope, scope)
172
+ .setValue(modelDiagnosticContext, {});
170
173
  const span = currentProvider
171
174
  .getTracer("gea.agent-sdk", agentSdkVersion)
172
175
  .startSpan(name, {
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const agentSdkVersion = "0.1.261020-alpha.0";
1
+ export declare const agentSdkVersion = "0.1.261021-alpha.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/build-sdk-version.mjs from package.json.
2
- export const agentSdkVersion = "0.1.261020-alpha.0";
2
+ export const agentSdkVersion = "0.1.261021-alpha.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gea-ai/agent-sdk",
3
- "version": "0.1.261020-alpha.0",
3
+ "version": "0.1.261021-alpha.0",
4
4
  "private": false,
5
5
  "homepage": "https://musegea.com/developers",
6
6
  "license": "Apache-2.0",
@@ -123,7 +123,7 @@
123
123
  "@ai-sdk/otel": "1.0.119",
124
124
  "@ai-sdk/provider": "4.0.19",
125
125
  "@ai-sdk/provider-utils": "5.0.50",
126
- "@gea-ai/contract": "0.1.261020-alpha.0",
126
+ "@gea-ai/contract": "0.1.261021-alpha.0",
127
127
  "@opentelemetry/api": "1.9.1",
128
128
  "@opentelemetry/context-async-hooks": "2.10.0",
129
129
  "@opentelemetry/core": "2.10.0",