@chatcode/cco-llm-chatcode-config 0.1.0

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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/README.zh.md +133 -0
  4. package/cordis.patch.yml +4 -0
  5. package/cordis.web.patch.yml +12 -0
  6. package/docs/chatcode-login.md +88 -0
  7. package/docs/chatcode-login.zh.md +179 -0
  8. package/docs/chatcode-models.md +29 -0
  9. package/docs/chatcode-models.zh.md +29 -0
  10. package/docs/chatcode-reporting.md +96 -0
  11. package/docs/chatcode-reporting.zh.md +96 -0
  12. package/docs/decisions/2026-08-31-chatcode-model-source.md +39 -0
  13. package/docs/decisions/2026-08-31-chatcode-model-source.zh.md +39 -0
  14. package/docs/decisions/2026-09-16-actual-model-adapter-routing.md +31 -0
  15. package/docs/decisions/2026-09-16-actual-model-adapter-routing.zh.md +31 -0
  16. package/lib/client.js +469 -0
  17. package/lib/index.d.ts +263 -0
  18. package/lib/index.d.ts.map +1 -0
  19. package/lib/index.js +4873 -0
  20. package/lib/index.js.map +1 -0
  21. package/lib/startup-gate-BaCbWaKH.js +164 -0
  22. package/lib/startup-gate-BaCbWaKH.js.map +1 -0
  23. package/lib/web-startup.d.ts +9 -0
  24. package/lib/web-startup.d.ts.map +1 -0
  25. package/lib/web-startup.js +20 -0
  26. package/lib/web-startup.js.map +1 -0
  27. package/package.json +121 -0
  28. package/vendor/README.md +7 -0
  29. package/vendor/dsh-llm-pi-ai/LICENSE +21 -0
  30. package/vendor/dsh-llm-pi-ai/README.i18n.yaml +6 -0
  31. package/vendor/dsh-llm-pi-ai/README.md +238 -0
  32. package/vendor/dsh-llm-pi-ai/README.zh.md +238 -0
  33. package/vendor/dsh-llm-pi-ai/package.json +65 -0
  34. package/vendor/dsh-llm-pi-ai/src/adapter.ts +434 -0
  35. package/vendor/dsh-llm-pi-ai/src/auth.ts +241 -0
  36. package/vendor/dsh-llm-pi-ai/src/catalog.ts +908 -0
  37. package/vendor/dsh-llm-pi-ai/src/config.ts +478 -0
  38. package/vendor/dsh-llm-pi-ai/src/context.ts +349 -0
  39. package/vendor/dsh-llm-pi-ai/src/discovery.ts +284 -0
  40. package/vendor/dsh-llm-pi-ai/src/index.ts +336 -0
  41. package/vendor/dsh-llm-pi-ai/src/invariant.ts +30 -0
  42. package/vendor/dsh-llm-pi-ai/src/login.ts +161 -0
  43. package/vendor/dsh-llm-pi-ai/src/provider.ts +192 -0
  44. package/vendor/dsh-llm-pi-ai/src/replay.ts +249 -0
  45. package/vendor/dsh-llm-pi-ai/src/stream.ts +232 -0
  46. package/vendor/dsh-llm-pi-ai/tests/adapter.e2e.ts +168 -0
  47. package/vendor/dsh-llm-pi-ai/tests/adapter.spec.ts +1034 -0
  48. package/vendor/dsh-llm-pi-ai/tests/assemble.ts +32 -0
  49. package/vendor/dsh-llm-pi-ai/tests/auth-double.ts +39 -0
  50. package/vendor/dsh-llm-pi-ai/tests/auth.spec.ts +221 -0
  51. package/vendor/dsh-llm-pi-ai/tests/catalog.spec.ts +1220 -0
  52. package/vendor/dsh-llm-pi-ai/tests/config.spec.ts +111 -0
  53. package/vendor/dsh-llm-pi-ai/tests/context.spec.ts +474 -0
  54. package/vendor/dsh-llm-pi-ai/tests/convert.spec.ts +922 -0
  55. package/vendor/dsh-llm-pi-ai/tests/discovery.spec.ts +374 -0
  56. package/vendor/dsh-llm-pi-ai/tests/dynamic-config.spec.ts +241 -0
  57. package/vendor/dsh-llm-pi-ai/tests/fixtures/qr-code.png +0 -0
  58. package/vendor/dsh-llm-pi-ai/tests/loader-composition.spec.ts +244 -0
  59. package/vendor/dsh-llm-pi-ai/tests/login.spec.ts +198 -0
  60. package/vendor/dsh-llm-pi-ai/tests/mock-server.ts +82 -0
  61. package/vendor/dsh-llm-pi-ai/tests/provider-apis.e2e.ts +266 -0
  62. package/vendor/dsh-llm-pi-ai/tests/sdk-options.spec.ts +106 -0
  63. package/vendor/dsh-llm-pi-ai/tsconfig.json +4 -0
  64. package/vendor/dsh-llm-pi-ai/tsconfig.upstream.json +51 -0
