@cleocode/lafs-protocol 1.2.3 → 1.3.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.
@@ -1,204 +1,234 @@
1
1
  /**
2
2
  * LAFS Agent Discovery - Express/Fastify Middleware
3
- * Serves discovery document at /.well-known/lafs.json
3
+ * Serves A2A-compliant Agent Card at /.well-known/agent-card.json
4
+ * Maintains backward compatibility with legacy /.well-known/lafs.json
5
+ *
6
+ * A2A v1.0+ Compliant Implementation
7
+ * Reference: specs/external/agent-discovery.md
4
8
  */
5
9
  import { createRequire } from "node:module";
6
10
  import { createHash } from "crypto";
7
- import { readFileSync } from "fs";
8
- import { fileURLToPath } from "url";
9
- import { dirname, join } from "path";
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
- // Handle ESM/CommonJS interop for AJV
11
+ import { buildLafsExtension } from './a2a/extensions.js';
13
12
  const require = createRequire(import.meta.url);
14
- const AjvModule = require("ajv");
15
- const AddFormatsModule = require("ajv-formats");
16
- const AjvCtor = (typeof AjvModule === "function" ? AjvModule : AjvModule.default);
17
- const addFormats = (typeof AddFormatsModule === "function" ? AddFormatsModule : AddFormatsModule.default);
18
- let ajvInstance = null;
19
- let validateDiscovery = null;
20
- /**
21
- * Initialize AJV validator for discovery documents
22
- */
23
- function initValidator() {
24
- if (ajvInstance && validateDiscovery)
25
- return;
26
- ajvInstance = new AjvCtor({ strict: true, allErrors: true });
27
- addFormats(ajvInstance);
28
- try {
29
- // Try to load schema from schemas directory
30
- const schemaPath = join(__dirname, "..", "..", "schemas", "v1", "discovery.schema.json");
31
- const schema = JSON.parse(readFileSync(schemaPath, "utf-8"));
32
- validateDiscovery = ajvInstance.compile(schema);
33
- }
34
- catch (e) {
35
- // Fallback to inline schema if file not found
36
- const fallbackSchema = {
37
- $schema: "http://json-schema.org/draft-07/schema#",
38
- type: "object",
39
- required: ["$schema", "lafs_version", "service", "capabilities", "endpoints"],
40
- properties: {
41
- $schema: { type: "string", format: "uri" },
42
- lafs_version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" },
43
- service: {
44
- type: "object",
45
- required: ["name", "version"],
46
- properties: {
47
- name: { type: "string", minLength: 1 },
48
- version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" },
49
- description: { type: "string" }
50
- }
51
- },
52
- capabilities: {
53
- type: "array",
54
- items: {
55
- type: "object",
56
- required: ["name", "version", "operations"],
57
- properties: {
58
- name: { type: "string", minLength: 1 },
59
- version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" },
60
- description: { type: "string" },
61
- operations: { type: "array", items: { type: "string" } },
62
- optional: { type: "boolean" }
63
- }
64
- }
65
- },
66
- endpoints: {
67
- type: "object",
68
- required: ["envelope", "discovery"],
69
- properties: {
70
- envelope: { type: "string", minLength: 1 },
71
- context: { type: "string", minLength: 1 },
72
- discovery: { type: "string", minLength: 1 }
73
- }
74
- }
75
- }
76
- };
77
- validateDiscovery = ajvInstance.compile(fallbackSchema);
78
- }
79
- }
13
+ // ============================================================================
14
+ // Utility Functions
15
+ // ============================================================================
80
16
  /**
81
17
  * Build absolute URL from base and path
82
18
  */
83
19
  function buildUrl(base, path, req) {
84
- // If path is already absolute, return it
85
20
  if (path.startsWith("http://") || path.startsWith("https://")) {
86
21
  return path;
87
22
  }
88
- // If base is provided, use it
89
23
  if (base) {
90
24
  const separator = base.endsWith("/") || path.startsWith("/") ? "" : "/";
91
25
  return `${base}${separator}${path}`;
92
26
  }
93
- // Otherwise try to construct from request
94
27
  if (req) {
95
28
  const protocol = req.headers["x-forwarded-proto"] || req.protocol || "http";
96
29
  const host = req.headers.host || "localhost";
97
30
  const separator = path.startsWith("/") ? "" : "/";
98
31
  return `${protocol}://${host}${separator}${path}`;
99
32
  }
100
- // Fallback to relative path
101
33
  return path.startsWith("/") ? path : `/${path}`;
102
34
  }
