@ottocode/server 0.1.259 → 0.1.260

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": "@ottocode/server",
3
- "version": "0.1.259",
3
+ "version": "0.1.260",
4
4
  "description": "HTTP API server for ottocode",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -61,8 +61,8 @@
61
61
  "typecheck": "tsc --noEmit"
62
62
  },
63
63
  "dependencies": {
64
- "@ottocode/database": "0.1.259",
65
- "@ottocode/sdk": "0.1.259",
64
+ "@ottocode/database": "0.1.260",
65
+ "@ottocode/sdk": "0.1.260",
66
66
  "ai-sdk-ollama": "^3.8.3",
67
67
  "drizzle-orm": "^0.44.5",
68
68
  "hono": "^4.9.9",
@@ -27,7 +27,7 @@ export async function handleReasoningStart(
27
27
  reasoningId: string,
28
28
  providerMetadata: unknown,
29
29
  opts: RunOpts,
30
- _db: Awaited<ReturnType<typeof getDb>>,
30
+ db: Awaited<ReturnType<typeof getDb>>,
31
31
  sharedCtx: ToolAdapterContext,
32
32
  getStepIndex: () => number,
33
33
  reasoningStates: Map<string, ReasoningState>,
@@ -43,6 +43,22 @@ export async function handleReasoningStart(
43
43
  getStepIndex,
44
44
  };
45
45
  reasoningStates.set(reasoningId, state);
46
+
47
+ if (hasAnthropicRedactedReasoning(providerMetadata)) {
48
+ const delta = '[Reasoning redacted by Anthropic]\n';
49
+ state.text = delta;
50
+ await persistReasoningPart(state, db);
51
+ publish({
52
+ type: 'reasoning.delta',
53
+ sessionId: opts.sessionId,
54
+ payload: {
55
+ messageId: opts.assistantMessageId,
56
+ partId: state.partId,
57
+ stepIndex: getStepIndex(),
58
+ delta,
59
+ },
60
+ });
61
+ }
46
62
  }
47
63
 
48
64
  async function persistReasoningPart(
@@ -73,11 +89,23 @@ export async function handleReasoningDelta(
73
89
  providerMetadata: unknown,
74
90
  opts: RunOpts,
75
91
  db: Awaited<ReturnType<typeof getDb>>,
92
+ sharedCtx: ToolAdapterContext,
76
93
  getStepIndex: () => number,
77
94
  reasoningStates: Map<string, ReasoningState>,
78
95
  ): Promise<void> {
79
- const state = reasoningStates.get(reasoningId);
80
- if (!state) return;
96
+ let state = reasoningStates.get(reasoningId);
97
+ if (!state) {
98
+ state = {
99
+ partId: crypto.randomUUID(),
100
+ text: '',
101
+ providerMetadata,
102
+ persisted: false,
103
+ opts,
104
+ sharedCtx,
105
+ getStepIndex,
106
+ };
107
+ reasoningStates.set(reasoningId, state);
108
+ }
81
109
  state.text += text;
82
110
  if (providerMetadata != null) {
83
111
  state.providerMetadata = providerMetadata;
@@ -108,6 +136,13 @@ export async function handleReasoningDelta(
108
136
  } catch {}
109
137
  }
110
138
 
139
+ function hasAnthropicRedactedReasoning(providerMetadata: unknown): boolean {
140
+ if (!providerMetadata || typeof providerMetadata !== 'object') return false;
141
+ const anthropic = (providerMetadata as Record<string, unknown>).anthropic;
142
+ if (!anthropic || typeof anthropic !== 'object') return false;
143
+ return 'redactedData' in anthropic;
144
+ }
145
+
111
146
  export async function handleReasoningEnd(
112
147
  reasoningId: string,
113
148
  db: Awaited<ReturnType<typeof getDb>>,
@@ -680,6 +680,7 @@ async function runAssistant(opts: RunOpts) {
680
680
  part.providerMetadata,
681
681
  opts,
682
682
  db,
683
+ sharedCtx,
683
684
  getStepIndex,
684
685
  reasoningStates,
685
686
  );
@@ -27,8 +27,9 @@ function normalizeReasoningLevel(
27
27
  }
28
28
 
29
29
  function toAnthropicEffort(
30
+ model: string,
30
31
  level: ReasoningLevel | undefined,
31
- ): 'low' | 'medium' | 'high' | 'max' {
32
+ ): 'low' | 'medium' | 'high' | 'xhigh' | 'max' {
32
33
  switch (level) {
33
34
  case 'minimal':
34
35
  case 'low':
@@ -36,8 +37,9 @@ function toAnthropicEffort(
36
37
  case 'medium':
37
38
  return 'medium';
38
39
  case 'max':
39
- case 'xhigh':
40
40
  return 'max';
41
+ case 'xhigh':
42
+ return isClaudeOpus47(model) ? 'xhigh' : 'max';
41
43
  default:
42
44
  return 'high';
43
45
  }
@@ -134,11 +136,15 @@ function buildSharedProviderOptions(
134
136
  return Object.fromEntries(keys.map((key) => [key, options]));
135
137
  }
136
138
 
139
+ function isClaudeOpus47(model: string): boolean {
140
+ const lower = model.toLowerCase();
141
+ return lower.includes('claude-opus-4-7') || lower.includes('claude-opus-4.7');
142
+ }
143
+
137
144
  function usesAdaptiveAnthropicThinking(model: string): boolean {
138
145
  const lower = model.toLowerCase();
139
146
  return (
140
- lower.includes('claude-opus-4-7') ||
141
- lower.includes('claude-opus-4.7') ||
147
+ isClaudeOpus47(model) ||
142
148
  lower.includes('claude-opus-4-6') ||
143
149
  lower.includes('claude-opus-4.6') ||
144
150
  lower.includes('claude-sonnet-4-6') ||
@@ -238,11 +244,15 @@ export function buildReasoningConfig(args: {
238
244
  const reasoningTarget = getReasoningProviderTarget(provider, model, cfg);
239
245
  if (reasoningTarget === 'anthropic') {
240
246
  if (usesAdaptiveAnthropicThinking(model)) {
247
+ const thinking = isClaudeOpus47(model)
248
+ ? { type: 'adaptive', display: 'summarized' }
249
+ : { type: 'adaptive' };
250
+
241
251
  return {
242
252
  providerOptions: {
243
253
  anthropic: {
244
- thinking: { type: 'adaptive' },
245
- effort: toAnthropicEffort(reasoningLevel),
254
+ thinking,
255
+ effort: toAnthropicEffort(model, reasoningLevel),
246
256
  },
247
257
  },
248
258
  effectiveMaxOutputTokens: maxOutputTokens,