@qduc/term2 0.1.7 → 0.1.8
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/dist/app.model-command-feedback.test.d.ts +2 -0
- package/dist/app.model-command-feedback.test.d.ts.map +1 -0
- package/dist/app.model-command-feedback.test.js +19 -0
- package/dist/app.model-command-feedback.test.js.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -1
- package/dist/components/BottomArea.d.ts +1 -8
- package/dist/components/BottomArea.d.ts.map +1 -1
- package/dist/components/BottomArea.js.map +1 -1
- package/dist/components/InputBox.d.ts +6 -0
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +25 -3
- package/dist/components/InputBox.js.map +1 -1
- package/dist/components/InputBox.test.js +10 -1
- package/dist/components/InputBox.test.js.map +1 -1
- package/dist/components/MentorMode.test.d.ts +2 -0
- package/dist/components/MentorMode.test.d.ts.map +1 -0
- package/dist/components/MentorMode.test.js.map +1 -0
- package/dist/components/StatusBar.test.d.ts +2 -0
- package/dist/components/StatusBar.test.d.ts.map +1 -0
- package/dist/components/StatusBar.test.js +19 -0
- package/dist/components/StatusBar.test.js.map +1 -0
- package/dist/components/TextInput.d.ts.map +1 -1
- package/dist/components/TextInput.js +1 -2
- package/dist/components/TextInput.js.map +1 -1
- package/dist/components/TextInput.test.js.map +1 -1
- package/dist/contracts/conversation.d.ts +27 -0
- package/dist/contracts/conversation.d.ts.map +1 -0
- package/dist/contracts/conversation.js +2 -0
- package/dist/contracts/conversation.js.map +1 -0
- package/dist/debug-schema.d.ts +2 -0
- package/dist/debug-schema.d.ts.map +1 -0
- package/dist/debug-schema.js +22 -0
- package/dist/debug-schema.js.map +1 -0
- package/dist/hooks/use-conversation.d.ts +3 -14
- package/dist/hooks/use-conversation.d.ts.map +1 -1
- package/dist/hooks/use-conversation.js +15 -87
- package/dist/hooks/use-conversation.js.map +1 -1
- package/dist/hooks/use-model-selection.test.d.ts +2 -0
- package/dist/hooks/use-model-selection.test.d.ts.map +1 -0
- package/dist/hooks/use-model-selection.test.js +28 -0
- package/dist/hooks/use-model-selection.test.js.map +1 -0
- package/dist/hooks/use-path-completion.test.d.ts +2 -0
- package/dist/hooks/use-path-completion.test.d.ts.map +1 -0
- package/dist/hooks/use-path-completion.test.js +29 -0
- package/dist/hooks/use-path-completion.test.js.map +1 -0
- package/dist/lib/mentor-client.d.ts +41 -0
- package/dist/lib/mentor-client.d.ts.map +1 -0
- package/dist/lib/mentor-client.js +146 -0
- package/dist/lib/mentor-client.js.map +1 -0
- package/dist/lib/mentor-client.test.d.ts +2 -0
- package/dist/lib/mentor-client.test.d.ts.map +1 -0
- package/dist/lib/mentor-client.test.js +440 -0
- package/dist/lib/mentor-client.test.js.map +1 -0
- package/dist/lib/retry-strategy.d.ts +43 -0
- package/dist/lib/retry-strategy.d.ts.map +1 -0
- package/dist/lib/retry-strategy.js +93 -0
- package/dist/lib/retry-strategy.js.map +1 -0
- package/dist/lib/retry-strategy.test.d.ts +2 -0
- package/dist/lib/retry-strategy.test.d.ts.map +1 -0
- package/dist/lib/retry-strategy.test.js +200 -0
- package/dist/lib/retry-strategy.test.js.map +1 -0
- package/dist/lib/tool-invoke.d.ts +13 -0
- package/dist/lib/tool-invoke.d.ts.map +1 -1
- package/dist/lib/tool-invoke.js +61 -3
- package/dist/lib/tool-invoke.js.map +1 -1
- package/dist/lib/tool-invoke.test.js +139 -1
- package/dist/lib/tool-invoke.test.js.map +1 -1
- package/dist/prompts/default.md.bak +77 -0
- package/dist/prompts/simple-mentor.md +0 -8
- package/dist/prompts/simple.md +4 -0
- package/dist/providers/github-copilot/model-direct.d.ts +34 -0
- package/dist/providers/github-copilot/model-direct.d.ts.map +1 -0
- package/dist/providers/github-copilot/model-direct.js +443 -0
- package/dist/providers/github-copilot/model-direct.js.map +1 -0
- package/dist/providers/github-copilot/model.d.ts.map +1 -1
- package/dist/providers/github-copilot/model.js +108 -25
- package/dist/providers/github-copilot/model.js.map +1 -1
- package/dist/providers/github-copilot/provider.d.ts +5 -0
- package/dist/providers/github-copilot/provider.d.ts.map +1 -1
- package/dist/providers/github-copilot/provider.js +7 -2
- package/dist/providers/github-copilot/provider.js.map +1 -1
- package/dist/providers/openrouter/merge-messages.test.d.ts +2 -0
- package/dist/providers/openrouter/merge-messages.test.d.ts.map +1 -0
- package/dist/providers/openrouter/merge-messages.test.js +83 -0
- package/dist/providers/openrouter/merge-messages.test.js.map +1 -0
- package/dist/providers/openrouter.history.test.d.ts +2 -0
- package/dist/providers/openrouter.history.test.d.ts.map +1 -0
- package/dist/providers/openrouter.history.test.js +533 -0
- package/dist/providers/openrouter.history.test.js.map +1 -0
- package/dist/reproduce_issue.test.d.ts +2 -0
- package/dist/reproduce_issue.test.d.ts.map +1 -0
- package/dist/reproduce_issue.test.js +31 -0
- package/dist/reproduce_issue.test.js.map +1 -0
- package/dist/services/approval-presentation-policy.d.ts +17 -0
- package/dist/services/approval-presentation-policy.d.ts.map +1 -0
- package/dist/services/approval-presentation-policy.js +44 -0
- package/dist/services/approval-presentation-policy.js.map +1 -0
- package/dist/services/approval-presentation-policy.test.d.ts +2 -0
- package/dist/services/approval-presentation-policy.test.d.ts.map +1 -0
- package/dist/services/approval-presentation-policy.test.js +74 -0
- package/dist/services/approval-presentation-policy.test.js.map +1 -0
- package/dist/services/approval-state.d.ts +4 -4
- package/dist/services/approval-state.d.ts.map +1 -1
- package/dist/services/conversation-events.d.ts +12 -9
- package/dist/services/conversation-events.d.ts.map +1 -1
- package/dist/services/conversation-result-builder.d.ts +41 -0
- package/dist/services/conversation-result-builder.d.ts.map +1 -0
- package/dist/services/conversation-result-builder.js +110 -0
- package/dist/services/conversation-result-builder.js.map +1 -0
- package/dist/services/conversation-result-builder.test.d.ts +2 -0
- package/dist/services/conversation-result-builder.test.d.ts.map +1 -0
- package/dist/services/conversation-result-builder.test.js +76 -0
- package/dist/services/conversation-result-builder.test.js.map +1 -0
- package/dist/services/conversation-service.d.ts +7 -5
- package/dist/services/conversation-service.d.ts.map +1 -1
- package/dist/services/conversation-service.js +1 -1
- package/dist/services/conversation-service.js.map +1 -1
- package/dist/services/conversation-service.test.js +183 -149
- package/dist/services/conversation-session.d.ts +4 -24
- package/dist/services/conversation-session.d.ts.map +1 -1
- package/dist/services/conversation-session.js +172 -229
- package/dist/services/conversation-session.js.map +1 -1
- package/dist/services/conversation-session.usage.test.d.ts +2 -0
- package/dist/services/conversation-session.usage.test.d.ts.map +1 -0
- package/dist/services/conversation-session.usage.test.js +59 -0
- package/dist/services/conversation-session.usage.test.js.map +1 -0
- package/dist/services/conversation-store.d.ts +6 -0
- package/dist/services/conversation-store.d.ts.map +1 -1
- package/dist/services/conversation-store.js +13 -0
- package/dist/services/conversation-store.js.map +1 -1
- package/dist/services/stream-event-processor.d.ts +32 -0
- package/dist/services/stream-event-processor.d.ts.map +1 -0
- package/dist/services/stream-event-processor.js +344 -0
- package/dist/services/stream-event-processor.js.map +1 -0
- package/dist/services/stream-event-processor.test.d.ts +2 -0
- package/dist/services/stream-event-processor.test.d.ts.map +1 -0
- package/dist/services/stream-event-processor.test.js +117 -0
- package/dist/services/stream-event-processor.test.js.map +1 -0
- package/dist/test-search-tool.d.ts +2 -0
- package/dist/test-search-tool.d.ts.map +1 -0
- package/dist/test-search-tool.js +36 -0
- package/dist/test-search-tool.js.map +1 -0
- package/dist/tools/read-file.test.js +15 -0
- package/dist/tools/read-file.test.js.map +1 -1
- package/dist/tools/search-replace.d.ts.map +1 -1
- package/dist/tools/search-replace.js +157 -1
- package/dist/tools/search-replace.js.map +1 -1
- package/dist/tools/search-replace.test.js +177 -0
- package/dist/tools/search-replace.test.js.map +1 -1
- package/dist/tools/tool-capabilities.d.ts +6 -0
- package/dist/tools/tool-capabilities.d.ts.map +1 -0
- package/dist/tools/tool-capabilities.js +17 -0
- package/dist/tools/tool-capabilities.js.map +1 -0
- package/dist/tools/types.d.ts +4 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +4 -1
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/utils.test.d.ts +2 -0
- package/dist/tools/utils.test.d.ts.map +1 -0
- package/dist/tools/utils.test.js +26 -0
- package/dist/tools/utils.test.js.map +1 -0
- package/dist/types/messages.d.ts +29 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/messages.js +2 -0
- package/dist/types/messages.js.map +1 -0
- package/dist/utils/command-safety.d.ts.map +1 -1
- package/dist/utils/command-safety.js +364 -10
- package/dist/utils/command-safety.js.map +1 -1
- package/dist/utils/conversation-event-handler.d.ts +16 -10
- package/dist/utils/conversation-event-handler.d.ts.map +1 -1
- package/dist/utils/conversation-event-handler.js +4 -0
- package/dist/utils/conversation-event-handler.js.map +1 -1
- package/dist/utils/extract-command-messages.repro.test.d.ts +2 -0
- package/dist/utils/extract-command-messages.repro.test.d.ts.map +1 -0
- package/dist/utils/extract-command-messages.repro.test.js +31 -0
- package/dist/utils/extract-command-messages.repro.test.js.map +1 -0
- package/dist/utils/extract-command-messages.test.js +51 -58
- package/dist/utils/message-utils.d.ts +17 -0
- package/dist/utils/message-utils.d.ts.map +1 -0
- package/dist/utils/message-utils.js +52 -0
- package/dist/utils/message-utils.js.map +1 -0
- package/dist/utils/message-utils.test.d.ts +2 -0
- package/dist/utils/message-utils.test.d.ts.map +1 -0
- package/dist/utils/message-utils.test.js +48 -0
- package/dist/utils/message-utils.test.js.map +1 -0
- package/dist/utils/streaming-session-factory.d.ts +9 -9
- package/dist/utils/streaming-session-factory.d.ts.map +1 -1
- package/dist/utils/streaming-session-factory.js +7 -2
- package/dist/utils/streaming-session-factory.js.map +1 -1
- package/dist/utils/synchronized-output.d.ts +35 -0
- package/dist/utils/synchronized-output.d.ts.map +1 -0
- package/dist/utils/synchronized-output.js +66 -0
- package/dist/utils/synchronized-output.js.map +1 -0
- package/dist/utils/synchronized-output.test.d.ts +2 -0
- package/dist/utils/synchronized-output.test.d.ts.map +1 -0
- package/dist/utils/synchronized-output.test.js +70 -0
- package/dist/utils/synchronized-output.test.js.map +1 -0
- package/package.json +1 -1
- package/dist/agent.lite-mode.test.d.ts +0 -2
- package/dist/agent.lite-mode.test.d.ts.map +0 -1
- package/dist/agent.lite-mode.test.js +0 -39
- package/dist/agent.lite-mode.test.js.map +0 -1
- package/dist/debug_ask_mentor.d.ts +0 -2
- package/dist/debug_ask_mentor.d.ts.map +0 -1
- package/dist/debug_ask_mentor.js +0 -73
- package/dist/debug_ask_mentor.js.map +0 -1
- package/dist/modes/companion/command-index.d.ts +0 -26
- package/dist/modes/companion/command-index.d.ts.map +0 -1
- package/dist/modes/companion/command-index.js +0 -50
- package/dist/modes/companion/command-index.js.map +0 -1
- package/dist/modes/companion/command-index.test.d.ts +0 -2
- package/dist/modes/companion/command-index.test.d.ts.map +0 -1
- package/dist/modes/companion/command-index.test.js +0 -86
- package/dist/modes/companion/command-index.test.js.map +0 -1
- package/dist/modes/companion/companion-app.d.ts +0 -12
- package/dist/modes/companion/companion-app.d.ts.map +0 -1
- package/dist/modes/companion/companion-app.js +0 -297
- package/dist/modes/companion/companion-app.js.map +0 -1
- package/dist/modes/companion/companion-session.d.ts +0 -63
- package/dist/modes/companion/companion-session.d.ts.map +0 -1
- package/dist/modes/companion/companion-session.js +0 -146
- package/dist/modes/companion/companion-session.js.map +0 -1
- package/dist/modes/companion/companion-session.test.d.ts +0 -2
- package/dist/modes/companion/companion-session.test.d.ts.map +0 -1
- package/dist/modes/companion/companion-session.test.js +0 -28
- package/dist/modes/companion/companion-session.test.js.map +0 -1
- package/dist/modes/companion/components/status-bar.d.ts +0 -13
- package/dist/modes/companion/components/status-bar.d.ts.map +0 -1
- package/dist/modes/companion/components/status-bar.js +0 -26
- package/dist/modes/companion/components/status-bar.js.map +0 -1
- package/dist/modes/companion/context-buffer.d.ts +0 -65
- package/dist/modes/companion/context-buffer.d.ts.map +0 -1
- package/dist/modes/companion/context-buffer.js +0 -156
- package/dist/modes/companion/context-buffer.js.map +0 -1
- package/dist/modes/companion/context-buffer.test.d.ts +0 -2
- package/dist/modes/companion/context-buffer.test.d.ts.map +0 -1
- package/dist/modes/companion/context-buffer.test.js +0 -154
- package/dist/modes/companion/context-buffer.test.js.map +0 -1
- package/dist/modes/companion/event-detector.d.ts +0 -46
- package/dist/modes/companion/event-detector.d.ts.map +0 -1
- package/dist/modes/companion/event-detector.js +0 -169
- package/dist/modes/companion/event-detector.js.map +0 -1
- package/dist/modes/companion/event-detector.test.d.ts +0 -2
- package/dist/modes/companion/event-detector.test.d.ts.map +0 -1
- package/dist/modes/companion/event-detector.test.js +0 -121
- package/dist/modes/companion/event-detector.test.js.map +0 -1
- package/dist/modes/companion/index.d.ts +0 -33
- package/dist/modes/companion/index.d.ts.map +0 -1
- package/dist/modes/companion/index.js +0 -21
- package/dist/modes/companion/index.js.map +0 -1
- package/dist/modes/companion/input-key-mapper.d.ts +0 -3
- package/dist/modes/companion/input-key-mapper.d.ts.map +0 -1
- package/dist/modes/companion/input-key-mapper.js +0 -31
- package/dist/modes/companion/input-key-mapper.js.map +0 -1
- package/dist/modes/companion/input-key-mapper.test.d.ts +0 -2
- package/dist/modes/companion/input-key-mapper.test.d.ts.map +0 -1
- package/dist/modes/companion/input-key-mapper.test.js +0 -26
- package/dist/modes/companion/input-key-mapper.test.js.map +0 -1
- package/dist/modes/companion/input-parser.d.ts +0 -53
- package/dist/modes/companion/input-parser.d.ts.map +0 -1
- package/dist/modes/companion/input-parser.js +0 -114
- package/dist/modes/companion/input-parser.js.map +0 -1
- package/dist/modes/companion/input-parser.test.d.ts +0 -2
- package/dist/modes/companion/input-parser.test.d.ts.map +0 -1
- package/dist/modes/companion/input-parser.test.js +0 -123
- package/dist/modes/companion/input-parser.test.js.map +0 -1
- package/dist/modes/companion/mode-manager.d.ts +0 -41
- package/dist/modes/companion/mode-manager.d.ts.map +0 -1
- package/dist/modes/companion/mode-manager.js +0 -56
- package/dist/modes/companion/mode-manager.js.map +0 -1
- package/dist/modes/companion/mode-manager.test.d.ts +0 -2
- package/dist/modes/companion/mode-manager.test.d.ts.map +0 -1
- package/dist/modes/companion/mode-manager.test.js +0 -65
- package/dist/modes/companion/mode-manager.test.js.map +0 -1
- package/dist/modes/companion/output-classifier.d.ts +0 -15
- package/dist/modes/companion/output-classifier.d.ts.map +0 -1
- package/dist/modes/companion/output-classifier.js +0 -77
- package/dist/modes/companion/output-classifier.js.map +0 -1
- package/dist/modes/companion/output-classifier.test.d.ts +0 -2
- package/dist/modes/companion/output-classifier.test.d.ts.map +0 -1
- package/dist/modes/companion/output-classifier.test.js +0 -133
- package/dist/modes/companion/output-classifier.test.js.map +0 -1
- package/dist/modes/companion/pty-wrapper.d.ts +0 -46
- package/dist/modes/companion/pty-wrapper.d.ts.map +0 -1
- package/dist/modes/companion/pty-wrapper.js +0 -143
- package/dist/modes/companion/pty-wrapper.js.map +0 -1
- package/dist/modes/companion/safety-classifier.d.ts +0 -31
- package/dist/modes/companion/safety-classifier.d.ts.map +0 -1
- package/dist/modes/companion/safety-classifier.js +0 -140
- package/dist/modes/companion/safety-classifier.js.map +0 -1
- package/dist/modes/companion/safety-classifier.test.d.ts +0 -2
- package/dist/modes/companion/safety-classifier.test.d.ts.map +0 -1
- package/dist/modes/companion/safety-classifier.test.js +0 -151
- package/dist/modes/companion/safety-classifier.test.js.map +0 -1
- package/dist/modes/companion/summarizer.d.ts +0 -24
- package/dist/modes/companion/summarizer.d.ts.map +0 -1
- package/dist/modes/companion/summarizer.js +0 -132
- package/dist/modes/companion/summarizer.js.map +0 -1
- package/dist/modes/companion/terminal-history.d.ts +0 -27
- package/dist/modes/companion/terminal-history.d.ts.map +0 -1
- package/dist/modes/companion/terminal-history.js +0 -142
- package/dist/modes/companion/terminal-history.js.map +0 -1
- package/dist/providers/github-copilot/model.test.d.ts +0 -2
- package/dist/providers/github-copilot/model.test.d.ts.map +0 -1
- package/dist/providers/github-copilot/model.test.js +0 -63
- package/dist/providers/github-copilot/model.test.js.map +0 -1
- package/dist/services/check_mock.d.ts +0 -2
- package/dist/services/check_mock.d.ts.map +0 -1
- package/dist/services/check_mock.js +0 -22
- package/dist/services/check_mock.js.map +0 -1
- package/dist/services/conversation-service.test.d.ts +0 -2
- package/dist/services/conversation-service.test.d.ts.map +0 -1
- package/dist/services/conversation-service.test.js.map +0 -1
- package/dist/utils/command-safety.devnull.test.d.ts +0 -2
- package/dist/utils/command-safety.devnull.test.d.ts.map +0 -1
- package/dist/utils/command-safety.devnull.test.js +0 -13
- package/dist/utils/command-safety.devnull.test.js.map +0 -1
- package/dist/utils/extract-command-messages.test.d.ts +0 -2
- package/dist/utils/extract-command-messages.test.d.ts.map +0 -1
- package/dist/utils/extract-command-messages.test.js.map +0 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { APIConnectionError, APIConnectionTimeoutError, InternalServerError, RateLimitError } from 'openai';
|
|
3
|
+
import { OpenRouterError } from '../providers/openrouter.js';
|
|
4
|
+
import { OpenAICompatibleError } from '../providers/openai-compatible/api.js';
|
|
5
|
+
import { isTransientError, getRetryAfterMs, computeBackoffDelay, executeWithRetry } from './retry-strategy.js';
|
|
6
|
+
// ========== isTransientError ==========
|
|
7
|
+
test('isTransientError - APIConnectionError is transient', (t) => {
|
|
8
|
+
// APIConnectionError expects (opts: { cause?: Error }) as first arg
|
|
9
|
+
const error = new APIConnectionError({ cause: new Error('connect timeout') });
|
|
10
|
+
t.true(isTransientError(error));
|
|
11
|
+
});
|
|
12
|
+
test('isTransientError - APIConnectionTimeoutError is transient', (t) => {
|
|
13
|
+
const error = new APIConnectionTimeoutError();
|
|
14
|
+
t.true(isTransientError(error));
|
|
15
|
+
});
|
|
16
|
+
test('isTransientError - InternalServerError is transient', (t) => {
|
|
17
|
+
const error = new InternalServerError(500, undefined, 'server error', undefined);
|
|
18
|
+
t.true(isTransientError(error));
|
|
19
|
+
});
|
|
20
|
+
test('isTransientError - RateLimitError is transient', (t) => {
|
|
21
|
+
const error = new RateLimitError(429, undefined, 'rate limited', undefined);
|
|
22
|
+
t.true(isTransientError(error));
|
|
23
|
+
});
|
|
24
|
+
test('isTransientError - OpenRouterError 429 is transient', (t) => {
|
|
25
|
+
t.true(isTransientError(new OpenRouterError('rate limit', 429, {})));
|
|
26
|
+
});
|
|
27
|
+
test('isTransientError - OpenRouterError 500 is transient', (t) => {
|
|
28
|
+
t.true(isTransientError(new OpenRouterError('server error', 500, {})));
|
|
29
|
+
});
|
|
30
|
+
test('isTransientError - OpenRouterError 502 is transient', (t) => {
|
|
31
|
+
t.true(isTransientError(new OpenRouterError('bad gateway', 502, {})));
|
|
32
|
+
});
|
|
33
|
+
test('isTransientError - OpenRouterError 400 is NOT transient', (t) => {
|
|
34
|
+
t.false(isTransientError(new OpenRouterError('bad request', 400, {})));
|
|
35
|
+
});
|
|
36
|
+
test('isTransientError - OpenRouterError 401 is NOT transient', (t) => {
|
|
37
|
+
t.false(isTransientError(new OpenRouterError('unauthorized', 401, {})));
|
|
38
|
+
});
|
|
39
|
+
test('isTransientError - OpenAICompatibleError 429 is transient', (t) => {
|
|
40
|
+
t.true(isTransientError(new OpenAICompatibleError('rate limit', 429, {})));
|
|
41
|
+
});
|
|
42
|
+
test('isTransientError - OpenAICompatibleError 503 is transient', (t) => {
|
|
43
|
+
t.true(isTransientError(new OpenAICompatibleError('unavailable', 503, {})));
|
|
44
|
+
});
|
|
45
|
+
test('isTransientError - OpenAICompatibleError 403 is NOT transient', (t) => {
|
|
46
|
+
t.false(isTransientError(new OpenAICompatibleError('forbidden', 403, {})));
|
|
47
|
+
});
|
|
48
|
+
test('isTransientError - generic Error is NOT transient', (t) => {
|
|
49
|
+
t.false(isTransientError(new Error('generic')));
|
|
50
|
+
});
|
|
51
|
+
test('isTransientError - non-Error value is NOT transient', (t) => {
|
|
52
|
+
t.false(isTransientError('string error'));
|
|
53
|
+
t.false(isTransientError(null));
|
|
54
|
+
t.false(isTransientError(undefined));
|
|
55
|
+
});
|
|
56
|
+
// ========== getRetryAfterMs ==========
|
|
57
|
+
test('getRetryAfterMs - extracts from RateLimitError headers', (t) => {
|
|
58
|
+
const error = new RateLimitError(429, undefined, 'rate limited', {
|
|
59
|
+
get: (key) => (key === 'retry-after' ? '10' : null),
|
|
60
|
+
values: () => ({}),
|
|
61
|
+
entries: () => ({}),
|
|
62
|
+
keys: () => ({}),
|
|
63
|
+
has: (key) => key === 'retry-after',
|
|
64
|
+
[Symbol.iterator]: function* () { },
|
|
65
|
+
'retry-after': '10',
|
|
66
|
+
});
|
|
67
|
+
t.is(getRetryAfterMs(error), 10000);
|
|
68
|
+
});
|
|
69
|
+
test('getRetryAfterMs - extracts from OpenRouterError headers', (t) => {
|
|
70
|
+
const error = new OpenRouterError('rate limit', 429, { 'retry-after': '60' });
|
|
71
|
+
t.is(getRetryAfterMs(error), 60000);
|
|
72
|
+
});
|
|
73
|
+
test('getRetryAfterMs - extracts from OpenAICompatibleError headers', (t) => {
|
|
74
|
+
const error = new OpenAICompatibleError('rate limit', 429, { 'retry-after': '5' });
|
|
75
|
+
t.is(getRetryAfterMs(error), 5000);
|
|
76
|
+
});
|
|
77
|
+
test('getRetryAfterMs - returns undefined when no header present', (t) => {
|
|
78
|
+
const error = new OpenRouterError('server error', 500, {});
|
|
79
|
+
t.is(getRetryAfterMs(error), undefined);
|
|
80
|
+
});
|
|
81
|
+
test('getRetryAfterMs - returns undefined for generic Error', (t) => {
|
|
82
|
+
t.is(getRetryAfterMs(new Error('generic')), undefined);
|
|
83
|
+
});
|
|
84
|
+
test('getRetryAfterMs - returns undefined for non-numeric header', (t) => {
|
|
85
|
+
const error = new OpenRouterError('rate limit', 429, { 'retry-after': 'not-a-number' });
|
|
86
|
+
t.is(getRetryAfterMs(error), undefined);
|
|
87
|
+
});
|
|
88
|
+
// ========== computeBackoffDelay ==========
|
|
89
|
+
test('computeBackoffDelay - attemptIndex 0 produces delay in [0, 1000]', (t) => {
|
|
90
|
+
// With random returning 0.5: baseDelay=750, exp=750, capped=750, jitter=0.5*750=375
|
|
91
|
+
const delay = computeBackoffDelay(0, () => 0.5);
|
|
92
|
+
t.is(delay, 375);
|
|
93
|
+
});
|
|
94
|
+
test('computeBackoffDelay - attemptIndex 0 with random 0', (t) => {
|
|
95
|
+
// random=0: baseDelay=500, exp=500, capped=500, jitter=0*500=0
|
|
96
|
+
const delay = computeBackoffDelay(0, () => 0);
|
|
97
|
+
t.is(delay, 0);
|
|
98
|
+
});
|
|
99
|
+
test('computeBackoffDelay - delay is always within [0, 30000]', (t) => {
|
|
100
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
101
|
+
// Worst case: random=1 (just below), base=1000, but jitter caps
|
|
102
|
+
const delay = computeBackoffDelay(attempt, () => 0.999);
|
|
103
|
+
t.true(delay >= 0, `attempt ${attempt}: delay >= 0`);
|
|
104
|
+
t.true(delay <= 30000, `attempt ${attempt}: delay <= 30000`);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
test('computeBackoffDelay - higher attemptIndex produces higher max possible delay', (t) => {
|
|
108
|
+
// Use random=1 (max) to check ceiling growth
|
|
109
|
+
const r = () => 0.999;
|
|
110
|
+
const d0 = computeBackoffDelay(0, r);
|
|
111
|
+
const d1 = computeBackoffDelay(1, r);
|
|
112
|
+
const d2 = computeBackoffDelay(2, r);
|
|
113
|
+
t.true(d1 > d0);
|
|
114
|
+
t.true(d2 > d1);
|
|
115
|
+
});
|
|
116
|
+
test('computeBackoffDelay - caps at 30000ms for large attemptIndex', (t) => {
|
|
117
|
+
// random=0.999: baseDelay≈999.5, 999.5*2^10≈1023488, capped=30000, jitter≈0.999*30000≈29970
|
|
118
|
+
const delay = computeBackoffDelay(10, () => 0.999);
|
|
119
|
+
t.true(delay <= 30000);
|
|
120
|
+
t.true(delay > 29000); // should be close to cap
|
|
121
|
+
});
|
|
122
|
+
// ========== executeWithRetry ==========
|
|
123
|
+
test('executeWithRetry - returns result on first attempt success', async (t) => {
|
|
124
|
+
const result = await executeWithRetry(() => Promise.resolve('ok'), { retries: 2, sleep: async () => { } });
|
|
125
|
+
t.is(result, 'ok');
|
|
126
|
+
});
|
|
127
|
+
test('executeWithRetry - does not retry non-transient errors', async (t) => {
|
|
128
|
+
let calls = 0;
|
|
129
|
+
const error = await t.throwsAsync(() => executeWithRetry(() => {
|
|
130
|
+
calls++;
|
|
131
|
+
return Promise.reject(new Error('non-transient'));
|
|
132
|
+
}, { retries: 2, sleep: async () => { } }));
|
|
133
|
+
t.is(calls, 1);
|
|
134
|
+
t.is(error?.message, 'non-transient');
|
|
135
|
+
});
|
|
136
|
+
test('executeWithRetry - retries transient errors up to the limit', async (t) => {
|
|
137
|
+
let calls = 0;
|
|
138
|
+
const error = await t.throwsAsync(() => executeWithRetry(() => {
|
|
139
|
+
calls++;
|
|
140
|
+
return Promise.reject(new OpenRouterError('oops', 500, {}));
|
|
141
|
+
}, { retries: 2, sleep: async () => { } }));
|
|
142
|
+
// 1 initial + 2 retries = 3 total calls
|
|
143
|
+
t.is(calls, 3);
|
|
144
|
+
t.true(error instanceof OpenRouterError);
|
|
145
|
+
});
|
|
146
|
+
test('executeWithRetry - succeeds on a later retry', async (t) => {
|
|
147
|
+
let calls = 0;
|
|
148
|
+
const result = await executeWithRetry(() => {
|
|
149
|
+
calls++;
|
|
150
|
+
if (calls < 3) {
|
|
151
|
+
return Promise.reject(new OpenRouterError('oops', 502, {}));
|
|
152
|
+
}
|
|
153
|
+
return Promise.resolve('recovered');
|
|
154
|
+
}, { retries: 3, sleep: async () => { } });
|
|
155
|
+
t.is(result, 'recovered');
|
|
156
|
+
t.is(calls, 3);
|
|
157
|
+
});
|
|
158
|
+
test('executeWithRetry - calls onRetry callback with correct metadata', async (t) => {
|
|
159
|
+
const retryInfos = [];
|
|
160
|
+
await t.throwsAsync(() => executeWithRetry(() => Promise.reject(new OpenRouterError('err', 500, {})), {
|
|
161
|
+
retries: 2,
|
|
162
|
+
onRetry: (info) => retryInfos.push(info),
|
|
163
|
+
sleep: async () => { },
|
|
164
|
+
}));
|
|
165
|
+
t.is(retryInfos.length, 2);
|
|
166
|
+
t.is(retryInfos[0].attemptIndex, 0);
|
|
167
|
+
t.is(retryInfos[1].attemptIndex, 1);
|
|
168
|
+
t.true(retryInfos[0].delay >= 0);
|
|
169
|
+
t.true(retryInfos[1].delay >= 0);
|
|
170
|
+
t.true(retryInfos[0].error instanceof OpenRouterError);
|
|
171
|
+
});
|
|
172
|
+
test('executeWithRetry - retries zero means no retries', async (t) => {
|
|
173
|
+
let calls = 0;
|
|
174
|
+
await t.throwsAsync(() => executeWithRetry(() => {
|
|
175
|
+
calls++;
|
|
176
|
+
return Promise.reject(new OpenRouterError('err', 500, {}));
|
|
177
|
+
}, { retries: 0, sleep: async () => { } }));
|
|
178
|
+
t.is(calls, 1);
|
|
179
|
+
});
|
|
180
|
+
test('executeWithRetry - uses Retry-After header delay for OpenRouterError', async (t) => {
|
|
181
|
+
const delays = [];
|
|
182
|
+
await t.throwsAsync(() => executeWithRetry(() => Promise.reject(new OpenRouterError('rate limit', 429, { 'retry-after': '1' })), {
|
|
183
|
+
retries: 1,
|
|
184
|
+
onRetry: (info) => delays.push(info.delay),
|
|
185
|
+
sleep: async () => { },
|
|
186
|
+
}));
|
|
187
|
+
t.is(delays.length, 1);
|
|
188
|
+
t.is(delays[0], 1000); // 1 second parsed from header
|
|
189
|
+
});
|
|
190
|
+
test('executeWithRetry - uses Retry-After header delay for OpenAICompatibleError', async (t) => {
|
|
191
|
+
const delays = [];
|
|
192
|
+
await t.throwsAsync(() => executeWithRetry(() => Promise.reject(new OpenAICompatibleError('rate limit', 429, { 'retry-after': '2' })), {
|
|
193
|
+
retries: 1,
|
|
194
|
+
onRetry: (info) => delays.push(info.delay),
|
|
195
|
+
sleep: async () => { },
|
|
196
|
+
}));
|
|
197
|
+
t.is(delays.length, 1);
|
|
198
|
+
t.is(delays[0], 2000);
|
|
199
|
+
});
|
|
200
|
+
//# sourceMappingURL=retry-strategy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-strategy.test.js","sourceRoot":"","sources":["../../source/lib/retry-strategy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type { Tool } from '@openai/agents';
|
|
2
|
+
/**
|
|
3
|
+
* Heuristic-based JSON repair for common model-generated errors.
|
|
4
|
+
*
|
|
5
|
+
* Fixes applied (in order):
|
|
6
|
+
* 1. Strip markdown code fences (```json ... ```)
|
|
7
|
+
* 2. Extract JSON object/array from surrounding prose
|
|
8
|
+
* 3. Escape unescaped double-quotes inside JSON string values
|
|
9
|
+
* 4. Remove trailing commas before closing braces/brackets
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: Only runs the repair heuristics when `JSON.parse` fails on the
|
|
12
|
+
* input, so already-valid JSON is never modified.
|
|
13
|
+
*/
|
|
14
|
+
export declare const repairJson: (text: string) => string;
|
|
2
15
|
export declare const normalizeToolInput: (input: unknown) => string;
|
|
3
16
|
export declare const wrapToolInvoke: <T extends Tool>(tool: T) => T;
|
|
4
17
|
//# sourceMappingURL=tool-invoke.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-invoke.d.ts","sourceRoot":"","sources":["../../source/lib/tool-invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAgB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-invoke.d.ts","sourceRoot":"","sources":["../../source/lib/tool-invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAgB,MAAM,gBAAgB,CAAC;AAQzD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MA6CzC,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,MAWnD,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,IAAI,EAAE,MAAM,CAAC,KAAG,CAcxD,CAAC"}
|
package/dist/lib/tool-invoke.js
CHANGED
|
@@ -1,13 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum payload size (in characters) for which JSON repair is attempted.
|
|
3
|
+
* Very large payloads are returned as-is to avoid regex backtracking costs.
|
|
4
|
+
*/
|
|
5
|
+
const MAX_REPAIR_LENGTH = 200_000;
|
|
6
|
+
/**
|
|
7
|
+
* Heuristic-based JSON repair for common model-generated errors.
|
|
8
|
+
*
|
|
9
|
+
* Fixes applied (in order):
|
|
10
|
+
* 1. Strip markdown code fences (```json ... ```)
|
|
11
|
+
* 2. Extract JSON object/array from surrounding prose
|
|
12
|
+
* 3. Escape unescaped double-quotes inside JSON string values
|
|
13
|
+
* 4. Remove trailing commas before closing braces/brackets
|
|
14
|
+
*
|
|
15
|
+
* IMPORTANT: Only runs the repair heuristics when `JSON.parse` fails on the
|
|
16
|
+
* input, so already-valid JSON is never modified.
|
|
17
|
+
*/
|
|
18
|
+
export const repairJson = (text) => {
|
|
19
|
+
if (!text || text.trim() === '')
|
|
20
|
+
return text;
|
|
21
|
+
// Skip repair for very large payloads to avoid regex backtracking
|
|
22
|
+
if (text.length > MAX_REPAIR_LENGTH)
|
|
23
|
+
return text;
|
|
24
|
+
// Don't repair already-valid JSON – avoids corrupting valid input
|
|
25
|
+
try {
|
|
26
|
+
JSON.parse(text);
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Fall through to repair logic
|
|
31
|
+
}
|
|
32
|
+
let repaired = text;
|
|
33
|
+
// 1. Strip markdown code fences (```json ... ```)
|
|
34
|
+
repaired = repaired.replace(/^```(?:json)?\s*\n?/gm, '').replace(/\n?```\s*$/gm, '');
|
|
35
|
+
// 2. Extract JSON object/array from surrounding prose
|
|
36
|
+
const jsonMatch = repaired.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
|
|
37
|
+
if (jsonMatch) {
|
|
38
|
+
repaired = jsonMatch[1];
|
|
39
|
+
}
|
|
40
|
+
// Check again after stripping – the cleaned text may already be valid
|
|
41
|
+
try {
|
|
42
|
+
JSON.parse(repaired);
|
|
43
|
+
return repaired;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Continue with deeper repairs
|
|
47
|
+
}
|
|
48
|
+
// 3. Fix unescaped double quotes inside values.
|
|
49
|
+
// Logic: find content between : " and "[,}] and escape only the quotes *inside* that content.
|
|
50
|
+
repaired = repaired.replace(/(:\s*")([\s\S]*?)("(?=\s*[,}\]]))/g, (_match, prefix, content, suffix) => {
|
|
51
|
+
// Escape unescaped double quotes (quotes not preceded by a backslash)
|
|
52
|
+
const escapedContent = content.replace(/(?<!\\)"/g, '\\"');
|
|
53
|
+
return prefix + escapedContent + suffix;
|
|
54
|
+
});
|
|
55
|
+
// 4. Fix trailing commas in objects/arrays
|
|
56
|
+
repaired = repaired.replace(/,(\s*[}\]])/g, '$1');
|
|
57
|
+
return repaired;
|
|
58
|
+
};
|
|
1
59
|
export const normalizeToolInput = (input) => {
|
|
2
60
|
if (typeof input === 'string') {
|
|
3
|
-
return input;
|
|
61
|
+
return repairJson(input);
|
|
4
62
|
}
|
|
5
63
|
try {
|
|
6
64
|
const serialized = JSON.stringify(input);
|
|
7
|
-
return typeof serialized === 'string' ? serialized : '';
|
|
65
|
+
return typeof serialized === 'string' ? serialized : '{}';
|
|
8
66
|
}
|
|
9
67
|
catch {
|
|
10
|
-
return '';
|
|
68
|
+
return '{}';
|
|
11
69
|
}
|
|
12
70
|
};
|
|
13
71
|
export const wrapToolInvoke = (tool) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-invoke.js","sourceRoot":"","sources":["../../source/lib/tool-invoke.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAc,EAAU,EAAE;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-invoke.js","sourceRoot":"","sources":["../../source/lib/tool-invoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,145 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
import { tool as createTool } from '@openai/agents';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { wrapToolInvoke } from './tool-invoke.js';
|
|
4
|
+
import { repairJson, normalizeToolInput, wrapToolInvoke } from './tool-invoke.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// repairJson – pass-through for valid / empty input
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
test('repairJson returns empty string as-is', (t) => {
|
|
9
|
+
t.is(repairJson(''), '');
|
|
10
|
+
});
|
|
11
|
+
test('repairJson returns whitespace-only string as-is', (t) => {
|
|
12
|
+
t.is(repairJson(' '), ' ');
|
|
13
|
+
});
|
|
14
|
+
test('repairJson returns null/undefined input as-is', (t) => {
|
|
15
|
+
// @ts-expect-error – testing runtime guard
|
|
16
|
+
t.is(repairJson(null), null);
|
|
17
|
+
// @ts-expect-error – testing runtime guard
|
|
18
|
+
t.is(repairJson(undefined), undefined);
|
|
19
|
+
});
|
|
20
|
+
test('repairJson does not modify already-valid JSON', (t) => {
|
|
21
|
+
const valid = '{"key": "value", "nested": {"a": 1}}';
|
|
22
|
+
t.is(repairJson(valid), valid);
|
|
23
|
+
});
|
|
24
|
+
test('repairJson does not modify valid JSON with escaped quotes', (t) => {
|
|
25
|
+
const valid = '{"key": "value with \\"escaped\\" quotes"}';
|
|
26
|
+
t.is(repairJson(valid), valid);
|
|
27
|
+
});
|
|
28
|
+
test('repairJson does not modify valid JSON arrays', (t) => {
|
|
29
|
+
const valid = '[1, 2, {"a": "b"}]';
|
|
30
|
+
t.is(repairJson(valid), valid);
|
|
31
|
+
});
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// repairJson – unescaped double quotes inside values
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
test('repairJson fixes unescaped double quotes in a single value', (t) => {
|
|
36
|
+
const broken = '{"search_content": "No results for "searchQuery" found"}';
|
|
37
|
+
const result = repairJson(broken);
|
|
38
|
+
t.notThrows(() => JSON.parse(result));
|
|
39
|
+
const parsed = JSON.parse(result);
|
|
40
|
+
t.is(parsed.search_content, 'No results for "searchQuery" found');
|
|
41
|
+
});
|
|
42
|
+
test('repairJson fixes unescaped quotes across multiple keys', (t) => {
|
|
43
|
+
const broken = '{"a": "he said "hi"", "b": "ok"}';
|
|
44
|
+
const result = repairJson(broken);
|
|
45
|
+
t.notThrows(() => JSON.parse(result));
|
|
46
|
+
});
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// repairJson – trailing commas
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
test('repairJson removes trailing comma in object', (t) => {
|
|
51
|
+
const broken = '{"a": 1, "b": 2,}';
|
|
52
|
+
const result = repairJson(broken);
|
|
53
|
+
t.notThrows(() => JSON.parse(result));
|
|
54
|
+
t.deepEqual(JSON.parse(result), { a: 1, b: 2 });
|
|
55
|
+
});
|
|
56
|
+
test('repairJson removes trailing comma in array', (t) => {
|
|
57
|
+
const broken = '[1, 2, 3,]';
|
|
58
|
+
const result = repairJson(broken);
|
|
59
|
+
t.notThrows(() => JSON.parse(result));
|
|
60
|
+
t.deepEqual(JSON.parse(result), [1, 2, 3]);
|
|
61
|
+
});
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// repairJson – markdown code fences
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
test('repairJson strips ```json code fences', (t) => {
|
|
66
|
+
const broken = '```json\n{"command": "ls"}\n```';
|
|
67
|
+
const result = repairJson(broken);
|
|
68
|
+
t.notThrows(() => JSON.parse(result));
|
|
69
|
+
t.deepEqual(JSON.parse(result), { command: 'ls' });
|
|
70
|
+
});
|
|
71
|
+
test('repairJson strips ``` code fences without language tag', (t) => {
|
|
72
|
+
const broken = '```\n{"command": "ls"}\n```';
|
|
73
|
+
const result = repairJson(broken);
|
|
74
|
+
t.notThrows(() => JSON.parse(result));
|
|
75
|
+
t.deepEqual(JSON.parse(result), { command: 'ls' });
|
|
76
|
+
});
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// repairJson – JSON extraction from surrounding prose
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
test('repairJson extracts JSON from surrounding text', (t) => {
|
|
81
|
+
const broken = 'Sure! Here is the tool call:\n{"command": "ls -la"}\nLet me know if you need anything else.';
|
|
82
|
+
const result = repairJson(broken);
|
|
83
|
+
t.notThrows(() => JSON.parse(result));
|
|
84
|
+
t.deepEqual(JSON.parse(result), { command: 'ls -la' });
|
|
85
|
+
});
|
|
86
|
+
test('repairJson extracts JSON array from surrounding text', (t) => {
|
|
87
|
+
const broken = 'The result is: [1, 2, 3] as expected.';
|
|
88
|
+
const result = repairJson(broken);
|
|
89
|
+
t.notThrows(() => JSON.parse(result));
|
|
90
|
+
t.deepEqual(JSON.parse(result), [1, 2, 3]);
|
|
91
|
+
});
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// repairJson – combined fixes
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
test('repairJson handles markdown fence + trailing comma', (t) => {
|
|
96
|
+
const broken = '```json\n{"a": 1, "b": 2,}\n```';
|
|
97
|
+
const result = repairJson(broken);
|
|
98
|
+
t.notThrows(() => JSON.parse(result));
|
|
99
|
+
t.deepEqual(JSON.parse(result), { a: 1, b: 2 });
|
|
100
|
+
});
|
|
101
|
+
test('repairJson handles prose + unescaped quotes', (t) => {
|
|
102
|
+
const broken = 'Here you go: {"content": "No results for "query" found"}';
|
|
103
|
+
const result = repairJson(broken);
|
|
104
|
+
t.notThrows(() => JSON.parse(result));
|
|
105
|
+
const parsed = JSON.parse(result);
|
|
106
|
+
t.is(parsed.content, 'No results for "query" found');
|
|
107
|
+
});
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// repairJson – size guard
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
test('repairJson skips repair for payloads exceeding max length', (t) => {
|
|
112
|
+
// Create a broken JSON string that's very large
|
|
113
|
+
const bigContent = 'x'.repeat(200_001);
|
|
114
|
+
const broken = `{"key": "${bigContent}"}`;
|
|
115
|
+
// Should return as-is without attempting repair
|
|
116
|
+
t.is(repairJson(broken), broken);
|
|
117
|
+
});
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// normalizeToolInput
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
test('normalizeToolInput returns repaired JSON for string input', (t) => {
|
|
122
|
+
const broken = '{"key": "bad "quote" here"}';
|
|
123
|
+
const result = normalizeToolInput(broken);
|
|
124
|
+
t.notThrows(() => JSON.parse(result));
|
|
125
|
+
});
|
|
126
|
+
test('normalizeToolInput stringifies object input', (t) => {
|
|
127
|
+
const result = normalizeToolInput({ a: 1 });
|
|
128
|
+
t.is(result, '{"a":1}');
|
|
129
|
+
});
|
|
130
|
+
test('normalizeToolInput returns {} for un-serializable input', (t) => {
|
|
131
|
+
const circular = {};
|
|
132
|
+
circular.self = circular;
|
|
133
|
+
const result = normalizeToolInput(circular);
|
|
134
|
+
t.is(result, '{}');
|
|
135
|
+
});
|
|
136
|
+
test('normalizeToolInput passes through valid JSON strings', (t) => {
|
|
137
|
+
const valid = '{"key": "value"}';
|
|
138
|
+
t.is(normalizeToolInput(valid), valid);
|
|
139
|
+
});
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// wrapToolInvoke
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
5
143
|
test('wrapToolInvoke stringifies object inputs for tool invocations', async (t) => {
|
|
6
144
|
const rawTool = createTool({
|
|
7
145
|
name: 'echo_tool',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-invoke.test.js","sourceRoot":"","sources":["../../source/lib/tool-invoke.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,KAAK,CAAC;AACvB,OAAO,EAAE,IAAI,IAAI,UAAU,EAAc,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-invoke.test.js","sourceRoot":"","sources":["../../source/lib/tool-invoke.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
## Introduction
|
|
2
|
+
|
|
3
|
+
Serve as a technically skilled reasoning partner: precise, objective, and contextually aware. Help solve problems by understanding requirements, thinking systematically when necessary, and delivering reliable results. Prioritize accuracy and usefulness over agreement or reassurance.
|
|
4
|
+
|
|
5
|
+
## Core Behavior
|
|
6
|
+
|
|
7
|
+
Communicate clearly and thoughtfully. Verify claims rather than accepting them at face value, and prioritize accuracy over persuasion. When user intent is unclear, reason carefully rather than making assumptions. When a task requires creativity, ground it in concrete reasoning. Operate within the constraints defined by the user's environment.
|
|
8
|
+
|
|
9
|
+
### Example: Interpreting Ambiguous Intent (DO vs. DON'T)
|
|
10
|
+
|
|
11
|
+
DON'T (overstates certainty, assumes intent):
|
|
12
|
+
User: "Optimize this algorithm; it's too slow."
|
|
13
|
+
Assistant: "I'll parallelize it across threads for a 10× speedup."
|
|
14
|
+
*(No code inspection; claims unsupported.)*
|
|
15
|
+
|
|
16
|
+
DO (investigate, reason, stay grounded):
|
|
17
|
+
Assistant: "Before proposing changes, I need to understand the existing implementation. Please share the current function or describe its inputs and constraints so I can identify actual bottlenecks."
|
|
18
|
+
|
|
19
|
+
## Working With Code and Tools
|
|
20
|
+
|
|
21
|
+
Be rigorous before acting. Review code completely before editing. Modify only what is directly necessary, avoiding unnecessary changes. Maintain safety boundaries around user input, execution environments, and external APIs. Use provided tools in preference to alternatives, and create files only when explicitly required.
|
|
22
|
+
|
|
23
|
+
### Example: Handling a Requested Refactor (DO vs. DON'T)
|
|
24
|
+
|
|
25
|
+
DON'T (changes code without review, adds speculative improvements):
|
|
26
|
+
User: "Fix the logging bug in this file."
|
|
27
|
+
Assistant: "I rewrote the logging module to be more modular and added retries."
|
|
28
|
+
*(Unnecessary changes; introduces new behavior.)*
|
|
29
|
+
|
|
30
|
+
DO (minimal, accurate, context-aware):
|
|
31
|
+
Assistant: "I'll inspect the file to understand the logging implementation and address only the bug you specified without altering unrelated code."
|
|
32
|
+
|
|
33
|
+
## Reasoning Style
|
|
34
|
+
|
|
35
|
+
Explain your thinking when it informs the user's decision, but avoid over-explaining routine steps. Keep reasoning internal when unnecessary, presenting only conclusions unless deeper analysis is needed. When comparing design options, articulate tradeoffs clearly and distinguish between established facts and assumptions.
|
|
36
|
+
|
|
37
|
+
### Example: Complex Tradeoff (DO vs. DON'T)
|
|
38
|
+
|
|
39
|
+
DON'T (selects approach without justification):
|
|
40
|
+
User: "Should we store this state in memory or persist it?"
|
|
41
|
+
Assistant: "In-memory storage is best."
|
|
42
|
+
*(No explanation; failure modes unaddressed.)*
|
|
43
|
+
|
|
44
|
+
DO (articulates meaningful tradeoffs):
|
|
45
|
+
Assistant: "In-memory storage provides faster access but loses state on process restart. Persistence adds overhead but ensures recovery. Your choice depends on whether crash resilience is more important than peak performance."
|
|
46
|
+
|
|
47
|
+
## Handling User Intent and Safety
|
|
48
|
+
|
|
49
|
+
Support user goals while maintaining boundaries around security, privacy, and correctness. Decline unsafe requests directly, offering secure alternatives when applicable. If a user pursues a harmful approach, redirect with transparent reasoning rather than compliance.
|
|
50
|
+
|
|
51
|
+
### Example: Misguided Technical Request (DO vs. DON'T)
|
|
52
|
+
|
|
53
|
+
DON'T:
|
|
54
|
+
User: "Bypass authentication checks for testing in production."
|
|
55
|
+
Assistant: "Here's how to comment out the auth middleware."
|
|
56
|
+
*(Creates security vulnerability.)*
|
|
57
|
+
|
|
58
|
+
DO:
|
|
59
|
+
Assistant: "Disabling authentication in production introduces serious security risks. For testing, use a mock auth layer or a development-only bypass that cannot activate in production builds. I can help implement that approach."
|
|
60
|
+
|
|
61
|
+
## Task Execution
|
|
62
|
+
|
|
63
|
+
Approach tasks with a clear plan when needed. Work systematically, maintaining single-threaded focus. Deliver functional implementations rather than theoretical descriptions, and follow established patterns in the environment. Avoid unnecessary refactoring, speculative enhancements, or unrelated changes.
|
|
64
|
+
|
|
65
|
+
### Example: Complex Implementation Flow (DO vs. DON'T)
|
|
66
|
+
|
|
67
|
+
DON'T:
|
|
68
|
+
User: "Add CSV export to this feature."
|
|
69
|
+
Assistant: "I redesigned the metrics system, added a plugin API, and included CSV, JSON, and XML exports."
|
|
70
|
+
*(Scope expansion; unrelated changes.)*
|
|
71
|
+
|
|
72
|
+
DO:
|
|
73
|
+
Assistant: "I'll add CSV export alongside existing exports, following established patterns. I'll review the serialization module, implement CSV output consistently with current exports, and validate with sample data. Unrelated logic remains unchanged."
|
|
74
|
+
|
|
75
|
+
## Communication Style
|
|
76
|
+
|
|
77
|
+
Communicate professionally and directly. Be concise without sacrificing clarity—maintain the efficiency of technical documentation with sufficient detail for understanding.
|
|
@@ -82,14 +82,6 @@ Search for files by name or glob pattern in the workspace.
|
|
|
82
82
|
- Returns up to 50 results by default (configurable with `max_results`)
|
|
83
83
|
- Prefer this over Shell commands like `ls` or `rg --files`
|
|
84
84
|
|
|
85
|
-
## create_file
|
|
86
|
-
|
|
87
|
-
Create a new file with the specified content.
|
|
88
|
-
|
|
89
|
-
- Use this for explicitly creating new files
|
|
90
|
-
- Fails if the file already exists (use `search_replace` for existing files)
|
|
91
|
-
- Automatically creates parent directories if they don't exist
|
|
92
|
-
|
|
93
85
|
## search_replace
|
|
94
86
|
|
|
95
87
|
Modify files with exact text replacement.
|
package/dist/prompts/simple.md
CHANGED
|
@@ -107,6 +107,10 @@ Modify files with exact text replacement.
|
|
|
107
107
|
- Include surrounding context (whitespace, indentation) for accuracy
|
|
108
108
|
- `replace_all: true` updates all occurrences; `false` expects single match
|
|
109
109
|
- For large replacements, include 3+ lines of context
|
|
110
|
+
- Use `<...>` on its own line in `search_content` to skip unchanged middle content (gap matching)
|
|
111
|
+
- Saves tokens: provide only the head and tail anchors, omit the middle
|
|
112
|
+
- Example: `"function foo() {\n<...>\nreturn result;\n}"` matches from head to tail
|
|
113
|
+
- `replace_content` is always the full replacement text (no `<...>` marker)
|
|
110
114
|
|
|
111
115
|
## grep
|
|
112
116
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHubCopilotDirectModel - Alternative implementation that lets Copilot SDK
|
|
3
|
+
* control the tool execution flow directly, without trying to integrate with
|
|
4
|
+
* OpenAI Agents SDK's approval pattern.
|
|
5
|
+
*
|
|
6
|
+
* This is simpler and more reliable because:
|
|
7
|
+
* 1. Copilot SDK handles its own event loop and tool execution
|
|
8
|
+
* 2. Tools execute immediately when called (no approval required)
|
|
9
|
+
* 3. We just translate events to the Agents SDK format for UI streaming
|
|
10
|
+
*/
|
|
11
|
+
import { type Model, type ModelRequest, type ModelResponse, type ResponseStreamEvent } from '@openai/agents-core';
|
|
12
|
+
import { CopilotClient, type CopilotSession } from '@github/copilot-sdk';
|
|
13
|
+
import type { ILoggingService, ISettingsService } from '../../services/service-interfaces.js';
|
|
14
|
+
export declare let sharedClient: CopilotClient | null;
|
|
15
|
+
export declare function getClient(): Promise<CopilotClient>;
|
|
16
|
+
export declare function extractCopilotTextDelta(accumulated: string, incoming: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Force stop the shared client (for cleanup/error recovery)
|
|
19
|
+
*/
|
|
20
|
+
export declare function forceStopClient(): Promise<void>;
|
|
21
|
+
export declare class GitHubCopilotDirectModel implements Model {
|
|
22
|
+
#private;
|
|
23
|
+
name: string;
|
|
24
|
+
constructor(deps: {
|
|
25
|
+
settingsService: ISettingsService;
|
|
26
|
+
loggingService: ILoggingService;
|
|
27
|
+
modelId?: string;
|
|
28
|
+
sessionMap?: Map<string, string>;
|
|
29
|
+
activeSessions?: Map<string, CopilotSession>;
|
|
30
|
+
});
|
|
31
|
+
getResponse(request: ModelRequest): Promise<ModelResponse>;
|
|
32
|
+
getStreamedResponse(request: ModelRequest): AsyncIterable<ResponseStreamEvent>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=model-direct.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-direct.d.ts","sourceRoot":"","sources":["../../../source/providers/github-copilot/model-direct.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACH,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAC3B,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EACR,eAAe,EACf,gBAAgB,EACnB,MAAM,sCAAsC,CAAC;AAc9C,eAAO,IAAI,YAAY,EAAE,aAAa,GAAG,IAAW,CAAC;AAErD,wBAAsB,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,CAMxD;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkBrF;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CASrD;AAOD,qBAAa,wBAAyB,YAAW,KAAK;;IAClD,IAAI,EAAE,MAAM,CAAC;gBAQD,IAAI,EAAE;QACd,eAAe,EAAE,gBAAgB,CAAC;QAClC,cAAc,EAAE,eAAe,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;KAChD;IA8BK,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAkCzD,mBAAmB,CACtB,OAAO,EAAE,YAAY,GACtB,aAAa,CAAC,mBAAmB,CAAC;CA0XxC"}
|