@magpie-community/opencode-cursor-auth 0.2.15 → 0.2.16
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/README.md +9 -1
- package/index.mjs +2 -1
- package/native-session.mjs +43 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,6 +100,10 @@ reach their bound (a long history asks for its blobs at once, and a slow link
|
|
|
100
100
|
drains them slowly), the Run waits for the link to drain, and fails only if it
|
|
101
101
|
doesn't for 30 seconds.
|
|
102
102
|
|
|
103
|
+
A step's calls must all arrive within 30 seconds of each other: Cursor sends
|
|
104
|
+
each one once the model has written it, so a step of many long calls can take
|
|
105
|
+
longer than that in all (#155).
|
|
106
|
+
|
|
103
107
|
Cursor's count of a step's tool calls includes calls the plugin answers itself:
|
|
104
108
|
a tool the request doesn't have is refused to the model, and Cursor's own
|
|
105
109
|
`get_mcp_tools` is answered with the request's tools. The step's calls are the
|
|
@@ -115,7 +119,11 @@ request can rebuild from its supplied history without submitting the result to
|
|
|
115
119
|
the old native exec again.
|
|
116
120
|
|
|
117
121
|
A native tool handoff reports zero usage with `magpie_native.accounting=pending`;
|
|
118
|
-
the final native answer
|
|
122
|
+
the final native answer bills the turn's totals. Its own `prompt_tokens` and
|
|
123
|
+
`completion_tokens` are its last model call's share (the larger of that
|
|
124
|
+
call's prompt estimate and the turn's mean per call), since a client reads
|
|
125
|
+
them as how full its context is; the earlier calls' share is
|
|
126
|
+
`usage.magpie_deferred` (#156). An identical completed retry
|
|
119
127
|
replays the saved response with zero usage. A native final also collects earlier
|
|
120
128
|
stateless debt as `usage.magpie_deferred`, separately from its own prompt total.
|
|
121
129
|
If a started native Run is abandoned after a pending handoff, its dashboard
|
package/index.mjs
CHANGED
|
@@ -2592,7 +2592,8 @@ async function answerOf(auth, chat, signal, session = "") {
|
|
|
2592
2592
|
const convID = conversationID(chat, session)
|
|
2593
2593
|
const prepared = nativeSessions.prepare(tok, chat, convID, tools)
|
|
2594
2594
|
let r
|
|
2595
|
-
|
|
2595
|
+
// the continuation's own prompt, which its final step reports (#156)
|
|
2596
|
+
if (prepared.owner) r = prepared.owner.resume({ ...prepared, estimate: conversation(chat, tools).estimate }, signal)
|
|
2596
2597
|
const model = String(chat.model ?? "")
|
|
2597
2598
|
if (!r) {
|
|
2598
2599
|
let raw = []
|
package/native-session.mjs
CHANGED
|
@@ -454,6 +454,10 @@ class NativeSession {
|
|
|
454
454
|
this.retainedBytes = 0
|
|
455
455
|
this.sequence = 0
|
|
456
456
|
this.segments = 0
|
|
457
|
+
// the model calls of the turn so far, and what was said before the
|
|
458
|
+
// latest one began: the last step's own share of the turn (#156)
|
|
459
|
+
this.steps = 1
|
|
460
|
+
this.stepSaid = 0
|
|
457
461
|
this.said = 0
|
|
458
462
|
this.wrote = 0
|
|
459
463
|
this.terminal = false
|
|
@@ -515,6 +519,7 @@ class NativeSession {
|
|
|
515
519
|
}
|
|
516
520
|
this.transport = transport
|
|
517
521
|
this.estimate = estimate
|
|
522
|
+
this.stepEstimate = estimate
|
|
518
523
|
this.blobs = blobs
|
|
519
524
|
this.knownHashes = new Set(blobs.keys())
|
|
520
525
|
this.blobSize = [...blobs.values()].reduce((n, b) => n + b.length, 0)
|
|
@@ -571,6 +576,8 @@ class NativeSession {
|
|
|
571
576
|
this.state = "submitting"
|
|
572
577
|
clearTimeout(this.resultTimer)
|
|
573
578
|
clearTimeout(this.batchTimer)
|
|
579
|
+
this.batchTimer = null
|
|
580
|
+
this.nextStep(prepared.estimate)
|
|
574
581
|
try {
|
|
575
582
|
for (let i = 0; i < prepared.results.length; i++) {
|
|
576
583
|
const call = batch.calls.find((c) => c.id === prepared.results[i].tool_call_id)
|
|
@@ -620,8 +627,20 @@ class NativeSession {
|
|
|
620
627
|
this.waitForBatch()
|
|
621
628
|
this.sealBatch()
|
|
622
629
|
}
|
|
630
|
+
// nextStep is Cursor's next model call in the same turn: after the
|
|
631
|
+
// caller's results, or after a step whose calls were all answered here.
|
|
632
|
+
nextStep(estimate) {
|
|
633
|
+
this.steps++
|
|
634
|
+
this.stepSaid = this.said
|
|
635
|
+
if (estimate != null) this.stepEstimate = estimate
|
|
636
|
+
}
|
|
637
|
+
// waitForBatch gives the step batchWait from its latest call, answered
|
|
638
|
+
// call or count, not from its first. Cursor sends each call once the model
|
|
639
|
+
// has written its arguments, so a step of many long calls arrives over
|
|
640
|
+
// longer than batchWait while never pausing that long (#155).
|
|
623
641
|
waitForBatch() {
|
|
624
|
-
this.batchTimer
|
|
642
|
+
clearTimeout(this.batchTimer)
|
|
643
|
+
this.batchTimer = later(() => {
|
|
625
644
|
if (this.segment.expected == null && this.segment.calls.length && !this.resultSubmitted) this.missingCount()
|
|
626
645
|
else this.fail({ status: 502, message: "Cursor did not complete its declared native tool batch" })
|
|
627
646
|
}, this.limits.batchWait)
|
|
@@ -636,6 +655,7 @@ class NativeSession {
|
|
|
636
655
|
answeredCall() {
|
|
637
656
|
if (this.terminal || this.state === "awaiting-results") return
|
|
638
657
|
this.segment.answered++
|
|
658
|
+
if (this.batchTimer) this.waitForBatch()
|
|
639
659
|
this.sealBatch()
|
|
640
660
|
}
|
|
641
661
|
listed(count) {
|
|
@@ -659,6 +679,7 @@ class NativeSession {
|
|
|
659
679
|
segment.answered = 0
|
|
660
680
|
clearTimeout(this.batchTimer)
|
|
661
681
|
this.batchTimer = null
|
|
682
|
+
this.nextStep()
|
|
662
683
|
return
|
|
663
684
|
}
|
|
664
685
|
clearTimeout(this.batchTimer)
|
|
@@ -762,6 +783,24 @@ class NativeSession {
|
|
|
762
783
|
const u = usageOf(this.usageFields ?? [])
|
|
763
784
|
if (!measuredInput) u.input = this.estimate
|
|
764
785
|
if (!measuredOutput) u.output = Math.floor((this.said + 3) / 4)
|
|
786
|
+
// A turn of several model calls: TurnEndedUpdate counts them all, but a
|
|
787
|
+
// client reads the last response's prompt as how full its context is
|
|
788
|
+
// (Codex compacted a 61K context at 1.1M, #156). The last call keeps its
|
|
789
|
+
// own share, the larger of its prompt estimate and the turn's mean per
|
|
790
|
+
// call; the rest is billed as magpie_deferred.
|
|
791
|
+
let earlier = null
|
|
792
|
+
if (this.steps > 1) {
|
|
793
|
+
const whole = u.input + u.cacheRead + u.cacheWrite
|
|
794
|
+
const share = (total, own) => total > 0 ? Math.min(1, Math.max(own, total / this.steps) / total) : 0
|
|
795
|
+
const fi = share(whole, measuredInput ? this.stepEstimate ?? 0 : whole)
|
|
796
|
+
const fo = share(u.output, Math.floor((this.said - this.stepSaid + 3) / 4))
|
|
797
|
+
const own = {
|
|
798
|
+
input: Math.round(u.input * fi), cacheRead: Math.round(u.cacheRead * fi), cacheWrite: Math.round(u.cacheWrite * fi),
|
|
799
|
+
output: Math.round(u.output * fo), reasoning: Math.round(u.reasoning * fo),
|
|
800
|
+
}
|
|
801
|
+
earlier = { input: u.input - own.input, cacheRead: u.cacheRead - own.cacheRead, cacheWrite: u.cacheWrite - own.cacheWrite, output: u.output - own.output }
|
|
802
|
+
Object.assign(u, own)
|
|
803
|
+
}
|
|
765
804
|
const prompt = u.input + u.cacheRead + u.cacheWrite
|
|
766
805
|
this.finalUsage = {
|
|
767
806
|
prompt_tokens: prompt, completion_tokens: u.output, total_tokens: prompt + u.output,
|
|
@@ -771,8 +810,9 @@ class NativeSession {
|
|
|
771
810
|
}
|
|
772
811
|
this.state = "finalizing"
|
|
773
812
|
this.closeTransport()
|
|
774
|
-
const finish = (
|
|
813
|
+
const finish = (settled) => {
|
|
775
814
|
if (this.error) return
|
|
815
|
+
const more = earlier && settled ? Object.fromEntries(Object.keys(earlier).map((k) => [k, earlier[k] + settled[k]])) : earlier ?? settled
|
|
776
816
|
const deferred = more && more.input + more.output + more.cacheRead + more.cacheWrite > 0
|
|
777
817
|
this.segment.finish({ stop: "stop", usage: {
|
|
778
818
|
...this.finalUsage,
|
|
@@ -816,6 +856,7 @@ class NativeSession {
|
|
|
816
856
|
this.said += text.length
|
|
817
857
|
if (u.num === 1) this.wrote += text.length
|
|
818
858
|
this.segment.emit(u.num === 1 ? { text } : { reasoning: text })
|
|
859
|
+
if (this.batchTimer) this.waitForBatch()
|
|
819
860
|
}
|
|
820
861
|
} else if (u.num === 14) {
|
|
821
862
|
if (!this.segment.content && !this.segment.calls.length) invalid("an empty reply (Cursor ended the turn without text or a tool call)", 502)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-cursor-auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"description": "Cursor subscriptions (Pro, Pro+, Ultra, Teams) in OpenCode and magpie, through the API cursor-agent talks to",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|