nexus-ai-pro 2.19.0 → 2.20.2

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.
@@ -1,4 +1,53 @@
1
+ import { capabilitiesOf, parseCapability } from '../agent/capabilities.js';
1
2
  import { sha256Hex } from '../utils/sha256.js';
3
+ export class EmulatedWorld {
4
+ scenario;
5
+ log;
6
+ constructor(start = {}) {
7
+ if (start.scenario !== undefined)
8
+ this.scenario = start.scenario;
9
+ this.log = JSON.parse(JSON.stringify(start.calls ?? []));
10
+ }
11
+ get calls() {
12
+ return JSON.parse(JSON.stringify(this.log));
13
+ }
14
+ get changes() {
15
+ return JSON.parse(JSON.stringify(this.log.filter((call) => call.changed)));
16
+ }
17
+ record(call, changed) {
18
+ this.log.push({ ...JSON.parse(JSON.stringify(call)), changed });
19
+ }
20
+ digest() {
21
+ return sha256Hex(canonical({
22
+ scenario: this.scenario ?? '',
23
+ changes: this.changes.map((call) => ({ tool: call.tool, args: call.args, result: call.result ?? null })),
24
+ }));
25
+ }
26
+ ordinal(tool, args) {
27
+ const identity = canonical(args);
28
+ let count = 0;
29
+ for (let index = this.log.length - 1; index >= 0; index -= 1) {
30
+ const call = this.log[index];
31
+ if (call.changed)
32
+ break;
33
+ if (call.tool === tool && canonical(call.args) === identity)
34
+ count += 1;
35
+ }
36
+ return count;
37
+ }
38
+ snapshot() {
39
+ return {
40
+ ...(this.scenario !== undefined ? { scenario: this.scenario } : {}),
41
+ calls: JSON.parse(JSON.stringify(this.log)),
42
+ };
43
+ }
44
+ fork() {
45
+ return new EmulatedWorld(this.snapshot());
46
+ }
47
+ toJSON() {
48
+ return this.snapshot();
49
+ }
50
+ }
2
51
  export class EmulationError extends Error {
3
52
  code;
4
53
  tool;
@@ -30,7 +79,23 @@ export class MemoryEmulationStore {
30
79
  }
31
80
  }
32
81
  export function emulationKey(call) {
33
- return sha256Hex(canonical({ tool: call.tool, args: call.args, scenario: call.scenario ?? '', ordinal: call.ordinal ?? 0 }));
82
+ return sha256Hex(canonical({
83
+ tool: call.tool,
84
+ args: call.args,
85
+ scenario: call.scenario ?? '',
86
+ ordinal: call.ordinal ?? 0,
87
+ ...(call.world !== undefined ? { world: call.world } : {}),
88
+ }));
89
+ }
90
+ function onlyReads(definition, args, reads) {
91
+ if (reads.has(definition.name))
92
+ return true;
93
+ const declared = capabilitiesOf(definition, args);
94
+ if (declared === undefined)
95
+ return false;
96
+ const parsed = declared.map((capability) => parseCapability(capability));
97
+ const isRead = (item) => (item.kind === 'filesystem' && item.access === 'read') || item.kind === 'mcp.read' || item.kind === 'api.read';
98
+ return (parsed.every((item) => isRead(item) || item.kind === 'network') && (parsed.length === 0 || parsed.some(isRead)));
34
99
  }