103
35
  /**
104
- * Generate ETag from document content
36
+ * Generate ETag from content
105
37
  */
106
38
  function generateETag(content) {
107
39
  return `"${createHash("sha256").update(content).digest("hex").slice(0, 32)}"`;
108
40
  }
109
41
  /**
110
- * Build discovery document from configuration
42
+ * Build A2A Agent Card from configuration
43
+ */
44
+ function buildAgentCard(config, req) {
45
+ const schemaUrl = config.schemaUrl || "https://lafs.dev/schemas/v1/agent-card.schema.json";
46
+ // Handle legacy config migration
47
+ if (config.service && !config.agent) {
48
+ console.warn("[DEPRECATION] Using legacy 'service' config. Migrate to 'agent' format for A2A v1.0+ compliance.");
49
+ return {
50
+ $schema: schemaUrl,
51
+ name: config.service.name,
52
+ description: config.service.description || "LAFS-compliant agent",
53
+ version: config.lafsVersion || config.service.version || "1.0.0",
54
+ url: config.endpoints?.envelope
55
+ ? buildUrl(config.baseUrl, config.endpoints.envelope, req)
56
+ : buildUrl(config.baseUrl, "/", req),
57
+ capabilities: {
58
+ streaming: false,
59
+ pushNotifications: false,
60
+ extendedAgentCard: false,
61
+ extensions: []
62
+ },
63
+ defaultInputModes: ["application/json"],
64
+ defaultOutputModes: ["application/json"],
65
+ skills: (config.capabilities || []).map(cap => ({
66
+ id: cap.name.toLowerCase().replace(/\s+/g, "-"),
67
+ name: cap.name,
68
+ description: cap.description || `${cap.name} capability`,
69
+ tags: cap.operations || [],
70
+ examples: []
71
+ }))
72
+ };
73
+ }
74
+ // Standard A2A v1.0 Agent Card (agent is guaranteed present; legacy path returned above)
75
+ const agent = config.agent;
76
+ const card = {
77
+ $schema: schemaUrl,
78
+ ...agent,
79
+ url: agent.url || buildUrl(config.baseUrl, "/", req)
80
+ };
81
+ // Auto-include LAFS extension if configured
82
+ if (config.autoIncludeLafsExtension) {
83
+ const lafsOptions = typeof config.autoIncludeLafsExtension === 'object'
84
+ ? config.autoIncludeLafsExtension
85
+ : undefined;
86
+ const ext = buildLafsExtension(lafsOptions);
87
+ if (!card.capabilities.extensions) {
88
+ card.capabilities.extensions = [];
89
+ }
90
+ card.capabilities.extensions.push({
91
+ uri: ext.uri,
92
+ description: ext.description ?? 'LAFS envelope protocol for structured agent responses',
93
+ required: ext.required ?? false,
94
+ params: ext.params,
95
+ });
96
+ }
97
+ return card;
98
+ }
99
+ /**
100
+ * Build legacy discovery document for backward compatibility
101
+ * @deprecated Will be removed in v2.0.0
111
102
  */
