@kindgi/handler-runtime 0.1.2 → 0.1.4-rc.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.
@@ -119,7 +119,15 @@ export function createPackService(options: PackServiceOptions): PackService {
119
119
  options.importModule ?? ((p: string) => import(pathToFileURL(p).href) as Promise<unknown>);
120
120
  const expectedToken = Buffer.from(options.token);
121
121
 
122
- const tools = new Map<string, IndexedTool>(options.index.tools.map((t) => [t.id, t]));
122
+ // Every version of a tool the pack holds, side by side: one agent version
123
+ // may pin tool@1 while another pins tool@2 (keyed by id and version).
124
+ const tools = new Map<string, IndexedTool>(
125
+ options.index.tools.map((t) => [toolKey(t.id, t.version), t]),
126
+ );
127
+ const versionsOf = new Map<string, IndexedTool[]>();
128
+ for (const t of options.index.tools) {
129
+ versionsOf.set(t.id, [...(versionsOf.get(t.id) ?? []), t]);
130
+ }
123
131
  const checks = new Map<string, IndexedGuardrail>(
124
132
  options.index.guardrails.map((g) => [g.checkId ?? g.id, g]),
125
133
  );
@@ -197,24 +205,44 @@ export function createPackService(options: PackServiceOptions): PackService {
197
205
  };
198
206
  }
199
207
 
200
- function callTool(message: ToolInvokeMessage, signal: AbortSignal): Promise<PackResponse> {
201
- const tool = tools.get(message.tool.id);
202
- if (tool === undefined) {
203
- return Promise.resolve(
204
- packError('tool-not-in-pack', `This pack has no tool "${message.tool.id}"`, {
205
- toolId: message.tool.id,
208
+ /**
209
+ * The tool version a call asks for: that version, or, when it names
210
+ * none, the tool's only version in the pack.
211
+ */
212
+ function toolFor(
213
+ ref: ToolInvokeMessage['tool'],
214
+ ): { readonly tool: IndexedTool } | { readonly refused: PackResponse } {
215
+ const versions = versionsOf.get(ref.id) ?? [];
216
+ if (versions.length === 0) {
217
+ return {
218
+ refused: packError('tool-not-in-pack', `This pack has no tool "${ref.id}"`, {
219
+ toolId: ref.id,
206
220
  }),
207
- );
208
- }
209
- if (message.tool.version !== undefined && message.tool.version !== tool.version) {
210
- return Promise.resolve(
211
- packError(
212
- 'tool-version-mismatch',
213
- `Tool "${tool.id}" is ${tool.version ?? 'unversioned'} in this pack; the caller asked for ${message.tool.version}`,
214
- { toolId: tool.id },
215
- ),
216
- );
221
+ };
217
222
  }
223
+ const have = versions.map((t) => t.version ?? 'unversioned').join(', ');
224
+ const tool =
225
+ ref.version === undefined
226
+ ? versions.length === 1
227
+ ? versions[0]
228
+ : undefined
229
+ : tools.get(toolKey(ref.id, ref.version));
230
+ if (tool !== undefined) return { tool };
231
+ return {
232
+ refused: packError(
233
+ 'tool-version-mismatch',
234
+ ref.version === undefined
235
+ ? `Tool "${ref.id}" has several versions in this pack (${have}); the caller named none`
236
+ : `Tool "${ref.id}" is ${have} in this pack; the caller asked for ${ref.version}`,
237
+ { toolId: ref.id },
238
+ ),
239
+ };
240
+ }
241
+
242
+ function callTool(message: ToolInvokeMessage, signal: AbortSignal): Promise<PackResponse> {
243
+ const found = toolFor(message.tool);
244
+ if ('refused' in found) return Promise.resolve(found.refused);
245
+ const { tool } = found;
218
246
  return runHandler({
219
247
  tool: {
220
248
  id: tool.id,
@@ -476,3 +504,8 @@ function sendJson(
476
504
  function describe(cause: unknown): string {
477
505
  return cause instanceof Error ? cause.message : String(cause);
478
506
  }
507
+
508
+ /** A tool's key in the pack: its id and version (an unversioned tool, by id alone). */
509
+ function toolKey(id: string, version: string | undefined): string {
510
+ return version === undefined ? id : `${id}@${version}`;
511
+ }
package/src/protocol.ts CHANGED
@@ -26,11 +26,17 @@ export interface PackCallContext {
26
26
  readonly tenantId: string;
27
27
  /** The kernel run this call belongs to. */
28
28
  readonly runId: string;
29
+ /** The run's project: set by the runtime from the run, never from input (protocol 2.3.0). */
30
+ readonly projectId?: string;
31
+ /** That project's org, when it has one; from the project, never from input (2.3.0). */
32
+ readonly orgId?: string;
29
33
  /** The individual call — e.g. the model's tool-call id. */
30
34
  readonly requestId?: string;
31
35
  readonly env?: Readonly<Record<string, unknown>>;
32
36
  readonly secrets?: Readonly<Record<string, unknown>>;
33
37
  readonly config?: Readonly<Record<string, unknown>>;
38
+ /** The calling agent version's settings blocks' values, by block id (protocol 2.4.0). */
39
+ readonly settings?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
34
40
  }
35
41
 
36
42
  export interface ToolRef {