35
100
  export function emulatedTools(tools, options) {
36
101
  const mode = options.mode ?? (options.store ? 'auto' : 'emulate');
@@ -40,6 +105,10 @@ export function emulatedTools(tools, options) {
40
105
  const limit = Math.max(0, options.history ?? 20);
41
106
  const history = [];
42
107
  const ordinals = new Map();
108
+ const world = options.world;
109
+ const reads = new Set(options.reads ?? []);
110
+ const scenario = options.scenario ?? world?.scenario;
111
+ const told = scenario === options.scenario ? options : { ...options, scenario };
43
112
  const report = (call) => {
44
113
  try {
45
114
  options.onCall?.(call);
@@ -47,6 +116,18 @@ export function emulatedTools(tools, options) {
47
116
  catch {
48
117
  }
49
118
  };
119
+ const earlier = () => {
120
+ if (!world)
121
+ return limit === 0 ? [] : history.slice(-limit);
122
+ const calls = world.calls;
123
+ return calls
124
+ .filter((call, index) => call.changed || index >= calls.length - limit)
125
+ .map(({ changed: _changed, ...call }) => call);
126
+ };
127
+ const remember = (definition, answer) => {
128
+ history.push(answer);
129
+ world?.record(answer, answer.error === undefined && !onlyReads(definition, answer.args, reads));
130
+ };
50
131
  return tools.map((definition) => {
51
132
  const { execute: run, stream, ...shape } = definition;
52
133
  if (passthrough.has(definition.name)) {
@@ -55,13 +136,20 @@ export function emulatedTools(tools, options) {
55
136
  return {
56
137
  ...shape,
57
138
  execute: async (args, context) => {
58
- const key = emulationKey({ tool: definition.name, args, scenario: options.scenario });
139
+ const key = emulationKey({
140
+ tool: definition.name,
141
+ args,
142
+ scenario,
143
+ ...(world ? { world: world.digest() } : {}),
144
+ });
59
145
  try {
60
146
  const result = run ? await run(args, context) : await drain(definition, args, context);
147
+ remember(definition, { tool: definition.name, args, result });
61
148
  report({ tool: definition.name, args, result, source: 'real', key });
62
149
  return result;
63
150
  }
64
151
  catch (error) {
152
+ remember(definition, { tool: definition.name, args, error: messageOf(error) });
65
153
  report({ tool: definition.name, args, error: messageOf(error), source: 'real', key });
66
154
  throw error;
67
155
  }
@@ -71,10 +159,22 @@ export function emulatedTools(tools, options) {
71
159
  return {
72
160
  ...shape,
73
161
  execute: async (args, context) => {
74
- const identity = `${definition.name}\u0000${canonical(args)}`;
75
- const ordinal = ordinals.get(identity) ?? 0;
76
- ordinals.set(identity, ordinal + 1);
77
- const key = emulationKey({ tool: definition.name, args, scenario: options.scenario, ordinal });
162
+ let ordinal;
163
+ if (world) {
164
+ ordinal = world.ordinal(definition.name, args);
165
+ }
166
+ else {
167
+ const identity = `${definition.name}\u0000${canonical(args)}`;
168
+ ordinal = ordinals.get(identity) ?? 0;
169
+ ordinals.set(identity, ordinal + 1);
170
+ }
171
+ const key = emulationKey({
172
+ tool: definition.name,
173
+ args,
174
+ scenario,
175
+ ordinal,
176
+ ...(world ? { world: world.digest() } : {}),
177
+ });
78
178
  let answer;
79
179
  let source = 'store';
80
180
  if (mode === 'auto' || mode === 'replay')
@@ -83,12 +183,12 @@ export function emulatedTools(tools, options) {
83
183
  if (mode === 'replay') {
84
184
  throw new EmulationError('EMULATION_MISS', definition.name, args, `No kept answer for ${definition.name}(${canonical(args)}), call ${ordinal + 1}: record it first`);
85
185
  }
86
- answer = await emulate(definition, args, context, limit === 0 ? [] : history.slice(-limit), options);
186
+ answer = await emulate(definition, args, context, earlier(), told, world !== undefined);
87
187
  source = 'model';
88
188
  if (mode !== 'emulate')
89
189
  await options.store?.set(key, answer);
90
190
  }
91
- history.push(answer);
191
+ remember(definition, answer);
92
192
  report({
93
193
  tool: definition.name,
94
194
  args,
@@ -103,9 +203,9 @@ export function emulatedTools(tools, options) {
103
203
  };
104
204
  });
105
205
  }
106
- async function emulate(definition, args, context, earlier, options) {
206
+ async function emulate(definition, args, context, earlier, options, inWorld) {
107
207
  const messages = [
108
- { role: 'system', content: brief(definition, earlier, options) },
208
+ { role: 'system', content: brief(definition, earlier, options, inWorld) },
109
209
  { role: 'user', content: `Arguments: ${JSON.stringify(args)}` },
110
210
  ];
111
211
  let problem = '';
@@ -136,7 +236,7 @@ async function emulate(definition, args, context, earlier, options) {
136
236
  }
137
237
  throw new EmulationError('EMULATION_INVALID', definition.name, args, `The emulator gave no usable answer for ${definition.name}: ${problem}`);
138
238
  }
139
- function brief(definition, earlier, options) {
239
+ function brief(definition, earlier, options, inWorld) {
140
240
  const lines = [
141
241
  `You are emulating the tool "${definition.name}" for a test, in place of the real one.`,
142
242
  'Reply with exactly what the real tool would return for the arguments you are given, as JSON:',
@@ -163,7 +263,9 @@ function brief(definition, earlier, options) {
163
263
  }
164
264
  }
165
265
  if (earlier.length > 0) {
166
- lines.push('', 'Earlier calls in this run, oldest first:');
266
+ lines.push('', inWorld
267
+ ? 'What has happened in this world, oldest first: every change made in it, and the latest calls. Answer as the world now is.'
268
+ : 'Earlier calls in this run, oldest first:');
167
269
  for (const call of earlier) {
168
270
  const outcome = call.error === undefined ? `returned ${JSON.stringify(call.result)}` : `failed: ${call.error}`;
169
271
  lines.push(`- ${call.tool} ${JSON.stringify(call.args)} ${outcome}`);
@@ -1,3 +1,12 @@
1
+ const PHRASES = [
2
+ [/\bplease make sure that\b/gi, 'ensure'],
3
+ [/\byou should\b/gi, 'do'],
4
+ [/\bit is important to\b/gi, 'must'],
5
+ [/\bin order to\b/gi, 'to'],
6
+ [/\bdue to the fact that\b/gi, 'because'],
7
+ [/\bat this point in time\b/gi, 'now'],
8
+ [/\bas soon as possible\b/gi, 'ASAP'],
9
+ ];
1
10
  export class PromptDensifier {
2
11
  densifyRequest(request, config = {}) {
3
12
  if (config.enabled === false)
@@ -19,7 +28,7 @@ export class PromptDensifier {
19
28
  }
20
29
  densifyText(text, techniques, applied, config) {
21
30
  const segments = this.splitCodeBlocks(text, config.preserveCodeBlocks !== false);
22
- return segments
31
+ const joined = segments
23
32
  .map((segment) => {
24
33
  if (segment.type === 'code')
25
34
  return segment.value;
@@ -29,21 +38,15 @@ export class PromptDensifier {
29
38
  output = output
30
39
  .replace(/[ \t]+/g, ' ')
31
40
  .replace(/\n{3,}/g, '\n\n')
32
- .replace(/[ \t]+\n/g, '\n')
33
- .trim();
41
+ .replace(/[ \t]+\n/g, '\n');
34
42
  if (output !== before)
35
43
  applied.add('whitespace-cleanup');
36
44
  }
37
45
  if (techniques.includes('phrase-compression')) {
38
46
  const before = output;
39
- output = output
40
- .replace(/please make sure that/gi, 'ensure')
41
- .replace(/you should/gi, 'do')
42
- .replace(/it is important to/gi, 'must')
43
- .replace(/in order to/gi, 'to')
44
- .replace(/due to the fact that/gi, 'because')
45
- .replace(/at this point in time/gi, 'now')
46
- .replace(/as soon as possible/gi, 'ASAP');
47
+ for (const [phrase, shorter] of PHRASES) {
48
+ output = output.replace(phrase, (match) => /^[A-Z]/.test(match) ? `${shorter.charAt(0).toUpperCase()}${shorter.slice(1)}` : shorter);
49
+ }
47
50
  if (output !== before)
48
51
  applied.add('phrase-compression');
49
52
  }
@@ -56,6 +59,12 @@ export class PromptDensifier {
56
59
  return output;
57
60
  })
58
61
  .join('');
62
+ if (!techniques.includes('whitespace-cleanup'))
63
+ return joined;
64
+ const trimmed = joined.trim();
65
+ if (trimmed !== joined)
66
+ applied.add('whitespace-cleanup');
67
+ return trimmed;
59
68
  }
60
69
  splitCodeBlocks(text, preserveCodeBlocks) {
61
70
  if (!preserveCodeBlocks)
@@ -258,7 +258,7 @@ export function a2aGrpcClient(options) {
258
258
  });
259
259
  const abort = () => request.close(http2.constants.NGHTTP2_CANCEL);
260
260
  signal?.addEventListener('abort', abort, { once: true });
261
- request.end(frame(encodeA2a(shape.request, params)));
261
+ request.end(frame(encodeA2a(shape.request, options.tenant ? { tenant: options.tenant, ...params } : params)));
262
262
  let status = {};
263
263
  request.on('response', (headers) => {
264
264
  if (headers['grpc-status'] !== undefined)
@@ -2,8 +2,8 @@
2
2
  * A2A's messages in Protocol Buffers, as `specification/a2a.proto` of protocol 1.0 numbers them
3
3
  * (package `lf.a2a.v1`): each turned into, and read from, the JSON the other bindings carry, so the
4
4
  * gRPC binding calls the same methods with the same params. With `google.protobuf.Struct`, `Value`,
5
- * `Timestamp`, and `google.rpc.Status`. Fields the agent never sends, such as a card's security
6
- * schemes, are read past and not written.
5
+ * `Timestamp`, and `google.rpc.Status`. A card's security schemes, requirements, and signatures are
6
+ * written and read as the card's JSON has them.
7
7
  */
8
8
  /** Each method of `lf.a2a.v1.A2AService`: what it takes, what it answers, and whether it streams. */
9
9
  export declare const A2A_GRPC_METHODS: Readonly<Record<string, {
@@ -95,11 +95,56 @@ const MESSAGES = {
95
95
  f('version', 5, 'string'),
96
96
  f('documentationUrl', 6, 'string', present),
97
97
  f('capabilities', 7, { message: 'AgentCapabilities' }),
98
+ f('securitySchemes', 8, { map: 'SecurityScheme' }),
99
+ f('securityRequirements', 9, { message: 'SecurityRequirement' }, many),
98
100
  f('defaultInputModes', 10, 'string', all),
99
101
  f('defaultOutputModes', 11, 'string', all),
100
102
  f('skills', 12, { message: 'AgentSkill' }, all),
103
+ f('signatures', 13, { message: 'AgentCardSignature' }, many),
101
104
  f('iconUrl', 14, 'string', present),
102
105
  ],
106
+ AgentCardSignature: [f('protected', 1, 'string'), f('signature', 2, 'string'), f('header', 3, 'struct')],
107
+ StringList: [f('list', 1, 'string', all)],
108
+ SecurityRequirement: [f('schemes', 1, { map: 'StringList' })],
109
+ SecurityScheme: [
110
+ f('apiKeySecurityScheme', 1, { message: 'APIKeySecurityScheme' }),
111
+ f('httpAuthSecurityScheme', 2, { message: 'HTTPAuthSecurityScheme' }),
112
+ f('oauth2SecurityScheme', 3, { message: 'OAuth2SecurityScheme' }),
113
+ f('openIdConnectSecurityScheme', 4, { message: 'OpenIdConnectSecurityScheme' }),
114
+ f('mtlsSecurityScheme', 5, { message: 'MutualTlsSecurityScheme' }),
115
+ ],
116
+ APIKeySecurityScheme: [f('description', 1, 'string'), f('location', 2, 'string'), f('name', 3, 'string')],
117
+ HTTPAuthSecurityScheme: [f('description', 1, 'string'), f('scheme', 2, 'string'), f('bearerFormat', 3, 'string')],
118
+ OAuth2SecurityScheme: [
119
+ f('description', 1, 'string'),
120
+ f('flows', 2, { message: 'OAuthFlows' }),
121
+ f('oauth2MetadataUrl', 3, 'string'),
122
+ ],
123
+ OpenIdConnectSecurityScheme: [f('description', 1, 'string'), f('openIdConnectUrl', 2, 'string')],
124
+ MutualTlsSecurityScheme: [f('description', 1, 'string')],
125
+ OAuthFlows: [
126
+ f('authorizationCode', 1, { message: 'AuthorizationCodeOAuthFlow' }),
127
+ f('clientCredentials', 2, { message: 'ClientCredentialsOAuthFlow' }),
128
+ f('implicit', 3, { message: 'ImplicitOAuthFlow' }),
129
+ f('password', 4, { message: 'PasswordOAuthFlow' }),
130
+ f('deviceCode', 5, { message: 'DeviceCodeOAuthFlow' }),
131
+ ],
132
+ AuthorizationCodeOAuthFlow: [
133
+ f('authorizationUrl', 1, 'string'),
134
+ f('tokenUrl', 2, 'string'),
135
+ f('refreshUrl', 3, 'string'),
136
+ f('scopes', 4, 'stringMap'),
137
+ f('pkceRequired', 5, 'bool'),
138
+ ],
139
+ ClientCredentialsOAuthFlow: [f('tokenUrl', 1, 'string'), f('refreshUrl', 2, 'string'), f('scopes', 3, 'stringMap')],
140
+ ImplicitOAuthFlow: [f('authorizationUrl', 1, 'string'), f('refreshUrl', 2, 'string'), f('scopes', 3, 'stringMap')],
141
+ PasswordOAuthFlow: [f('tokenUrl', 1, 'string'), f('refreshUrl', 2, 'string'), f('scopes', 3, 'stringMap')],
142
+ DeviceCodeOAuthFlow: [
143
+ f('deviceAuthorizationUrl', 1, 'string'),
144
+ f('tokenUrl', 2, 'string'),
145
+ f('refreshUrl', 3, 'string'),
146
+ f('scopes', 4, 'stringMap'),
147
+ ],
103
148
  AgentProvider: [f('url', 1, 'string'), f('organization', 2, 'string')],
104
149
  AgentCapabilities: [
105
150
  f('streaming', 1, 'bool', present),
@@ -121,6 +166,7 @@ const MESSAGES = {
121
166
  f('examples', 5, 'string', many),
122
167
  f('inputModes', 6, 'string', many),
123
168
  f('outputModes', 7, 'string', many),
169
+ f('securityRequirements', 8, { message: 'SecurityRequirement' }, many),
124
170
  ],
125
171
  TaskPushNotificationConfig: [
126
172
  f('tenant', 1, 'string'),
@@ -337,6 +383,21 @@ function writeField(writer, field, item, always) {
337
383
  writer.bytes(inner.finish());
338
384
  }
339
385
  }
386
+ else if ('map' in type) {
387
+ if (typeof item !== 'object' || item === null || Array.isArray(item))
388
+ return;
389
+ for (const [key, entry] of Object.entries(item)) {
390
+ const inner = new Writer();
391
+ inner.tag(1, 2);
392
+ inner.bytes(utf8.encode(key));
393
+ const value = new Writer();
394
+ writeMessage(value, type.map, (entry ?? {}));
395
+ inner.tag(2, 2);
396
+ inner.bytes(value.finish());
397
+ writer.tag(field.number, 2);
398
+ writer.bytes(inner.finish());
399
+ }
400
+ }
340
401
  else if ('enum' in type) {
341
402
  const index = typeof item === 'number' ? item : type.enum.indexOf(String(item));
342
403
  if (index < 0 || (!always && index === 0))
@@ -456,8 +517,9 @@ export function decodeA2a(type, bytes) {
456
517
  const value = readField(field, raw);
457
518
  if (value === undefined)
458
519
  continue;
459
- if (field.type === 'stringMap')
520
+ if (field.type === 'stringMap' || (typeof field.type === 'object' && 'map' in field.type)) {
460
521
  out[field.json] = { ...out[field.json], ...value };
522
+ }
461
523
  else if (field.repeated) {
462
524
  const list = out[field.json] ?? [];
463
525
  list.push(value);
@@ -511,6 +573,19 @@ function readField(field, raw) {
511
573
  }
512
574
  return { [key]: value };
513
575
  }
576
+ if ('map' in type) {
577
+ if (!raw.bytes)
578
+ return undefined;
579
+ let key = '';
580
+ let value = new Uint8Array();
581
+ for (const inner of rawFields(raw.bytes)) {
582
+ if (inner.number === 1 && inner.bytes)
583
+ key = fromUtf8.decode(inner.bytes);
584
+ if (inner.number === 2 && inner.bytes)
585
+ value = inner.bytes;
586
+ }
587
+ return { [key]: decodeA2a(type.map, value) };
588
+ }
514
589
  if ('enum' in type) {
515
590
  if (raw.varint === undefined)
516
591
  return undefined;
@@ -69,6 +69,86 @@ export interface A2aTask {
69
69
  /** Anything else. */
70
70
  metadata?: Record<string, unknown>;
71
71
  }
72
+ /** One of the OAuth 2.0 flows an `oauth2SecurityScheme` offers: exactly one is set. */
73
+ export type A2aOAuthFlows = {
74
+ authorizationCode: {
75
+ authorizationUrl: string;
76
+ tokenUrl: string;
77
+ refreshUrl?: string;
78
+ scopes: Record<string, string>;
79
+ pkceRequired?: boolean;
80
+ };
81
+ } | {
82
+ clientCredentials: {
83
+ tokenUrl: string;
84
+ refreshUrl?: string;
85
+ scopes: Record<string, string>;
86
+ };
87
+ } | {
88
+ deviceCode: {
89
+ deviceAuthorizationUrl: string;
90
+ tokenUrl: string;
91
+ refreshUrl?: string;
92
+ scopes: Record<string, string>;
93
+ };
94
+ } | {
95
+ implicit: {
96
+ authorizationUrl?: string;
97
+ refreshUrl?: string;
98
+ scopes?: Record<string, string>;
99
+ };
100
+ } | {
101
+ password: {
102
+ tokenUrl?: string;
103
+ refreshUrl?: string;
104
+ scopes?: Record<string, string>;
105
+ };
106
+ };
107
+ /** How a caller authenticates with an agent, as its card names it: exactly one scheme is set. */
108
+ export type A2aSecurityScheme = {
109
+ apiKeySecurityScheme: {
110
+ description?: string;
111
+ location: 'query' | 'header' | 'cookie';
112
+ name: string;
113
+ };
114
+ } | {
115
+ httpAuthSecurityScheme: {
116
+ description?: string;
117
+ scheme: string;
118
+ bearerFormat?: string;
119
+ };
120
+ } | {
121
+ oauth2SecurityScheme: {
122
+ description?: string;
123
+ flows: A2aOAuthFlows;
124
+ oauth2MetadataUrl?: string;
125
+ };
126
+ } | {
127
+ openIdConnectSecurityScheme: {
128
+ description?: string;
129
+ openIdConnectUrl: string;
130
+ };
131
+ } | {
132
+ mtlsSecurityScheme: {
133
+ description?: string;
134
+ };
135
+ };
136
+ /** The schemes a call needs, by the names the card gives them, each with the scopes it needs. */
137
+ export interface A2aSecurityRequirement {
138
+ /** Each scheme's name, with its scopes. */
139
+ schemes: Record<string, {
140
+ list: string[];
141
+ }>;
142
+ }
143
+ /** A JSON Web Signature over an agent card, as the card carries it. */
144
+ export interface A2aCardSignature {
145
+ /** The protected header: base64url-encoded JSON. */
146
+ protected: string;
147
+ /** The signature, base64url-encoded. */
148
+ signature: string;
149
+ /** The unprotected header's values. */
150
+ header?: Record<string, unknown>;
151
+ }
72
152
  /** A skill an agent card advertises. */
73
153
  export interface A2aSkill {
74
154
  /** Its id. */
@@ -81,6 +161,8 @@ export interface A2aSkill {
81
161
  tags: string[];
82
162
  /** Example requests. */
83
163
  examples?: string[];
164
+ /** The schemes a call of this skill needs, beyond the card's. */
165
+ securityRequirements?: A2aSecurityRequirement[];
84
166
  }
85
167
  /** What an agent publishes about itself at `/.well-known/agent-card.json`. */
86
168
  export interface A2aAgentCard {
@@ -114,6 +196,12 @@ export interface A2aAgentCard {
114
196
  defaultOutputModes: string[];
115
197
  /** What it can do. */
116
198
  skills: A2aSkill[];
199
+ /** How a caller authenticates, each scheme by a name `securityRequirements` use. */
200
+ securitySchemes?: Record<string, A2aSecurityScheme>;
201
+ /** The schemes a call needs. */
202
+ securityRequirements?: A2aSecurityRequirement[];
203
+ /** Signatures over the card, as given: a signature must be over the card as it is served. */
204
+ signatures?: A2aCardSignature[];
117
205
  }
118
206
  /** A streamed event: a task, a status change, or a piece of an artifact. */
119
207
  export type A2aStreamEvent = {
@@ -143,6 +231,11 @@ export declare const A2A_ERRORS: {
143
231
  readonly unsupportedOperation: -32004;
144
232
  readonly extendedCardNotConfigured: -32007;
145
233
  readonly versionNotSupported: -32009;
234
+ /**
235
+ * This package's own, from the range JSON-RPC leaves to servers: the caller may not act for the
236
+ * tenant it named. HTTP 403, and `PERMISSION_DENIED` over gRPC.
237
+ */
238
+ readonly permissionDenied: -32099;
146
239
  };
147
240
  /** Raised by a client when an agent answers with an error, on any binding, as A2A's code. */
148
241
  export declare class A2aError extends Error {
@@ -191,6 +284,8 @@ export interface A2aTaskRecord {
191
284
  run?: A2aTaskRun;
192
285
  /** Bumped by every claim of the lease, so two replicas claiming one task cannot both win. */
193
286
  version?: number;
287
+ /** The tenant it belongs to, when the handler serves several: no other tenant's request sees it. */
288
+ tenant?: string;
194
289
  }
195
290
  /** A replica's hold on a working task. */
196
291
  export interface A2aTaskLease {
@@ -216,6 +311,8 @@ export interface A2aTaskQuery {
216
311
  contextId?: string;
217
312
  /** Only those in this state. */
218
313
  state?: A2aTaskState;
314
+ /** Only this tenant's. A store that serves several tenants must honour it. */
315
+ tenant?: string;
219
316
  /** Most returned. */
220
317
  limit: number;
221
318
  /** Skipped first, for paging. */
@@ -314,6 +411,16 @@ export interface A2aPushOptions {
314
411
  everyMs?: number;
315
412
  };
316
413
  }
414
+ /** How one handler serves several tenants, each request routed by the `tenant` it names. */
415
+ export interface A2aTenancyOptions {
416
+ /**
417
+ * Whether a caller may act for the tenant its request names. Defaults to its principal's `tenantId`
418
+ * being that tenant, so a caller nobody authenticated may act for none.
419
+ */
420
+ authorize?: (tenant: string, principal: Principal | undefined) => boolean | Promise<boolean>;
421
+ /** Whether every request must name a tenant. Defaults to true. */
422
+ required?: boolean;
423
+ }
317
424
  /** Options for `a2aHandler()`. */
318
425
  export interface A2aServerOptions {
319
426
  /** The card's content: the endpoint `url` is where this handler is mounted. */
@@ -381,6 +488,15 @@ export interface A2aServerOptions {
381
488
  protocolVersion?: string;
382
489
  tenant?: string;
383
490
  }>;
491
+ /**
492
+ * Serves several tenants from this one handler, each request routed by the tenant it names: in its
493
+ * params over JSON-RPC, as its path's first segment over HTTP+JSON (`/{tenant}/message:send`), and in
494
+ * its message over gRPC. Each tenant's tasks and conversations are its own, and its runs carry the
495
+ * tenant on their principal, for its credentials and budget. A caller that may not act for the tenant
496
+ * it names is refused with `A2A_ERRORS.permissionDenied`. `true` takes the defaults. Off by default:
497
+ * a request's tenant is not read.
498
+ */
499
+ tenants?: A2aTenancyOptions | boolean;
384
500
  }
385
501
  /** The binding a call arrived on. */
386
502
  export type A2aBinding = 'JSONRPC' | 'HTTP+JSON' | 'GRPC' | (string & {});
@@ -483,6 +599,11 @@ export interface A2aClientOptions {
483
599
  * on `nexus-ai-pro/protocols/a2a/grpc`.
484
600
  */
485
601
  binding?: 'JSONRPC' | 'HTTP+JSON';
602
+ /**
603
+ * The tenant every request names. Defaults to the `tenant` of the interface the card lists for the
604
+ * binding, as protocol 1.0 requires a client to send it.
605
+ */
606
+ tenant?: string;
486
607
  }
487
608
  /** What to send: text, and optionally data, a conversation, or the paused task it answers. */
488
609
  export interface A2aSendOptions {