112
- function buildDiscoveryDocument(config, req) {
103
+ function buildLegacyDiscoveryDocument(config, req) {
113
104
  const schemaUrl = config.schemaUrl || "https://lafs.dev/schemas/v1/discovery.schema.json";
114
- const lafsVersion = config.lafsVersion || "1.0.0";
105
+ const lafsVersion = config.lafsVersion || "1.3.1";
115
106
  return {
116
107
  $schema: schemaUrl,
117
108
  lafs_version: lafsVersion,
118
- service: config.service,
119
- capabilities: config.capabilities,
109
+ service: config.service || {
110
+ name: config.agent.name,
111
+ version: config.agent.version,
112
+ description: config.agent.description
113
+ },
114
+ capabilities: config.capabilities || config.agent.skills.map(skill => ({
115
+ name: skill.name,
116
+ version: config.agent.version,
117
+ description: skill.description,
118
+ operations: skill.tags,
119
+ optional: false
120
+ })),
120
121
  endpoints: {
121
- envelope: buildUrl(config.baseUrl, config.endpoints.envelope, req),
122
- context: config.endpoints.context
123
- ? buildUrl(config.baseUrl, config.endpoints.context, req)
124
- : undefined,
125
- discovery: config.endpoints.discovery
126
- ? buildUrl(config.baseUrl, config.endpoints.discovery, req)
127
- : buildUrl(config.baseUrl, "/.well-known/lafs.json", req)
122
+ envelope: buildUrl(config.baseUrl, config.endpoints?.envelope || config.agent.url, req),
123
+ context: config.endpoints?.context ? buildUrl(config.baseUrl, config.endpoints.context, req) : undefined,
124
+ discovery: config.endpoints?.discovery || buildUrl(config.baseUrl, "/.well-known/lafs.json", req)
128
125
  }
129
126
  };
130
127
  }
128
+ // ============================================================================
129
+ // Middleware
130
+ // ============================================================================
131
131
  /**
132
- * Validate discovery document against schema
133
- */
134
- function validateDocument(doc) {
135
- initValidator();
136
- if (!validateDiscovery) {
137
- throw new Error("Discovery document validator not initialized");
138
- }
139
- const valid = validateDiscovery(doc);
140
- if (!valid) {
141
- const errors = validateDiscovery.errors;
142
- const errorMessages = errors?.map((e) => `${e.instancePath || "root"}: ${e.message}`).join("; ");
143
- throw new Error(`Discovery document validation failed: ${errorMessages}`);
144
- }
145
- }
146
- /**
147
- * Create Express middleware for serving LAFS discovery document
132
+ * Create Express middleware for serving A2A Agent Card
133
+ *
134
+ * Serves A2A-compliant Agent Card at /.well-known/agent-card.json
135
+ * Maintains backward compatibility with legacy /.well-known/lafs.json
148
136
  *
149
- * @param config - Discovery configuration
137
+ * @param config - Discovery configuration (A2A v1.0 format)
150
138
  * @param options - Middleware options
151
139
  * @returns Express RequestHandler
152
140
  *
153
141
  * @example
154
142
  * ```typescript
155
143
  * import express from "express";
156
- * import { discoveryMiddleware } from "./discovery.js";
144
+ * import { discoveryMiddleware } from "@cleocode/lafs-protocol/discovery";
157
145
  *
158
146
  * const app = express();
159
147
  *
160
148
  * app.use(discoveryMiddleware({
161
- * service: {
162
- * name: "my-lafs-service",
149
+ * agent: {
150
+ * name: "my-lafs-agent",
151
+ * description: "A LAFS-compliant agent with A2A support",
163
152
  * version: "1.0.0",
164
- * description: "A LAFS-compliant API service"
165
- * },
166
- * capabilities: [
167
- * {
168
- * name: "envelope-processor",
169
- * version: "1.0.0",
170
- * operations: ["process", "validate"],
171
- * description: "Process LAFS envelopes"
172
- * }
173
- * ],
174
- * endpoints: {
175
- * envelope: "/api/v1/envelope",
176
- * context: "/api/v1/context"
153
+ * url: "https://api.example.com",
154
+ * capabilities: {
155
+ * streaming: true,
156
+ * pushNotifications: false,
157
+ * extensions: []
158
+ * },
159
+ * defaultInputModes: ["application/json", "text/plain"],
160
+ * defaultOutputModes: ["application/json"],
161
+ * skills: [
162
+ * {
163
+ * id: "envelope-processor",
164
+ * name: "Envelope Processor",
165
+ * description: "Process LAFS envelopes",
166
+ * tags: ["lafs", "envelope", "validation"],
167
+ * examples: ["Validate this envelope", "Process envelope data"]
168
+ * }
169
+ * ]
177
170
  * }
178
171
  * }));
179
172
  * ```
180
173
  */
181
174
  export function discoveryMiddleware(config, options = {}) {
182
- const path = options.path || "/.well-known/lafs.json";
175
+ const path = options.path || "/.well-known/agent-card.json";
176
+ const legacyPath = options.legacyPath || "/.well-known/lafs.json";
177
+ // Disable legacy path by default when a custom path is set, unless explicitly enabled
178
+ const enableLegacyPath = options.enableLegacyPath ?? !options.path;
183
179
  const enableHead = options.enableHead !== false;
184
180
  const enableEtag = options.enableEtag !== false;
185
181
  const cacheMaxAge = config.cacheMaxAge || 3600;
186
182
  // Validate configuration
187
- if (!config.service?.name || !config.service?.version) {
188
- throw new Error("Discovery config requires service.name and service.version");
183
+ if (!config.agent && !config.service) {
184
+ throw new Error("Discovery config requires 'agent' (A2A v1.0) or 'service' (legacy) configuration");
189
185
  }
190
- if (!Array.isArray(config.capabilities)) {
191
- throw new Error("Discovery config requires capabilities array");
186
+ // Validate legacy service config fields
187
+ if (config.service) {
188
+ if (!config.service.name) {
189
+ throw new Error("Discovery config requires 'service.name'");
190
+ }
191
+ if (!config.service.version) {
192
+ throw new Error("Discovery config requires 'service.version'");
193
+ }
192
194
  }
193
- if (!config.endpoints?.envelope) {
194
- throw new Error("Discovery config requires endpoints.envelope");
195
+ // Validate legacy capabilities/endpoints when using service config
196
+ if (config.service && !config.agent) {
197
+ if (config.capabilities === undefined || config.capabilities === null) {
198
+ throw new Error("Discovery config requires 'capabilities' when using legacy 'service' config");
199
+ }
200
+ if (!config.endpoints?.envelope) {
201
+ throw new Error("Discovery config requires 'endpoints.envelope' when using legacy 'service' config");
202
+ }
203
+ }
204
+ // Cache serialized documents to ensure consistent ETags across GET/HEAD
205
+ let cachedPrimaryJson = null;
206
+ let cachedLegacyJson = null;
207
+ function getSerializedDoc(isLegacy, req) {
208
+ if (isLegacy) {
209
+ if (!cachedLegacyJson) {
210
+ cachedLegacyJson = JSON.stringify(buildLegacyDiscoveryDocument(config, req), null, 2);
211
+ }
212
+ return cachedLegacyJson;
213
+ }
214
+ if (!cachedPrimaryJson) {
215
+ cachedPrimaryJson = JSON.stringify(buildAgentCard(config, req), null, 2);
216
+ }
217
+ return cachedPrimaryJson;
195
218
  }
196
219
  return function discoveryHandler(req, res, next) {
197
- // Only handle requests to the discovery path
198
- if (req.path !== path) {
220
+ const isPrimaryPath = req.path === path;
221
+ const isLegacyPath = enableLegacyPath && req.path === legacyPath;
222
+ // Only handle requests to discovery paths
223
+ if (!isPrimaryPath && !isLegacyPath) {
199
224
  next();
200
225
  return;
201
226
  }
227
+ // Log deprecation warning for legacy path
228
+ if (isLegacyPath) {
229
+ console.warn(`[DEPRECATION] Accessing legacy discovery endpoint ${legacyPath}. ` +
230
+ `Migrate to ${path} for A2A v1.0+ compliance. Legacy support will be removed in v2.0.0.`);
231
+ }
202
232
  // Handle HEAD requests
203
233
  if (req.method === "HEAD") {
204
234
  if (!enableHead) {
@@ -208,23 +238,13 @@ export function discoveryMiddleware(config, options = {}) {
208
238
  });
209
239
  return;
210
240
  }
211
- // For HEAD, we still need to build the document to get the ETag
212
- const doc = buildDiscoveryDocument(config, req);
213
- const json = JSON.stringify(doc);
214
- // Generate stable ETag from config hash (not request-dependent document)
215
- const configHash = generateETag(JSON.stringify({
216
- schemaUrl: config.schemaUrl,
217
- lafsVersion: config.lafsVersion,
218
- service: config.service,
219
- capabilities: config.capabilities,
220
- endpoints: config.endpoints,
221
- cacheMaxAge: config.cacheMaxAge
222
- }));
223
- const etag = enableEtag ? configHash : undefined;
241
+ const json = getSerializedDoc(isLegacyPath, req);
242
+ const etag = enableEtag ? generateETag(json) : undefined;
224
243
  res.set({
225
244
  "Content-Type": "application/json",
226
245
  "Cache-Control": `public, max-age=${cacheMaxAge}`,
227
246
  ...(etag && { "ETag": etag }),
247
+ ...(isLegacyPath && { "Deprecation": "true", "Sunset": "Sat, 31 Dec 2025 23:59:59 GMT" }),
228
248
  "Content-Length": Buffer.byteLength(json)
229
249
  });
230
250
  res.status(200).end();
@@ -239,23 +259,8 @@ export function discoveryMiddleware(config, options = {}) {
239
259
  return;
240
260
  }
241
261
  try {
242
- // Build discovery document
243
- const doc = buildDiscoveryDocument(config, req);
244
- // Validate against schema
245
- validateDocument(doc);
246
- // Serialize document
247
- const json = JSON.stringify(doc);
248
- // Generate ETag from config hash (stable) rather than request-dependent document
249
- // This ensures ETag is consistent across requests even when URLs are constructed from request
250
- const configHash = generateETag(JSON.stringify({
251
- schemaUrl: config.schemaUrl,
252
- lafsVersion: config.lafsVersion,
253
- service: config.service,
254
- capabilities: config.capabilities,
255
- endpoints: config.endpoints,
256
- cacheMaxAge: config.cacheMaxAge
257
- }));
258
- const etag = enableEtag ? configHash : undefined;
262
+ const json = getSerializedDoc(isLegacyPath, req);
263
+ const etag = enableEtag ? generateETag(json) : undefined;
259
264
  // Check If-None-Match for conditional request
260
265
  if (enableEtag && req.headers["if-none-match"] === etag) {
261
266
  res.status(304).end();
@@ -270,6 +275,12 @@ export function discoveryMiddleware(config, options = {}) {
270
275
  if (etag) {
271
276
  headers["ETag"] = etag;
272
277
  }
278
+ // Add deprecation headers for legacy path
279
+ if (isLegacyPath) {
280
+ headers["Deprecation"] = "true";
281
+ headers["Sunset"] = "Sat, 31 Dec 2025 23:59:59 GMT";
282
+ headers["Link"] = `<${buildUrl(config.baseUrl, path, req)}>; rel="successor-version"`;
283
+ }
273
284
  res.set(headers);
274
285
  res.status(200).send(json);
275
286
  }
@@ -279,18 +290,17 @@ export function discoveryMiddleware(config, options = {}) {
279
290
  };
280
291
  }
281
292
  /**
282
- * Fastify plugin for LAFS discovery (for Fastify users)
293
+ * Fastify plugin for A2A Agent Card discovery
283
294
  *
284
295
  * @param fastify - Fastify instance
285
296
  * @param options - Plugin options
286
297
  */
287
298
  export async function discoveryFastifyPlugin(fastify, options) {
288
- const path = options.path || "/.well-known/lafs.json";
299
+ const path = options.path || "/.well-known/agent-card.json";
289
300
  const config = options.config;
290
301
  const cacheMaxAge = config.cacheMaxAge || 3600;
291
302
  const handler = async (request, reply) => {
292
- const doc = buildDiscoveryDocument(config, request.raw);
293
- validateDocument(doc);
303
+ const doc = buildAgentCard(config, request.raw);
294
304
  const json = JSON.stringify(doc);
295
305
  const etag = generateETag(json);
296
306
  reply.header("Content-Type", "application/json");
@@ -301,4 +311,32 @@ export async function discoveryFastifyPlugin(fastify, options) {
301
311
  // Note: Actual route registration depends on Fastify's API
302
312
  // This is a type-safe signature for the plugin
303
313
  }
314
+ // ============================================================================
315
+ // Breaking Changes Documentation
316
+ // ============================================================================
317
+ /**
318
+ * BREAKING CHANGES v1.2.3 → v2.0.0:
319
+ *
320
+ * 1. Discovery Endpoint Path
321
+ * - OLD: /.well-known/lafs.json
322
+ * - NEW: /.well-known/agent-card.json
323
+ * - MIGRATION: Update client code to use new path
324
+ * - BACKWARD COMPAT: Legacy path still works but logs deprecation warning
325
+ *
326
+ * 2. Discovery Document Format
327
+ * - OLD: DiscoveryDocument interface (lafs_version, service, capabilities, endpoints)
328
+ * - NEW: AgentCard interface (A2A v1.0 compliant)
329
+ * - MIGRATION: Update config from 'service' to 'agent' format
330
+ * - BACKWARD COMPAT: Legacy config format automatically converted with warning
331
+ *
332
+ * 3. Type Names
333
+ * - Capability → AgentSkill (renamed to align with A2A spec)
334
+ * - ServiceConfig → AgentCard (renamed)
335
+ * - All old types marked as @deprecated
336
+ *
337
+ * 4. Removed in v2.0.0
338
+ * - Legacy path support will be removed
339
+ * - Old type definitions will be removed
340
+ * - Automatic config migration will be removed
341
+ */
304
342
  export default discoveryMiddleware;
@@ -10,4 +10,6 @@ export * from "./discovery.js";
10
10
  export * from "./health/index.js";
11
11
  export * from "./shutdown/index.js";
12
12
  export * from "./circuit-breaker/index.js";
13
- export * from "./a2a/index.js";
13
+ export { LafsA2AResult, createLafsArtifact, createTextArtifact, createFileArtifact, isExtensionRequired, getExtensionParams, AGENT_CARD_PATH, HTTP_EXTENSION_HEADER, LAFS_EXTENSION_URI, A2A_EXTENSIONS_HEADER, parseExtensionsHeader, negotiateExtensions, formatExtensionsHeader, buildLafsExtension, ExtensionSupportRequiredError, extensionNegotiationMiddleware, TERMINAL_STATES, INTERRUPTED_STATES, VALID_TRANSITIONS, isValidTransition, isTerminalState, isInterruptedState, InvalidStateTransitionError, TaskImmutabilityError, TaskNotFoundError, TaskManager, attachLafsEnvelope, } from "./a2a/index.js";
14
+ export type { LafsA2AConfig, LafsSendMessageParams, LafsExtensionParams, ExtensionNegotiationResult, BuildLafsExtensionOptions, ExtensionNegotiationMiddlewareOptions, CreateTaskOptions, ListTasksOptions, ListTasksResult, } from "./a2a/index.js";
15
+ export type { Task, TaskState, TaskStatus, Artifact, Part, Message, PushNotificationConfig, MessageSendConfiguration, TaskStatusUpdateEvent, TaskArtifactUpdateEvent, SendMessageResponse, SendMessageSuccessResponse, JSONRPCErrorResponse, TextPart, DataPart, FilePart, } from "./a2a/index.js";
package/dist/src/index.js CHANGED
@@ -12,4 +12,13 @@ export * from "./health/index.js";
12
12
  export * from "./shutdown/index.js";
13
13
  export * from "./circuit-breaker/index.js";
14
14
  // A2A Integration
15
- export * from "./a2a/index.js";
15
+ // Explicitly re-export to avoid naming conflicts with discovery types
16
+ // (AgentCard, AgentSkill, AgentCapabilities, AgentExtension).
17
+ // For full A2A types, import from '@cleocode/lafs-protocol/a2a'.
18
+ export {
19
+ // Bridge
20
+ LafsA2AResult, createLafsArtifact, createTextArtifact, createFileArtifact, isExtensionRequired, getExtensionParams,
21
+ // Extensions (T098)
22
+ LAFS_EXTENSION_URI, A2A_EXTENSIONS_HEADER, parseExtensionsHeader, negotiateExtensions, formatExtensionsHeader, buildLafsExtension, ExtensionSupportRequiredError, extensionNegotiationMiddleware,
23
+ // Task Lifecycle (T099)
24
+ TERMINAL_STATES, INTERRUPTED_STATES, VALID_TRANSITIONS, isValidTransition, isTerminalState, isInterruptedState, InvalidStateTransitionError, TaskImmutabilityError, TaskNotFoundError, TaskManager, attachLafsEnvelope, } from "./a2a/index.js";
package/lafs.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # LAFS: LLM-Agent-First Specification
2
2
 
3
3
  > 📚 **Documentation:** https://codluv.gitbook.io/lafs-protocol/
4
- > **Version:** 1.2.3 | **Status:** Production Ready
4
+ > **Version:** 1.3.1 | **Status:** Production Ready
5
5
 
6
6
  ## 1. Scope
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/lafs-protocol",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "LLM-Agent-First Specification schemas and conformance tooling",
@@ -10,6 +10,18 @@
10
10
  ".": {
11
11
  "import": "./dist/src/index.js",
12
12
  "types": "./dist/src/index.d.ts"
13
+ },
14
+ "./discovery": {
15
+ "import": "./dist/src/discovery.js",
16
+ "types": "./dist/src/discovery.d.ts"
17
+ },
18
+ "./a2a": {
19
+ "import": "./dist/src/a2a/index.js",
20
+ "types": "./dist/src/a2a/index.d.ts"
21
+ },
22
+ "./a2a/bindings": {
23
+ "import": "./dist/src/a2a/bindings/index.js",
24
+ "types": "./dist/src/a2a/bindings/index.d.ts"
13
25
  }
14
26
  },
15
27
  "files": [