@springbrand/agent-runtime 0.2.0-alpha.70 → 0.2.0-alpha.72

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/agent-runtime",
3
- "version": "0.2.0-alpha.70",
3
+ "version": "0.2.0-alpha.72",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -550,6 +550,14 @@ function projectedTool(
550
550
  approval?: PiToolApprovalView,
551
551
  ): DynamicToolUIPart {
552
552
  const input = safeInput(call.arguments);
553
+ if (call.name === "ask_user" && typeof input.questions === "string") {
554
+ try {
555
+ const questions: unknown = JSON.parse(input.questions);
556
+ if (Array.isArray(questions)) input.questions = questions;
557
+ } catch {
558
+ // Preserve malformed legacy input for the normal unavailable state.
559
+ }
560
+ }
553
561
  const base = {
554
562
  type: "dynamic-tool" as const,
555
563
  toolCallId: call.id,
@@ -32,7 +32,6 @@ import {
32
32
  codeExecutionPiToolCandidate,
33
33
  compilePiTools,
34
34
  createPiToolGovernance,
35
- normalizeUpdatePlanArguments,
36
35
  type PiToolCandidate,
37
36
  type PiToolInteractionSpec,
38
37
  type PiToolGovernance,
@@ -87,11 +86,35 @@ export class RetryableModelSessionError extends RetryableModelError {}
87
86
 
88
87
  export class ContextOverflowError extends RetryableModelError {}
89
88
 
90
- function normalizePlanToolCalls(message: AgentMessage): void {
89
+ function prepareToolArguments(
90
+ toolName: string,
91
+ input: unknown,
92
+ candidates: readonly PiToolCandidate[],
93
+ ): unknown {
94
+ const prepare = candidates.find(({ tool }) => tool.name === toolName)
95
+ ?.tool.prepareArguments;
96
+ if (!prepare) return input;
97
+ try {
98
+ return prepare(input);
99
+ } catch {
100
+ // Streaming inputs may still be incomplete. Preserve them so Pi can
101
+ // produce the normal validation ToolResult once the call is final.
102
+ return input;
103
+ }
104
+ }
105
+
106
+ function normalizeToolCallArguments(
107
+ message: AgentMessage,
108
+ candidates: readonly PiToolCandidate[],
109
+ ): void {
91
110
  if (message.role !== "assistant") return;
92
111
  for (const part of message.content) {
93
- if (part.type === "toolCall" && part.name === "update_plan") {
94
- part.arguments = normalizeUpdatePlanArguments(part.arguments);
112
+ if (part.type === "toolCall") {
113
+ part.arguments = prepareToolArguments(
114
+ part.name,
115
+ part.arguments,
116
+ candidates,
117
+ ) as Record<string, unknown>;
95
118
  }
96
119
  }
97
120
  }
@@ -1011,7 +1034,18 @@ export class PreparedPiTurnAdapter {
1011
1034
  event.type === "message_update" ||
1012
1035
  event.type === "message_end"
1013
1036
  ) {
1014
- normalizePlanToolCalls(event.message);
1037
+ normalizeToolCallArguments(event.message, this.candidates);
1038
+ }
1039
+ if (
1040
+ event.type === "message_update" &&
1041
+ event.assistantMessageEvent.type === "toolcall_end"
1042
+ ) {
1043
+ const call = event.assistantMessageEvent.toolCall;
1044
+ call.arguments = prepareToolArguments(
1045
+ call.name,
1046
+ call.arguments,
1047
+ this.candidates,
1048
+ ) as Record<string, unknown>;
1015
1049
  }
1016
1050
  if (
1017
1051
  event.type === "message_update" &&
@@ -743,6 +743,8 @@ function configuredModel(
743
743
  ? {
744
744
  compat: {
745
745
  ...anthropicMessagesCompat,
746
+ // OpenRouter rejects Anthropic's mid-conversation effort messages and block binding.
747
+ supportsMidConvoEffort: false,
746
748
  supportsEagerToolInputStreaming: false,
747
749
  supportsStrictTools:
748
750
  anthropicMessagesCompat?.supportsStrictTools ?? false,