osborn 0.5.2 → 0.5.3

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.
@@ -452,14 +452,25 @@ class ClaudeLLMStream extends llm.LLMStream {
452
452
  // Research mode system prompt — always injected
453
453
  systemPrompt: getResearchSystemPrompt(workspacePath),
454
454
  canUseTool: async (toolName, input, _options) => {
455
- // Auto-approve writes to session workspace
455
+ // Auto-approve writes to session workspace (but block spec.md and library/ — fast brain manages those)
456
456
  if (toolName === 'Write' || toolName === 'Edit') {
457
457
  const filePath = String(input?.file_path || '');
458
458
  if (filePath.includes('.osborn/sessions/') || filePath.includes('.osborn/research/')) {
459
+ // Block writes to spec.md and library/ — the fast brain manages these
460
+ const fileName = filePath.split('/').pop() || '';
461
+ if (fileName === 'spec.md' || filePath.includes('/library/')) {
462
+ console.log(`🚫 Blocked research agent write to managed file: ${filePath} (fast brain handles spec.md and library/)`);
463
+ return { behavior: 'deny', message: 'spec.md and library/ are managed by the fast brain sub-agent. Do NOT write to them. Return your findings in your response text — the fast brain will organize them into spec.md and library/ automatically.' };
464
+ }
459
465
  console.log(`✅ Auto-approved ${toolName} to workspace: ${filePath}`);
460
466
  return { behavior: 'allow', updatedInput: input };
461
467
  }
462
468
  }
469
+ // Auto-approve AskUserQuestion — research agent should freely ask clarifying questions
470
+ if (toolName === 'AskUserQuestion') {
471
+ console.log(`✅ Auto-approved ${toolName}`);
472
+ return { behavior: 'allow', updatedInput: input };
473
+ }
463
474
  // Auto-deny tools the research agent should never use
464
475
  if (toolName === 'EnterPlanMode' || toolName === 'ExitPlanMode') {
465
476
  console.log(`🚫 Auto-denied ${toolName} (not used in research mode)`);
package/dist/config.d.ts CHANGED
@@ -245,7 +245,7 @@ export declare function listLibraryFiles(projectPath: string, sessionId: string)
245
245
  export interface ResearchArtifact {
246
246
  fileName: string;
247
247
  filePath: string;
248
- type: 'plan' | 'diagram' | 'notes' | 'image' | 'summary' | 'other';
248
+ type: 'plan' | 'diagram' | 'notes' | 'image' | 'summary' | 'html' | 'other';
249
249
  size: number;
250
250
  updatedAt: string;
251
251
  }
package/dist/config.js CHANGED
@@ -842,6 +842,8 @@ function classifyFile(fileName) {
842
842
  return 'plan';
843
843
  if (ext === 'mmd' || ext === 'mermaid')
844
844
  return 'diagram';
845
+ if (ext === 'html' || ext === 'htm')
846
+ return 'html';
845
847
  if (ext === 'md')
846
848
  return 'notes';
847
849
  if (['png', 'jpg', 'jpeg', 'svg', 'gif', 'webp'].includes(ext))
@@ -26,6 +26,13 @@
26
26
  * Returns null for tools with no useful content (Write confirmations, etc.)
27
27
  */
28
28
  export declare function extractToolContent(toolName: string, toolInput: any, toolResponse: any): string | null;
29
+ /** A single voice conversation turn from the realtime LLM's chatCtx */
30
+ export interface ConversationTurn {
31
+ role: 'user' | 'assistant';
32
+ text: string;
33
+ }
34
+ /** No-op — history is now sourced live from agent.chatCtx, passed per-call */
35
+ export declare function clearFastBrainHistory(): void;
29
36
  /**
30
37
  * Ask the fast brain a question with access to session files and web search.
31
38
  * Returns an answer or "NEEDS_DEEPER_RESEARCH: ..." for escalation.
@@ -35,7 +42,7 @@ export declare function extractToolContent(toolName: string, toolInput: any, too
35
42
  * @param researchContext - Optional snapshot of the live research log.
36
43
  * ~2 second response time for most queries.
37
44
  */
38
- export declare function askHaiku(workingDir: string, sessionId: string, question: string, researchContext?: string): Promise<string>;
45
+ export declare function askHaiku(workingDir: string, sessionId: string, question: string, researchContext?: string, chatHistory?: ConversationTurn[]): Promise<string>;
39
46
  /**
40
47
  * Process a batch of research content chunks through the fast brain.
41
48
  * Updates spec.md and library/ files incrementally during research.
@@ -46,6 +53,14 @@ export declare function processResearchChunk(workingDir: string, sessionId: stri
46
53
  spec: string | null;
47
54
  libraryFiles: string[];
48
55
  } | null>;
56
+ /**
57
+ * Augment agent SDK research results with context from spec.md.
58
+ * Passes ALL specific details through verbatim — only ADDS context annotations.
59
+ * The voice model downstream handles summarization for speech.
60
+ *
61
+ * Falls back to returning the original result if the fast brain is unavailable.
62
+ */
63
+ export declare function augmentResearchResult(workingDir: string, sessionId: string, task: string, agentResult: string): Promise<string>;
49
64
  /**
50
65
  * Update spec.md and library/ files after research completes.
51
66
  * Reads FULL untruncated data directly from Claude Agent SDK JSONL files
@@ -62,3 +77,46 @@ export declare function updateSpecFromJSONL(workingDir: string, sessionId: strin
62
77
  spec: string | null;
63
78
  libraryFiles: string[];
64
79
  } | null>;
80
+ /**
81
+ * Fire-and-forget: Write a user question to spec.md Open Questions > From User
82
+ * before the agent starts researching. Ensures every escalated question is tracked.
83
+ *
84
+ * Uses a simple LLM call to fuzzy-match existing questions and avoid duplicates.
85
+ * Skips if spec.md doesn't exist yet or no provider is available.
86
+ */
87
+ export declare function writeQuestionToSpec(workingDir: string, sessionId: string, question: string): Promise<void>;
88
+ /**
89
+ * Fire-and-forget: Check if substantial agent output answers any open questions in spec.md.
90
+ * Debounced (3s) to prevent flooding during rapid tool_result sequences.
91
+ *
92
+ * When a question is answered, marks it with [x] and moves the answer to Findings.
93
+ */
94
+ export declare function checkOutputAgainstQuestions(workingDir: string, sessionId: string, output: string, outputType: 'tool_result' | 'assistant_text'): Promise<void>;
95
+ /**
96
+ * Generate a natural, contextualized voice update from raw research events.
97
+ * Called by scheduleResearchBatch() instead of injecting raw events directly.
98
+ *
99
+ * Returns a natural 1-2 sentence update, or null if nothing interesting to say.
100
+ * 3-second timeout — returns null if the LLM is too slow.
101
+ */
102
+ export declare function contextualizeResearchUpdate(workingDir: string, sessionId: string, task: string, batchEvents: string[], researchLog: string[]): Promise<string | null>;
103
+ /**
104
+ * Generate a proactive conversational prompt to keep the user engaged during research.
105
+ * Called periodically (every 15s) during active research.
106
+ *
107
+ * Can ask open questions, discuss implications of findings, or give progress with depth.
108
+ * Returns null/NOTHING if nothing interesting to say.
109
+ * 3-second timeout.
110
+ */
111
+ export declare function generateProactivePrompt(workingDir: string, sessionId: string, task: string, researchLog: string[], previousPrompts: string[]): Promise<string | null>;
112
+ /**
113
+ * Generate a structured visual document (comparison table, Mermaid diagram,
114
+ * analysis, or summary) from research findings.
115
+ *
116
+ * Reads spec.md, JSONL results, and library for context.
117
+ * Writes the result to library/ and returns the filename + content.
118
+ */
119
+ export declare function generateVisualDocument(workingDir: string, sessionId: string, request: string, documentType: 'comparison' | 'diagram' | 'analysis' | 'summary'): Promise<{
120
+ fileName: string;
121
+ content: string;
122
+ } | null>;