@@ -0,0 +1,168 @@
1
+ import { afterEach, describe, expect, it } from 'vitest'
2
+ import { Context } from '@deepseek-ai/cordis'
3
+ import LlmRuntime, { createUserMessage, ToolCallId, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
4
+ import type { Message, ToolSchema } from '@deepseek-ai/dsh-llm'
5
+ import * as LlmPiAi from '@deepseek-ai/dsh-llm-pi-ai'
6
+ import type { PiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai'
7
+ import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek'
8
+ import { assemble, type AssembledResult } from './assemble.ts'
9
+
10
+ /**
11
+ * Real-API e2e for the pi-ai-backed adapter: V4 Flash defaults and
12
+ * off/high/max reasoning. Mirrors the native adapter's StreamChunk contract
13
+ * and exercises a replayed tool follow-up. Key-gated.
14
+ */
15
+
16
+ const FLASH = 'deepseek-v4-flash'
17
+ const contexts: Context[] = []
18
+
19
+ async function harness(_model: string, config: Partial<PiAiProviderProfile> = {}) {
20
+ const ctx = new Context()
21
+ contexts.push(ctx)
22
+ await ctx.plugin(LlmRuntime)
23
+ await ctx.plugin(LlmPiAi, {
24
+ providers: {
25
+ deepseek: {
26
+ ...process.env.DEEPSEEK_API_KEY === undefined ? {} : { apiKey: process.env.DEEPSEEK_API_KEY },
27
+ ...process.env.DEEPSEEK_BASE_URL === undefined ? {} : { baseURL: process.env.DEEPSEEK_BASE_URL },
28
+ ...config,
29
+ },
30
+ },
31
+ })
32
+ return ctx
33
+ }
34
+
35
+ afterEach(async () => {
36
+ await Promise.all(contexts.splice(0).map(ctx => ctx.fiber.dispose()))
37
+ })
38
+
39
+ function ask(text: string): Message[] {
40
+ return [createUserMessage({
41
+ content: [{ type: 'text', text }],
42
+ source: { kind: 'plugin', plugin: 'test' },
43
+ })]
44
+ }
45
+
46
+ function textOf(result: AssembledResult): string {
47
+ return result.message.content
48
+ .filter(block => block.type === 'text')
49
+ .map(block => block.text)
50
+ .join('')
51
+ }
52
+
53
+ function blockKinds(result: AssembledResult): string[] {
54
+ return result.message.content.map(block => block.type)
55
+ }
56
+
57
+ const weatherTool: ToolSchema = {
58
+ name: 'get_weather',
59
+ description: 'Get the current weather for a city.',
60
+ parameters: {
61
+ type: 'object',
62
+ properties: { city: { type: 'string', description: 'City name' } },
63
+ required: ['city'],
64
+ },
65
+ }
66
+
67
+ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('llm-pi-ai e2e (real API)', () => {
68
+ it(`${FLASH} + provider-default reasoning: plain text generation`, async () => {
69
+ const ctx = await harness(FLASH)
70
+ const result = await assemble(ctx,{
71
+ model: FLASH,
72
+ messages: ask('Reply with exactly the word: pong'),
73
+ maxTokens: 50,
74
+ })
75
+ expect(result.finish.kind).toBe('stop')
76
+ expect(textOf(result).toLowerCase()).toContain('pong')
77
+ })
78
+
79
+ it('flash + reasoning off: plain text without reasoning blocks', async () => {
80
+ const ctx = await harness(FLASH)
81
+ const result = await assemble(ctx,{
82
+ model: FLASH,
83
+ reasoningEffort: ReasoningEffortId('off'),
84
+ messages: ask('Reply with exactly the word: pong'),
85
+ maxTokens: 50,
86
+ })
87
+ expect(result.finish.kind).toBe('stop')
88
+ expect(result.message.content.some(block => block.type === 'reasoning')).toBe(false)
89
+ expect(textOf(result).toLowerCase()).toContain('pong')
90
+ })
91
+
92
+ it(`${FLASH} + reasoning high: reasoning blocks present`, async () => {
93
+ const ctx = await harness(FLASH)
94
+ const result = await assemble(ctx,{
95
+ model: FLASH,
96
+ reasoningEffort: ReasoningEffortId('high'),
97
+ messages: ask('Which is larger, 9.11 or 9.8? Answer with just the number.'),
98
+ maxTokens: 2000,
99
+ })
100
+ expect(result.finish.kind).toBe('stop')
101
+ expect(result.message.content.some(block => block.type === 'reasoning')).toBe(true)
102
+ expect(textOf(result)).toContain('9.8')
103
+ })
104
+
105
+ it('flash + reasoning max: tool-call round trip', async () => {
106
+ const ctx = await harness(FLASH)
107
+
108
+ const first = await assemble(ctx,{
109
+ model: FLASH,
110
+ reasoningEffort: ReasoningEffortId('max'),
111
+ messages: ask('What is the weather in Paris right now? Use the get_weather tool.'),
112
+ tools: [weatherTool],
113
+ maxTokens: 2000,
114
+ })
115
+ expect(
116
+ first.finish.kind,
117
+ `pi-ai Flash tool-call turn finished as ${JSON.stringify(first.finish)}`,
118
+ ).toBe('tool-calls')
119
+ const call = first.message.content.find(block => block.type === 'tool-call')
120
+ expect(call).toBeDefined()
121
+ expect(call!.name).toBe('get_weather')
122
+ expect(JSON.parse(call!.arguments)).toMatchObject({ city: expect.stringMatching(/paris/i) as string })
123
+
124
+ const second = await assemble(ctx,{
125
+ model: FLASH,
126
+ reasoningEffort: ReasoningEffortId('max'),
127
+ messages: [
128
+ ...ask('What is the weather in Paris right now? Use the get_weather tool.'),
129
+ first.message,
130
+ createUserMessage({
131
+ content: [{
132
+ type: 'tool-result',
133
+ toolCallId: ToolCallId(call!.id),
134
+ content: [{ type: 'text', text: 'Sunny, 22°C' }],
135
+ }],
136
+ source: { kind: 'plugin', plugin: 'test' },
137
+ }),
138
+ ],
139
+ tools: [weatherTool],
140
+ maxTokens: 2000,
141
+ })
142
+ expect(
143
+ second.finish.kind,
144
+ `pi-ai Flash tool-result turn finished as ${JSON.stringify(second.finish)}`,
145
+ ).toBe('stop')
146
+ expect(textOf(second).toLowerCase()).toMatch(/sunny|22/)
147
+ })
148
+
149
+ it('produces the same block structure as llm-deepseek for the same prompt', async () => {
150
+ // Loose structural equivalence between the two independent adapters:
151
+ // same block KINDS in the same order for a deterministic prompt — the
152
+ // cross-implementation check that the StreamChunk design holds.
153
+ const deepseekCtx = new Context()
154
+ contexts.push(deepseekCtx)
155
+ await deepseekCtx.plugin(LlmRuntime)
156
+ await deepseekCtx.plugin(LlmDeepSeek, { thinking: 'disabled' })
157
+
158
+ const piCtx = await harness(FLASH)
159
+
160
+ const prompt = ask('Reply with exactly the word: pong')
161
+ const [fromDeepSeek, fromPiAi] = await Promise.all([
162
+ assemble(deepseekCtx, { provider: 'deepseek-official', model: FLASH, messages: prompt, maxTokens: 50 }),
163
+ assemble(piCtx, { model: FLASH, messages: prompt, maxTokens: 50 }),
164
+ ])
165
+ expect(blockKinds(fromPiAi)).toEqual(blockKinds(fromDeepSeek))
166
+ expect(fromPiAi.finish.kind).toBe(fromDeepSeek.finish.kind)
167
+ })
168
+ })