pi-harness-runtime 1.1.341 → 1.1.343

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.
Files changed (129) hide show
  1. package/README.md +127 -0
  2. package/harness/notification-center.ts +363 -0
  3. package/index.ts +111 -15
  4. package/package.json +1 -1
  5. package/packages/a2a-adapter/package.json +1 -1
  6. package/packages/agent-policy/package.json +1 -1
  7. package/packages/architecture-generator/package.json +1 -1
  8. package/packages/auth/package.json +1 -1
  9. package/packages/autonomous-refactor/package.json +1 -1
  10. package/packages/autonomous-runtime/package.json +1 -1
  11. package/packages/cache-strategy/package.json +1 -1
  12. package/packages/capability-registry/package.json +1 -1
  13. package/packages/checkpoint/package.json +1 -1
  14. package/packages/cli-plugin-sdk/package.json +1 -1
  15. package/packages/clipboard/package.json +1 -1
  16. package/packages/clipboard-plugin/package.json +1 -1
  17. package/packages/code-generation/package.json +1 -1
  18. package/packages/code-review/package.json +1 -1
  19. package/packages/codex-adapter/package.json +1 -1
  20. package/packages/codex-watcher/package.json +1 -1
  21. package/packages/config-capture/package.json +1 -1
  22. package/packages/connection-runtime/package.json +1 -1
  23. package/packages/context-compiler/package.json +1 -1
  24. package/packages/context-discovery/package.json +1 -1
  25. package/packages/context-manager/package.json +1 -1
  26. package/packages/contracts/package.json +1 -1
  27. package/packages/cookie-sanitizer/package.json +1 -1
  28. package/packages/cost-optimizer/package.json +1 -1
  29. package/packages/dependency-analyzer/package.json +1 -1
  30. package/packages/django-plugin/package.json +1 -1
  31. package/packages/doc-generator/package.json +1 -1
  32. package/packages/durable-review/package.json +1 -1
  33. package/packages/e2e-tester/package.json +1 -1
  34. package/packages/evaluation-engine/package.json +1 -1
  35. package/packages/evaluation-runner/package.json +1 -1
  36. package/packages/event-bus/package.json +1 -1
  37. package/packages/event-sink/package.json +1 -1
  38. package/packages/event-store/package.json +1 -1
  39. package/packages/experience-replay/package.json +1 -1
  40. package/packages/feedback-collector/package.json +1 -1
  41. package/packages/file-copy-helper/package.json +1 -1
  42. package/packages/framework-detector/package.json +1 -1
  43. package/packages/framework-plugin-sdk/package.json +1 -1
  44. package/packages/frappe-plugin/package.json +1 -1
  45. package/packages/generic-web-plugin/package.json +1 -1
  46. package/packages/health-monitor/package.json +1 -1
  47. package/packages/intent-analyzer/package.json +1 -1
  48. package/packages/jev-judge/package.json +1 -1
  49. package/packages/knowledge-graph/package.json +1 -1
  50. package/packages/knowledge-retrieval/package.json +1 -1
  51. package/packages/laravel-plugin/package.json +1 -1
  52. package/packages/learning-engine/package.json +1 -1
  53. package/packages/mcp-adapter/package.json +1 -1
  54. package/packages/memory-engine/package.json +1 -1
  55. package/packages/milestone-manager/package.json +1 -1
  56. package/packages/model-registry/package.json +1 -1
  57. package/packages/nextjs-plugin/package.json +1 -1
  58. package/packages/notification/dist/notification-center.d.ts +13 -0
  59. package/packages/notification/dist/notification-center.d.ts.map +1 -1
  60. package/packages/notification/dist/notification-center.js +24 -0
  61. package/packages/notification/dist/notification-center.js.map +1 -1
  62. package/packages/notification/dist/telegram-webhook-handler.d.ts +4 -0
  63. package/packages/notification/dist/telegram-webhook-handler.d.ts.map +1 -1
  64. package/packages/notification/dist/telegram-webhook-handler.js +4 -0
  65. package/packages/notification/dist/telegram-webhook-handler.js.map +1 -1
  66. package/packages/notification/package.json +1 -1
  67. package/packages/notification/src/notification-center.ts +40 -13
  68. package/packages/notification/src/telegram-webhook-handler.ts +4 -0
  69. package/packages/observability/package.json +1 -1
  70. package/packages/okf-indexer/package.json +1 -1
  71. package/packages/paperclip-integration/package.json +1 -1
  72. package/packages/performance-optimizer/package.json +1 -1
  73. package/packages/permission-mode/package.json +1 -1
  74. package/packages/privilege-broker/package.json +1 -1
  75. package/packages/project-analyzer/package.json +1 -1
  76. package/packages/project-bootstrap/package.json +1 -1
  77. package/packages/projection-engine/package.json +1 -1
  78. package/packages/prompt-compiler/package.json +1 -1
  79. package/packages/prompt-versioning/package.json +1 -1
  80. package/packages/provider-adapter-sdk/package.json +1 -1
  81. package/packages/provider-router/package.json +1 -1
  82. package/packages/provider-selector/package.json +1 -1
  83. package/packages/providers/package.json +1 -1
  84. package/packages/qdrant-skills/package.json +1 -1
  85. package/packages/quota-manager/package.json +1 -1
  86. package/packages/rate-limiter/package.json +1 -1
  87. package/packages/react-vite-plugin/package.json +1 -1
  88. package/packages/relay/package.json +1 -1
  89. package/packages/release-manager/package.json +1 -1
  90. package/packages/requirement-compiler/package.json +1 -1
  91. package/packages/runtime/package.json +1 -1
  92. package/packages/scheduler/package.json +1 -1
  93. package/packages/scheduler-adapter/package.json +1 -1
  94. package/packages/session/package.json +1 -1
  95. package/packages/session-api/package.json +1 -1
  96. package/packages/session-export/package.json +1 -1
  97. package/packages/shared-context/package.json +1 -1
  98. package/packages/skill-mcp-client/package.json +1 -1
  99. package/packages/skill-registry/package.json +1 -1
  100. package/packages/skills/package.json +1 -1
  101. package/packages/sprint-planner/package.json +1 -1
  102. package/packages/subscription-engine/package.json +1 -1
  103. package/packages/task-compiler/package.json +1 -1
  104. package/packages/telegram/package.json +1 -1
  105. package/packages/tencentdb-memory/package.json +1 -1
  106. package/packages/tencentdb-sync/package.json +1 -1
  107. package/packages/test-data-generator/package.json +1 -1
  108. package/packages/test-generator/package.json +1 -1
  109. package/packages/todo-bd-sync/package.json +1 -1
  110. package/packages/token-estimation/package.json +1 -1
  111. package/packages/token-optimizer/package.json +1 -1
  112. package/packages/trajectory/package.json +1 -1
  113. package/packages/tui/package.json +1 -1
  114. package/packages/types/package.json +1 -1
  115. package/packages/voice-api/dist/line.d.ts +2 -1
  116. package/packages/voice-api/dist/line.js +9 -6
  117. package/packages/voice-api/dist/telegram.js +8 -1
  118. package/packages/voice-api/dist/transcriber.d.ts +12 -41
  119. package/packages/voice-api/dist/transcriber.js +88 -108
  120. package/packages/voice-api/package.json +1 -1
  121. package/packages/voice-api/src/line.ts +11 -8
  122. package/packages/voice-api/src/telegram.ts +9 -1
  123. package/packages/voice-api/src/transcriber.ts +98 -122
  124. package/packages/webmcp-tester/package.json +1 -1
  125. package/packages/wiki/package.json +1 -1
  126. package/packages/workflow-events/package.json +1 -1
  127. package/packages/workspace-scanner/package.json +1 -1
  128. package/packages/worktree/package.json +1 -1
  129. package/packages/write-review/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/trajectory",
3
- "version": "1.1.341",
3
+ "version": "1.1.343",
4
4
  "description": "Trajectory capture for the write-review loop — persists cycle records for learning",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tui",
3
- "version": "1.1.341",
3
+ "version": "1.1.343",
4
4
  "description": "pi-harness-runtime — tui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/types",
3
- "version": "1.1.341",
3
+ "version": "1.1.343",
4
4
  "description": "Shared TypeScript types for pi-harness-runtime packages",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -58,13 +58,14 @@ export declare class LineVoiceHandler {
58
58
  private channelSecret?;
59
59
  private transcriber;
60
60
  private apiBase;
61
+ private dataApiBase;
61
62
  private onTranscribed?;
62
63
  private onError?;
63
64
  constructor(options: LineVoiceHandlerOptions);
64
65
  /**
65
66
  * Verify LINE webhook signature
66
67
  */
67
- verifySignature(body: string, signature: string): boolean;
68
+ verifySignature(_body: string, _signature: string): boolean;
68
69
  /**
69
70
  * Handle incoming webhook from LINE
70
71
  */
@@ -13,6 +13,7 @@ export class LineVoiceHandler {
13
13
  channelSecret;
14
14
  transcriber;
15
15
  apiBase;
16
+ dataApiBase;
16
17
  onTranscribed;
17
18
  onError;
18
19
  constructor(options) {
@@ -20,13 +21,14 @@ export class LineVoiceHandler {
20
21
  this.channelSecret = options.channelSecret;
21
22
  this.transcriber = options.transcriber;
22
23
  this.apiBase = options.apiBase || 'https://api.line.me';
24
+ this.dataApiBase = 'https://api-data.line.me'; // Content API is different
23
25
  this.onTranscribed = options.onTranscribed;
24
26
  this.onError = options.onError;
25
27
  }
26
28
  /**
27
29
  * Verify LINE webhook signature
28
30
  */
29
- verifySignature(body, signature) {
31
+ verifySignature(_body, _signature) {
30
32
  if (!this.channelSecret)
31
33
  return true; // Skip verification if no secret
32
34
  // Note: In production, implement proper HMAC verification
@@ -52,9 +54,7 @@ export class LineVoiceHandler {
52
54
  continue;
53
55
  }
54
56
  // Transcribe
55
- const result = await this.transcriber.transcribe({
56
- audioBuffer: audioContent,
57
- });
57
+ const result = await this.transcriber.transcribe(audioContent);
58
58
  if (result.error) {
59
59
  this.onError?.(userId, new Error(result.error));
60
60
  responses.push(`Transcription error: ${result.error}`);
@@ -77,18 +77,21 @@ export class LineVoiceHandler {
77
77
  */
78
78
  async getAudioContent(messageId) {
79
79
  try {
80
- const response = await fetch(`${this.apiBase}/v2/bot/message/${messageId}/content`, {
80
+ // Use data API for content retrieval
81
+ const response = await fetch(`${this.dataApiBase}/v2/bot/message/${messageId}/content`, {
81
82
  headers: {
82
83
  'Authorization': `Bearer ${this.channelAccessToken}`,
83
84
  },
84
85
  });
85
86
  if (!response.ok) {
87
+ console.error(`LINE API error: ${response.status} ${response.statusText}`);
86
88
  return null;
87
89
  }
88
90
  const arrayBuffer = await response.arrayBuffer();
89
91
  return new Uint8Array(arrayBuffer);
90
92
  }
91
- catch {
93
+ catch (error) {
94
+ console.error(`Failed to get audio content: ${error}`);
92
95
  return null;
93
96
  }
94
97
  }
@@ -39,8 +39,15 @@ export class TelegramVoiceHandler {
39
39
  }
40
40
  // Construct download URL
41
41
  const fileUrl = `${this.apiBase}/file/bot${this.botToken}/${filePath}`;
42
+ // Download audio file
43
+ const response = await fetch(fileUrl);
44
+ if (!response.ok) {
45
+ return { success: false, error: `Failed to download audio: ${response.status}` };
46
+ }
47
+ const arrayBuffer = await response.arrayBuffer();
48
+ const audioBuffer = new Uint8Array(arrayBuffer);
42
49
  // Transcribe
43
- const result = await this.transcriber.transcribe({ audioUrl: fileUrl });
50
+ const result = await this.transcriber.transcribe(audioBuffer);
44
51
  if (result.error) {
45
52
  this.onError?.(chatId, new Error(result.error));
46
53
  return { success: false, error: result.error };
@@ -1,48 +1,19 @@
1
1
  /**
2
- * Voice Transcriber - Main interface for speech-to-text
3
- */
4
- import type { TranscriptionResult, TranscribeOptions, VoiceApiConfig } from './types.js';
5
- import { WhisperProvider } from './provider.js';
6
- /**
7
- * Voice Transcriber
2
+ * OpenAI Whisper API Transcription
8
3
  *
9
- * Main interface for transcribing voice messages to text.
10
- * Supports multiple providers (OpenAI, Replicate).
4
+ * Transcribes audio using OpenAI's Whisper API.
11
5
  */
6
+ import type { TranscriptionResult } from './types.js';
7
+ export interface TranscriberOptions {
8
+ openaiApiKey: string;
9
+ model?: string;
10
+ }
12
11
  export declare class VoiceTranscriber {
13
- private providers;
14
- private defaultProvider;
15
- constructor(config?: VoiceApiConfig);
16
- /**
17
- * Check if transcriber is configured
18
- */
19
- isConfigured(): boolean;
20
- /**
21
- * Get configured providers
22
- */
23
- getProviders(): string[];
24
- /**
25
- * Get default provider
26
- */
27
- getDefaultProvider(): string | null;
12
+ private apiKey;
13
+ private model;
14
+ constructor(options: TranscriberOptions);
28
15
  /**
29
- * Transcribe audio to text
16
+ * Transcribe audio buffer using Whisper API
30
17
  */
31
- transcribe(options: TranscribeOptions): Promise<TranscriptionResult>;
32
- /**
33
- * Add a provider
34
- */
35
- addProvider(name: string, provider: WhisperProvider): void;
36
- /**
37
- * Remove a provider
38
- */
39
- removeProvider(name: string): boolean;
40
- /**
41
- * Set default provider
42
- */
43
- setDefaultProvider(name: string): boolean;
18
+ transcribe(audioBuffer: Uint8Array): Promise<TranscriptionResult>;
44
19
  }
45
- /**
46
- * Create a VoiceTranscriber from environment variables
47
- */
48
- export declare function createFromEnv(): VoiceTranscriber;
@@ -1,118 +1,98 @@
1
1
  /**
2
- * Voice Transcriber - Main interface for speech-to-text
3
- */
4
- import { createOpenAIProvider, createReplicateProvider } from './provider.js';
5
- /**
6
- * Voice Transcriber
2
+ * OpenAI Whisper API Transcription
7
3
  *
8
- * Main interface for transcribing voice messages to text.
9
- * Supports multiple providers (OpenAI, Replicate).
4
+ * Transcribes audio using OpenAI's Whisper API.
10
5
  */
6
+ import * as https from "https";
11
7
  export class VoiceTranscriber {
12
- providers = new Map();
13
- defaultProvider = '';
14
- constructor(config = {}) {
15
- // Initialize OpenAI provider
16
- if (config.openaiApiKey) {
17
- const provider = createOpenAIProvider(config.openaiApiKey);
18
- this.providers.set('openai', provider);
19
- this.defaultProvider = 'openai';
20
- }
21
- // Initialize Replicate provider
22
- if (config.replicateApiToken) {
23
- const provider = createReplicateProvider(config.replicateApiToken);
24
- this.providers.set('replicate', provider);
25
- if (!this.defaultProvider) {
26
- this.defaultProvider = 'replicate';
27
- }
28
- }
29
- // Set default provider from config
30
- if (config.provider && this.providers.has(config.provider)) {
31
- this.defaultProvider = config.provider;
32
- }
33
- }
34
- /**
35
- * Check if transcriber is configured
36
- */
37
- isConfigured() {
38
- return this.providers.size > 0;
39
- }
40
- /**
41
- * Get configured providers
42
- */
43
- getProviders() {
44
- return Array.from(this.providers.keys());
45
- }
46
- /**
47
- * Get default provider
48
- */
49
- getDefaultProvider() {
50
- return this.defaultProvider || null;
8
+ apiKey;
9
+ model;
10
+ constructor(options) {
11
+ this.apiKey = options.openaiApiKey;
12
+ this.model = options.model || "whisper-1";
51
13
  }
52
14
  /**
53
- * Transcribe audio to text
15
+ * Transcribe audio buffer using Whisper API
54
16
  */
55
- async transcribe(options) {
56
- const providerName = options.provider || this.defaultProvider;
57
- if (!providerName) {
58
- return {
59
- text: '',
60
- timestamp: new Date().toISOString(),
61
- provider: 'openai',
62
- error: 'No provider configured',
63
- };
64
- }
65
- const provider = this.providers.get(providerName);
66
- if (!provider) {
67
- return {
68
- text: '',
69
- timestamp: new Date().toISOString(),
70
- provider: providerName,
71
- error: `Provider ${providerName} not configured`,
17
+ async transcribe(audioBuffer) {
18
+ return new Promise((resolve) => {
19
+ const boundary = "----FormBoundary" + Math.random().toString(36).substring(2);
20
+ // Build multipart form data
21
+ const body = Buffer.concat([
22
+ Buffer.from(`--${boundary}\r\n`),
23
+ Buffer.from(`Content-Disposition: form-data; name="file"; filename="audio.m4a"\r\n`),
24
+ Buffer.from(`Content-Type: audio/x-m4a\r\n\r\n`),
25
+ Buffer.from(audioBuffer),
26
+ Buffer.from(`\r\n--${boundary}\r\n`),
27
+ Buffer.from(`Content-Disposition: form-data; name="model"\r\n\r\n`),
28
+ Buffer.from(`${this.model}\r\n`),
29
+ Buffer.from(`--${boundary}--\r\n`),
30
+ ]);
31
+ const options = {
32
+ hostname: "api.openai.com",
33
+ path: "/v1/audio/transcriptions",
34
+ method: "POST",
35
+ headers: {
36
+ "Authorization": `Bearer ${this.apiKey}`,
37
+ "Content-Type": `multipart/form-data; boundary=${boundary}`,
38
+ "Content-Length": body.length.toString(),
39
+ }
72
40
  };
73
- }
74
- return provider.transcribe(options);
41
+ const req = https.request(options, (res) => {
42
+ let data = "";
43
+ res.on("data", (chunk) => data += chunk);
44
+ res.on("end", () => {
45
+ if (res.statusCode !== 200) {
46
+ try {
47
+ const error = JSON.parse(data);
48
+ resolve({
49
+ text: "",
50
+ timestamp: new Date().toISOString(),
51
+ provider: 'openai',
52
+ error: error.error?.message || data
53
+ });
54
+ }
55
+ catch {
56
+ resolve({
57
+ text: "",
58
+ timestamp: new Date().toISOString(),
59
+ provider: 'openai',
60
+ error: data
61
+ });
62
+ }
63
+ return;
64
+ }
65
+ try {
66
+ const result = JSON.parse(data);
67
+ resolve({
68
+ text: result.text || "",
69
+ language: result.language,
70
+ duration: result.duration,
71
+ confidence: result.confidence,
72
+ timestamp: new Date().toISOString(),
73
+ provider: 'openai',
74
+ });
75
+ }
76
+ catch (e) {
77
+ resolve({
78
+ text: "",
79
+ timestamp: new Date().toISOString(),
80
+ provider: 'openai',
81
+ error: String(e)
82
+ });
83
+ }
84
+ });
85
+ });
86
+ req.on("error", (err) => {
87
+ resolve({
88
+ text: "",
89
+ timestamp: new Date().toISOString(),
90
+ provider: 'openai',
91
+ error: String(err)
92
+ });
93
+ });
94
+ req.write(body);
95
+ req.end();
96
+ });
75
97
  }
76
- /**
77
- * Add a provider
78
- */
79
- addProvider(name, provider) {
80
- this.providers.set(name, provider);
81
- if (!this.defaultProvider) {
82
- this.defaultProvider = name;
83
- }
84
- }
85
- /**
86
- * Remove a provider
87
- */
88
- removeProvider(name) {
89
- const deleted = this.providers.delete(name);
90
- if (this.defaultProvider === name) {
91
- this.defaultProvider = this.providers.keys().next().value || '';
92
- }
93
- return deleted;
94
- }
95
- /**
96
- * Set default provider
97
- */
98
- setDefaultProvider(name) {
99
- if (this.providers.has(name)) {
100
- this.defaultProvider = name;
101
- return true;
102
- }
103
- return false;
104
- }
105
- }
106
- /**
107
- * Create a VoiceTranscriber from environment variables
108
- */
109
- export function createFromEnv() {
110
- // SAFETY: globalThis.process is always available in Node.js
111
- const env = globalThis.process;
112
- const envVars = env?.env ?? {};
113
- return new VoiceTranscriber({
114
- openaiApiKey: envVars.OPENAI_API_KEY,
115
- replicateApiToken: envVars.REPLICATE_API_TOKEN,
116
- provider: envVars.VOICE_PROVIDER || 'openai',
117
- });
118
98
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/voice-api",
3
- "version": "1.1.341",
3
+ "version": "1.1.343",
4
4
  "type": "module",
5
5
  "description": "Voice-to-text API using Whisper for Telegram and LINE integration",
6
6
  "main": "./dist/index.js",
@@ -4,7 +4,7 @@
4
4
  * Handles voice messages from LINE Messaging API.
5
5
  */
6
6
 
7
- import type { VoiceMessage, TranscriptionResult } from './types.js';
7
+ import type { TranscriptionResult } from './types.js';
8
8
  import { VoiceTranscriber } from './transcriber.js';
9
9
 
10
10
  /**
@@ -38,7 +38,7 @@ export interface LineWebhookBody {
38
38
  /**
39
39
  * LINE Messaging API response
40
40
  */
41
- interface LineMessageContent {
41
+ interface _LineMessageContent {
42
42
  displayName?: string;
43
43
  }
44
44
 
@@ -70,6 +70,7 @@ export class LineVoiceHandler {
70
70
  private channelSecret?: string;
71
71
  private transcriber: VoiceTranscriber;
72
72
  private apiBase: string;
73
+ private dataApiBase: string;
73
74
  private onTranscribed?: (userId: string, text: string, result: TranscriptionResult) => Promise<void>;
74
75
  private onError?: (userId: string, error: Error) => void;
75
76
 
@@ -78,6 +79,7 @@ export class LineVoiceHandler {
78
79
  this.channelSecret = options.channelSecret;
79
80
  this.transcriber = options.transcriber;
80
81
  this.apiBase = options.apiBase || 'https://api.line.me';
82
+ this.dataApiBase = 'https://api-data.line.me'; // Content API is different
81
83
  this.onTranscribed = options.onTranscribed;
82
84
  this.onError = options.onError;
83
85
  }
@@ -85,7 +87,7 @@ export class LineVoiceHandler {
85
87
  /**
86
88
  * Verify LINE webhook signature
87
89
  */
88
- verifySignature(body: string, signature: string): boolean {
90
+ verifySignature(_body: string, _signature: string): boolean {
89
91
  if (!this.channelSecret) return true; // Skip verification if no secret
90
92
 
91
93
  // Note: In production, implement proper HMAC verification
@@ -116,9 +118,7 @@ export class LineVoiceHandler {
116
118
  }
117
119
 
118
120
  // Transcribe
119
- const result = await this.transcriber.transcribe({
120
- audioBuffer: audioContent,
121
- });
121
+ const result = await this.transcriber.transcribe(audioContent);
122
122
 
123
123
  if (result.error) {
124
124
  this.onError?.(userId, new Error(result.error));
@@ -145,8 +145,9 @@ export class LineVoiceHandler {
145
145
  */
146
146
  private async getAudioContent(messageId: string): Promise<Uint8Array | null> {
147
147
  try {
148
+ // Use data API for content retrieval
148
149
  const response = await fetch(
149
- `${this.apiBase}/v2/bot/message/${messageId}/content`,
150
+ `${this.dataApiBase}/v2/bot/message/${messageId}/content`,
150
151
  {
151
152
  headers: {
152
153
  'Authorization': `Bearer ${this.channelAccessToken}`,
@@ -155,12 +156,14 @@ export class LineVoiceHandler {
155
156
  );
156
157
 
157
158
  if (!response.ok) {
159
+ console.error(`LINE API error: ${response.status} ${response.statusText}`);
158
160
  return null;
159
161
  }
160
162
 
161
163
  const arrayBuffer = await response.arrayBuffer();
162
164
  return new Uint8Array(arrayBuffer);
163
- } catch {
165
+ } catch (error) {
166
+ console.error(`Failed to get audio content: ${error}`);
164
167
  return null;
165
168
  }
166
169
  }
@@ -99,8 +99,16 @@ export class TelegramVoiceHandler {
99
99
  // Construct download URL
100
100
  const fileUrl = `${this.apiBase}/file/bot${this.botToken}/${filePath}`;
101
101
 
102
+ // Download audio file
103
+ const response = await fetch(fileUrl);
104
+ if (!response.ok) {
105
+ return { success: false, error: `Failed to download audio: ${response.status}` };
106
+ }
107
+ const arrayBuffer = await response.arrayBuffer();
108
+ const audioBuffer = new Uint8Array(arrayBuffer);
109
+
102
110
  // Transcribe
103
- const result = await this.transcriber.transcribe({ audioUrl: fileUrl });
111
+ const result = await this.transcriber.transcribe(audioBuffer);
104
112
 
105
113
  if (result.error) {
106
114
  this.onError?.(chatId, new Error(result.error));